OpenJPA Integration Changes

This commit is contained in:
Nazeer Hussain Shaik
2016-10-17 11:46:52 +05:30
parent 8d3f7af16f
commit 9d7f1c2197
238 changed files with 1544 additions and 913 deletions
+12 -10
View File
@@ -23,6 +23,7 @@ gradle clean tomcatrunwar
buildscript { buildscript {
repositories { repositories {
jcenter() jcenter()
mavenCentral()
} }
dependencies { dependencies {
@@ -30,6 +31,8 @@ buildscript {
'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0', 'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0',
'org.zeroturnaround:gradle-jrebel-plugin:1.1.2', 'org.zeroturnaround:gradle-jrebel-plugin:1.1.2',
'org.springframework.boot:spring-boot-gradle-plugin:1.1.6.RELEASE' // also change springDataJpaVersion below 'org.springframework.boot:spring-boot-gradle-plugin:1.1.6.RELEASE' // also change springDataJpaVersion below
classpath 'org.apache.openjpa:openjpa-all:2.4.1'
classpath 'at.schmutterer.oss.gradle:gradle-openjpa:0.2.0'
} }
} }
@@ -42,6 +45,7 @@ apply plugin: 'idea'
apply plugin: 'tomcat' apply plugin: 'tomcat'
apply plugin: 'project-report' apply plugin: 'project-report'
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'openjpa'
/* define the valid syntax level for source files */ /* define the valid syntax level for source files */
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
@@ -64,9 +68,16 @@ repositories {
jcenter() jcenter()
// mavenLocal() // useful for local dev using MariaDB4j SNAPSHOTs (not needed for real-world non-SNAPHOT builds) // mavenLocal() // useful for local dev using MariaDB4j SNAPSHOTs (not needed for real-world non-SNAPHOT builds)
} }
openjpa {
files = fileTree(sourceSets.main.output.classesDir).matching {
include '**/AbstractPersistableCustom.class'
include '**/domain/*.class'
}
enforcePropertyRestrictions = true
}
configurations { configurations {
hibernateDependencies
providedRuntime // needed for Spring Boot executable WAR providedRuntime // needed for Spring Boot executable WAR
providedCompile providedCompile
compile() { compile() {
@@ -136,11 +147,6 @@ task dist(type:Zip){
war { war {
war.finalizedBy(bootRepackage) war.finalizedBy(bootRepackage)
if (project.hasProperty('buildType') && project.getProperty('buildType') == 'TEST') {
from(configurations.hibernateDependencies) { // notice the parens
into "WEB-INF/lib/" // no leading slash
}
}
} }
license { license {
@@ -200,7 +206,6 @@ sourceSets {
integrationTest { integrationTest {
compileClasspath += main.output + test.output compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output runtimeClasspath += main.output + test.output
runtimeClasspath += configurations.hibernateDependencies
} }
} }
@@ -231,9 +236,6 @@ configurations {
} }
dependencies { dependencies {
driver 'org.drizzle.jdbc:drizzle-jdbc:1.3' driver 'org.drizzle.jdbc:drizzle-jdbc:1.3'
hibernateDependencies(
[group:'org.springframework.boot', name:'spring-boot-starter-data-jpa', version:'1.1.6.RELEASE'],
)
} }
test { test {
+3 -1
View File
@@ -37,11 +37,13 @@ dependencies {
[group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion], [group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion],
[group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: springBootVersion], [group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: springBootVersion],
[group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: springBootVersion], [group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: springBootVersion],
[group: 'org.eclipse.persistence', name: 'javax.persistence', version: '2.0.0'], //[group: 'org.eclipse.persistence', name: 'javax.persistence', version: '2.0.0'],
[group: 'org.springframework', name: 'spring-context-support', version: springVersion], [group: 'org.springframework', name: 'spring-context-support', version: springVersion],
[group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: springOauthVersion], [group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: springOauthVersion],
[group: 'org.apache.openjpa', name:'openjpa-all', version:'2.4.1'],
[group: 'org.apache.openjpa', name:'openjpa-maven-plugin', version:'2.4.1'],
[group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'], [group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'],
[group: 'com.sun.jersey', name: 'jersey-core', version: jerseyVersion], [group: 'com.sun.jersey', name: 'jersey-core', version: jerseyVersion],
[group: 'com.sun.jersey', name: 'jersey-servlet', version: jerseyVersion], [group: 'com.sun.jersey', name: 'jersey-servlet', version: jerseyVersion],
+3 -1
View File
@@ -37,10 +37,12 @@ dependencies {
[group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion], [group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion],
[group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: springBootVersion], [group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: springBootVersion],
[group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: springBootVersion], [group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: springBootVersion],
[group: 'org.eclipse.persistence', name: 'javax.persistence', version: '2.0.0'], //[group: 'org.eclipse.persistence', name: 'javax.persistence', version: '2.0.0'],
[group: 'org.springframework', name: 'spring-context-support', version: springVersion], [group: 'org.springframework', name: 'spring-context-support', version: springVersion],
[group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: springOauthVersion], [group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: springOauthVersion],
[group: 'org.apache.openjpa', name:'openjpa-all', version:'2.4.1'],
[group: 'org.apache.openjpa', name:'openjpa-maven-plugin', version:'2.4.1'],
[group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'], [group: 'javax.ws.rs', name: 'jsr311-api', version: '1.1.1'],
[group: 'com.sun.jersey', name: 'jersey-core', version: jerseyVersion], [group: 'com.sun.jersey', name: 'jersey-core', version: jerseyVersion],
[group: 'com.sun.jersey', name: 'jersey-servlet', version: jerseyVersion], [group: 'com.sun.jersey', name: 'jersey-servlet', version: jerseyVersion],
@@ -155,14 +155,24 @@ public class ProvisioningIntegrationTest {
Assert.assertEquals(newdefintions.size(), requestedDefinitions.size()) ; Assert.assertEquals(newdefintions.size(), requestedDefinitions.size()) ;
for(int i = 0 ; i < newdefintions.size() ; i++) { for(int i = 0 ; i < newdefintions.size() ; i++) {
Map requestedMap = (Map)requestedDefinitions.get(i) ; Map requestedMap = (Map)requestedDefinitions.get(i) ;
Map newMap = (Map)newdefintions.get(i) ; Object requestedCategoryId = requestedMap.get("categoryId") ;
checkProperty("categoryId", requestedMap, newMap) ; boolean found = false ;
checkProperty("categoryName", requestedMap, newMap) ; for(int j = 0 ; j < newdefintions.size(); j++) {
checkProperty("minAge", requestedMap, newMap) ; Map newMap = (Map)newdefintions.get(j) ;
checkProperty("maxAge", requestedMap, newMap) ; Object newCategoryId = newMap.get("categoryId") ;
checkProperty("provisioningPercentage", requestedMap, newMap) ; if(requestedCategoryId.equals(newCategoryId)) {
checkProperty("liabilityAccount", requestedMap, newMap) ; found = true ;
checkProperty("expenseAccount", requestedMap, newMap) ; checkProperty("categoryId", requestedMap, newMap) ;
checkProperty("categoryName", requestedMap, newMap) ;
checkProperty("minAge", requestedMap, newMap) ;
checkProperty("maxAge", requestedMap, newMap) ;
checkProperty("provisioningPercentage", requestedMap, newMap) ;
checkProperty("liabilityAccount", requestedMap, newMap) ;
checkProperty("expenseAccount", requestedMap, newMap) ;
break ; //internal loop
}
}
if(!found) Assert.fail("No Category found with Id:"+requestedCategoryId);
} }
} }
@@ -25,6 +25,6 @@ import org.springframework.data.repository.query.Param;
public interface GLClosureRepository extends JpaRepository<GLClosure, Long>, JpaSpecificationExecutor<GLClosure> { public interface GLClosureRepository extends JpaRepository<GLClosure, Long>, JpaSpecificationExecutor<GLClosure> {
@Query("from GLClosure closure where closure.closingDate = (select max(closure1.closingDate) from GLClosure closure1 where closure1.office.id=:officeId) and closure.office.id= :officeId") @Query("select closure from GLClosure closure where closure.closingDate = (select max(closure1.closingDate) from GLClosure closure1 where closure1.office.id=:officeId) and closure.office.id= :officeId")
GLClosure getLatestGLClosureByBranch(@Param("officeId") Long officeId); GLClosure getLatestGLClosureByBranch(@Param("officeId") Long officeId);
} }
@@ -26,11 +26,11 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "acc_gl_financial_activity_account") @Table(name = "acc_gl_financial_activity_account")
public class FinancialActivityAccount extends AbstractPersistable<Long> { public class FinancialActivityAccount extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "gl_account_id") @JoinColumn(name = "gl_account_id")
@@ -26,7 +26,7 @@ import org.springframework.data.repository.query.Param;
public interface FinancialActivityAccountRepository extends JpaRepository<FinancialActivityAccount, Long>, public interface FinancialActivityAccountRepository extends JpaRepository<FinancialActivityAccount, Long>,
JpaSpecificationExecutor<FinancialActivityAccount> { JpaSpecificationExecutor<FinancialActivityAccount> {
@Query("from FinancialActivityAccount faa where faa.financialActivityType = :financialActivityType") @Query("select faa from FinancialActivityAccount faa where faa.financialActivityType = :financialActivityType")
FinancialActivityAccount findByFinancialActivityType(@Param("financialActivityType") int financialAccountType); FinancialActivityAccount findByFinancialActivityType(@Param("financialActivityType") int financialAccountType);
} }
@@ -21,6 +21,9 @@ package org.apache.fineract.accounting.financialactivityaccount.service;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY; import org.apache.fineract.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY;
import org.apache.fineract.accounting.financialactivityaccount.api.FinancialActivityAccountsJsonInputParams; import org.apache.fineract.accounting.financialactivityaccount.api.FinancialActivityAccountsJsonInputParams;
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount; import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount;
@@ -76,7 +79,11 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
.withEntityId(financialActivityAccount.getId()) // .withEntityId(financialActivityAccount.getId()) //
.build(); .build();
} catch (DataIntegrityViolationException dataIntegrityViolationException) { } catch (DataIntegrityViolationException dataIntegrityViolationException) {
handleFinancialActivityAccountDataIntegrityIssues(command, dataIntegrityViolationException); handleFinancialActivityAccountDataIntegrityIssues(command, dataIntegrityViolationException.getMostSpecificCause(), dataIntegrityViolationException);
return CommandProcessingResult.empty();
}catch(final PersistenceException ee) {
Throwable throwable = ExceptionUtils.getRootCause(ee.getCause()) ;
handleFinancialActivityAccountDataIntegrityIssues(command, throwable, ee);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
} }
} }
@@ -122,8 +129,12 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
.with(changes) // .with(changes) //
.build(); .build();
} catch (DataIntegrityViolationException dataIntegrityViolationException) { } catch (DataIntegrityViolationException dataIntegrityViolationException) {
handleFinancialActivityAccountDataIntegrityIssues(command, dataIntegrityViolationException); handleFinancialActivityAccountDataIntegrityIssues(command, dataIntegrityViolationException.getMostSpecificCause(), dataIntegrityViolationException);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch(final PersistenceException ee) {
Throwable throwable = ExceptionUtils.getRootCause(ee.getCause()) ;
handleFinancialActivityAccountDataIntegrityIssues(command, throwable, ee);
return CommandProcessingResult.empty();
} }
} }
@@ -138,8 +149,7 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
.build(); .build();
} }
private void handleFinancialActivityAccountDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleFinancialActivityAccountDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("financial_activity_type")) { if (realCause.getMessage().contains("financial_activity_type")) {
final Integer financialActivityId = command final Integer financialActivityId = command
.integerValueSansLocaleOfParameterNamed(FinancialActivityAccountsJsonInputParams.FINANCIAL_ACTIVITY_ID.getValue()); .integerValueSansLocaleOfParameterNamed(FinancialActivityAccountsJsonInputParams.FINANCIAL_ACTIVITY_ID.getValue());
@@ -37,11 +37,11 @@ import org.apache.commons.lang.StringUtils;
import org.apache.fineract.accounting.glaccount.api.GLAccountJsonInputParams; import org.apache.fineract.accounting.glaccount.api.GLAccountJsonInputParams;
import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "acc_gl_account", uniqueConstraints = { @UniqueConstraint(columnNames = { "gl_code" }, name = "acc_gl_code") }) @Table(name = "acc_gl_account", uniqueConstraints = { @UniqueConstraint(columnNames = { "gl_code" }, name = "acc_gl_code") })
public class GLAccount extends AbstractPersistable<Long> { public class GLAccount extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id") @JoinColumn(name = "parent_id")
@@ -52,7 +52,7 @@ public class GLAccount extends AbstractPersistable<Long> {
@OneToMany(fetch = FetchType.LAZY) @OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id") @JoinColumn(name = "parent_id")
private final List<GLAccount> children = new LinkedList<>(); private List<GLAccount> children = new LinkedList<>();
@Column(name = "name", nullable = false, length = 45) @Column(name = "name", nullable = false, length = 45)
private String name; private String name;
@@ -29,24 +29,24 @@ import org.springframework.data.repository.query.Param;
public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long>, JpaSpecificationExecutor<JournalEntry>, public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long>, JpaSpecificationExecutor<JournalEntry>,
JournalEntryRepositoryCustom { JournalEntryRepositoryCustom {
@Query("from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.manualEntry is true") @Query("select journalEntry from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed=false and journalEntry.manualEntry=true")
List<JournalEntry> findUnReversedManualJournalEntriesByTransactionId(@Param("transactionId") String transactionId); List<JournalEntry> findUnReversedManualJournalEntriesByTransactionId(@Param("transactionId") String transactionId);
@Query("select DISTINCT j.transactionId from JournalEntry j where j.transactionId not in (select DISTINCT je.transactionId from JournalEntry je where je.glAccount.id = :contraId)") @Query("select DISTINCT j.transactionId from JournalEntry j where j.transactionId not in (select DISTINCT je.transactionId from JournalEntry je where je.glAccount.id = :contraId)")
List<String> findNonContraTansactionIds(@Param("contraId") Long contraId); List<String> findNonContraTansactionIds(@Param("contraId") Long contraId);
@Query("select DISTINCT j.transactionId from JournalEntry j where j.office.id = :officeId and j.glAccount.id = :contraId and j.reversed is false and j.transactionId not in (select DISTINCT je.reversalJournalEntry.transactionId from JournalEntry je where je.reversed is true)") @Query("select DISTINCT j.transactionId from JournalEntry j where j.office.id = :officeId and j.glAccount.id = :contraId and j.reversed=false and j.transactionId not in (select DISTINCT je.reversalJournalEntry.transactionId from JournalEntry je where je.reversed=true)")
List<String> findNonReversedContraTansactionIds(@Param("contraId") Long contraId, @Param("officeId") Long officeId); List<String> findNonReversedContraTansactionIds(@Param("contraId") Long contraId, @Param("officeId") Long officeId);
@Query("from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType") @Query("select journalEntry from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType")
List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType) ; List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType) ;
@Query("from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.entityType = :entityType") @Query("select journalEntry from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed=false and journalEntry.entityType = :entityType")
List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType); List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType);
@Query("from JournalEntry journalEntry where glAccount.id= :accountId and transactionId= :transactionId and transactionDate= :transactionDate" /*@Query("select journalEntry from JournalEntry journalEntry where glAccount.id= :accountId and transactionId= :transactionId and transactionDate= :transactionDate"
+ " and type= :journalEntryType and entityType=1 and entityId= :loanId and loanTransaction.id= :loanTransactionId") + " and type= :journalEntryType and entityType=1 and entityId= :loanId and loanTransaction.id= :loanTransactionId")
JournalEntry findLOANJournalEntryWith(@Param("accountId") Long accountId, @Param("transactionId") String transactionId, JournalEntry findLOANJournalEntryWith(@Param("accountId") Long accountId, @Param("transactionId") String transactionId,
@Param("transactionDate") Date transactionDate, @Param("journalEntryType") Integer journalEntryType, @Param("transactionDate") Date transactionDate, @Param("journalEntryType") Integer journalEntryType,
@Param("loanId") Long loanId, @Param("loanTransactionId") Long loanTransactionId); @Param("loanId") Long loanId, @Param("loanTransactionId") Long loanTransactionId);*/
} }
@@ -20,41 +20,40 @@ package org.apache.fineract.accounting.producttoaccountmapping.domain;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.charge.domain.Charge; import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentType; import org.apache.fineract.portfolio.paymenttype.domain.PaymentType;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "acc_product_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "product_id", "product_type", @Table(name = "acc_product_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "product_id", "product_type",
"financial_account_type", "payment_type" }, name = "financial_action") }) "financial_account_type", "payment_type" }, name = "financial_action") })
public class ProductToGLAccountMapping extends AbstractPersistable<Long> { public class ProductToGLAccountMapping extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(optional=true)
@JoinColumn(name = "gl_account_id") @JoinColumn(name = "gl_account_id")
private GLAccount glAccount; private GLAccount glAccount;
@Column(name = "product_id", nullable = false) @Column(name = "product_id", nullable = true)
private Long productId; private Long productId;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne
@JoinColumn(name = "payment_type", nullable = true) @JoinColumn(name = "payment_type", nullable = true)
private PaymentType paymentType; private PaymentType paymentType;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne
@JoinColumn(name = "charge_id", nullable = true) @JoinColumn(name = "charge_id", nullable = true)
private Charge charge; private Charge charge;
@Column(name = "product_type", nullable = false) @Column(name = "product_type", nullable = true)
private int productType; private int productType;
@Column(name = "financial_account_type", nullable = false) @Column(name = "financial_account_type", nullable = true)
private int financialAccountType; private int financialAccountType;
public static ProductToGLAccountMapping createNew(final GLAccount glAccount, final Long productId, final int productType, public static ProductToGLAccountMapping createNew(final GLAccount glAccount, final Long productId, final int productType,
@@ -34,22 +34,22 @@ public interface ProductToGLAccountMappingRepository extends JpaRepository<Produ
ProductToGLAccountMapping findByProductIdAndProductTypeAndFinancialAccountTypeAndChargeId(Long productId, int productType, ProductToGLAccountMapping findByProductIdAndProductTypeAndFinancialAccountTypeAndChargeId(Long productId, int productType,
int financialAccountType, Long chargeId); int financialAccountType, Long chargeId);
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL and mapping.charge is NULL") @Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL and mapping.charge is NULL")
ProductToGLAccountMapping findCoreProductToFinAccountMapping(@Param("productId") Long productId, @Param("productType") int productType, ProductToGLAccountMapping findCoreProductToFinAccountMapping(@Param("productId") Long productId, @Param("productType") int productType,
@Param("financialAccountType") int financialAccountType); @Param("financialAccountType") int financialAccountType);
/*** The financial Account Type for a fund source will always be an asset (1) ***/ /*** The financial Account Type for a fund source will always be an asset (1) ***/
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=1 and mapping.paymentType is not NULL") @Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=1 and mapping.paymentType is not NULL")
List<ProductToGLAccountMapping> findAllPaymentTypeToFundSourceMappings(@Param("productId") Long productId, List<ProductToGLAccountMapping> findAllPaymentTypeToFundSourceMappings(@Param("productId") Long productId,
@Param("productType") int productType); @Param("productType") int productType);
/*** The financial Account Type for income from interest will always be 4 ***/ /*** The financial Account Type for income from interest will always be 4 ***/
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=4 and mapping.charge is not NULL") @Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=4 and mapping.charge is not NULL")
List<ProductToGLAccountMapping> findAllFeeToIncomeAccountMappings(@Param("productId") Long productId, List<ProductToGLAccountMapping> findAllFeeToIncomeAccountMappings(@Param("productId") Long productId,
@Param("productType") int productType); @Param("productType") int productType);
/*** The financial Account Type for income from interest will always be 5 ***/ /*** The financial Account Type for income from interest will always be 5 ***/
@Query("from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=5 and mapping.charge is not NULL") @Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=5 and mapping.charge is not NULL")
List<ProductToGLAccountMapping> findAllPenaltyToIncomeAccountMappings(@Param("productId") Long productId, List<ProductToGLAccountMapping> findAllPenaltyToIncomeAccountMappings(@Param("productId") Long productId,
@Param("productType") int productType); @Param("productType") int productType);
@@ -27,14 +27,14 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.provisioning.domain.ProvisioningCategory; import org.apache.fineract.organisation.provisioning.domain.ProvisioningCategory;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "m_loanproduct_provisioning_entry") @Table(name = "m_loanproduct_provisioning_entry")
public class LoanProductProvisioningEntry extends AbstractPersistable<Long> { public class LoanProductProvisioningEntry extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "history_id", referencedColumnName = "id", nullable = false) @JoinColumn(name = "history_id", referencedColumnName = "id", nullable = false)
@@ -35,17 +35,17 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_provisioning_history") @Table(name = "m_provisioning_history")
public class ProvisioningEntry extends AbstractPersistable<Long> { public class ProvisioningEntry extends AbstractPersistableCustom<Long> {
@Column(name = "journal_entry_created") @Column(name = "journal_entry_created")
private Boolean isJournalEntryCreated; private Boolean isJournalEntryCreated;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "entry", orphanRemoval = true, fetch=FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "entry", orphanRemoval = true, fetch=FetchType.EAGER)
Set<LoanProductProvisioningEntry> provisioningEntries = new HashSet<>(); private Set<LoanProductProvisioningEntry> provisioningEntries = new HashSet<>();
@OneToOne @OneToOne
@JoinColumn(name = "createdby_id") @JoinColumn(name = "createdby_id")
@@ -27,9 +27,10 @@ import org.springframework.data.repository.query.Param;
public interface ProvisioningEntryRepository extends JpaRepository<ProvisioningEntry, Long>, JpaSpecificationExecutor<ProvisioningEntry> { public interface ProvisioningEntryRepository extends JpaRepository<ProvisioningEntry, Long>, JpaSpecificationExecutor<ProvisioningEntry> {
@Query("select entry from ProvisioningEntry entry where entry.createdDate = :createdDate") //OPENJPA throws error if we use entry
@Query("select entry1 from ProvisioningEntry entry1 where entry1.createdDate = :createdDate")
ProvisioningEntry findByProvisioningEntryDate(@Param("createdDate") Date createdDate); ProvisioningEntry findByProvisioningEntryDate(@Param("createdDate") Date createdDate);
@Query("select entry from ProvisioningEntry entry where entry.createdDate = (select max(entry1.createdDate) from ProvisioningEntry entry1 where entry1.isJournalEntryCreated='1')") @Query("select entry1 from ProvisioningEntry entry1 where entry1.createdDate = (select max(entry2.createdDate) from ProvisioningEntry entry2 where entry2.isJournalEntryCreated=true)")
ProvisioningEntry findExistingProvisioningEntryWithJournalEntries() ; ProvisioningEntry findExistingProvisioningEntryWithJournalEntries() ;
} }
@@ -41,11 +41,11 @@ import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
import org.apache.fineract.accounting.rule.api.AccountingRuleJsonInputParams; import org.apache.fineract.accounting.rule.api.AccountingRuleJsonInputParams;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "acc_accounting_rule", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "accounting_rule_name_unique") }) @Table(name = "acc_accounting_rule", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "accounting_rule_name_unique") })
public class AccountingRule extends AbstractPersistable<Long> { public class AccountingRule extends AbstractPersistableCustom<Long> {
@Column(name = "name", nullable = false, length = 500) @Column(name = "name", nullable = false, length = 500)
private String name; private String name;
@@ -69,7 +69,7 @@ public class AccountingRule extends AbstractPersistable<Long> {
private Boolean systemDefined; private Boolean systemDefined;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accountingRule", orphanRemoval = true, fetch=FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "accountingRule", orphanRemoval = true, fetch=FetchType.EAGER)
private final List<AccountingTagRule> accountingTagRules = new ArrayList<>(); private List<AccountingTagRule> accountingTagRules = new ArrayList<>();
@Column(name = "allow_multiple_credits", nullable = false) @Column(name = "allow_multiple_credits", nullable = false)
private boolean allowMultipleCreditEntries; private boolean allowMultipleCreditEntries;
@@ -25,6 +25,6 @@ import org.springframework.data.repository.query.Param;
public interface AccountingRuleRepository extends JpaRepository<AccountingRule, Long>, JpaSpecificationExecutor<AccountingRule> { public interface AccountingRuleRepository extends JpaRepository<AccountingRule, Long>, JpaSpecificationExecutor<AccountingRule> {
@Query("from AccountingRule accountingRule where accountingRule.office is null or accountingRule.office.id =:officeId") @Query("select accountingRule from AccountingRule accountingRule where accountingRule.office is null or accountingRule.office.id =:officeId")
AccountingRule getAccountingRuleByOfficeId(@Param("officeId") Long officeId); AccountingRule getAccountingRuleByOfficeId(@Param("officeId") Long officeId);
} }
@@ -27,11 +27,11 @@ import javax.persistence.UniqueConstraint;
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType; import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "acc_rule_tags", uniqueConstraints = { @UniqueConstraint(columnNames = { "acc_rule_id", "tag_id", "acc_type_enum" }, name = "UNIQUE_ACCOUNT_RULE_TAGS") }) @Table(name = "acc_rule_tags", uniqueConstraints = { @UniqueConstraint(columnNames = { "acc_rule_id", "tag_id", "acc_type_enum" }, name = "UNIQUE_ACCOUNT_RULE_TAGS") })
public class AccountingTagRule extends AbstractPersistable<Long> { public class AccountingTagRule extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "acc_rule_id", nullable = false) @JoinColumn(name = "acc_rule_id", nullable = false)
@@ -31,6 +31,7 @@ import org.apache.fineract.infrastructure.core.exceptionmapper.PlatformResourceN
import org.apache.fineract.infrastructure.core.exceptionmapper.UnsupportedParameterExceptionMapper; import org.apache.fineract.infrastructure.core.exceptionmapper.UnsupportedParameterExceptionMapper;
import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException; import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementDataRequiredException;
import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionException;
import com.google.gson.Gson; import com.google.gson.Gson;
@@ -120,6 +121,8 @@ public class ErrorHandler extends RuntimeException {
final String errorBody = jsonHelper.toJson(mapper.toResponse((PlatformInternalServerException) exception).getEntity()); final String errorBody = jsonHelper.toJson(mapper.toResponse((PlatformInternalServerException) exception).getEntity());
return new ErrorInfo(500, 5001, errorBody); return new ErrorInfo(500, 5001, errorBody);
}else if(exception instanceof NonTransientDataAccessException) {
return new ErrorInfo(400, 4001, "{\"Exception\": " + exception.getMessage()+"}");
} }
return new ErrorInfo(500, 9999, "{\"Exception\": " + exception.toString() + "}"); return new ErrorInfo(500, 9999, "{\"Exception\": " + exception.toString() + "}");
@@ -35,6 +35,7 @@ import org.apache.fineract.batch.exception.ErrorHandler;
import org.apache.fineract.batch.exception.ErrorInfo; import org.apache.fineract.batch.exception.ErrorInfo;
import org.apache.fineract.batch.service.ResolutionHelper.BatchRequestNode; import org.apache.fineract.batch.service.ResolutionHelper.BatchRequestNode;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.TransactionStatus;
@@ -216,7 +217,22 @@ public class BatchApiServiceImpl implements BatchApiService {
errResponseList.add(errResponse); errResponseList.add(errResponse);
return errResponseList; return errResponseList;
} }catch (final NonTransientDataAccessException ex) {
ErrorInfo e = ErrorHandler.handler(ex);
BatchResponse errResponse = new BatchResponse();
errResponse.setStatusCode(e.getStatusCode());
for (BatchResponse res : checkList) {
if (!res.getStatusCode().equals(200)) {
errResponse.setBody("Transaction is being rolled back. First erroneous request: \n" + new Gson().toJson(res));
break;
}
}
checkList.clear();
List<BatchResponse> errResponseList = new ArrayList<>();
errResponseList.add(errResponse);
return errResponseList;
}
} }
} }
@@ -32,11 +32,11 @@ import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_portfolio_command_source") @Table(name = "m_portfolio_command_source")
public class CommandSource extends AbstractPersistable<Long> { public class CommandSource extends AbstractPersistableCustom<Long> {
@Column(name = "action_name", nullable = true, length = 100) @Column(name = "action_name", nullable = true, length = 100)
private String actionName; private String actionName;
@@ -25,16 +25,16 @@ import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType;
import org.apache.fineract.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; import org.apache.fineract.infrastructure.accountnumberformat.service.AccountNumberFormatConstants;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_TABLE_NAME, uniqueConstraints = { @UniqueConstraint(columnNames = { AccountNumberFormatConstants.ACCOUNT_TYPE_ENUM_COLUMN_NAME }, name = AccountNumberFormatConstants.ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME) }) @Table(name = AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_TABLE_NAME, uniqueConstraints = { @UniqueConstraint(columnNames = { AccountNumberFormatConstants.ACCOUNT_TYPE_ENUM_COLUMN_NAME }, name = AccountNumberFormatConstants.ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME) })
public class AccountNumberFormat extends AbstractPersistable<Long> { public class AccountNumberFormat extends AbstractPersistableCustom<Long> {
@Column(name = AccountNumberFormatConstants.ACCOUNT_TYPE_ENUM_COLUMN_NAME, nullable = false) @Column(name = AccountNumberFormatConstants.ACCOUNT_TYPE_ENUM_COLUMN_NAME, nullable = false)
private Integer accountTypeEnum; private Integer accountTypeEnum;
@Column(name = AccountNumberFormatConstants.PREFIX_TYPE_ENUM_COLUMN_NAME, nullable = false) @Column(name = AccountNumberFormatConstants.PREFIX_TYPE_ENUM_COLUMN_NAME, nullable = true)
private Integer prefixEnum; private Integer prefixEnum;
protected AccountNumberFormat() { protected AccountNumberFormat() {
@@ -26,7 +26,7 @@ import org.springframework.data.repository.query.Param;
public interface AccountNumberFormatRepository extends JpaRepository<AccountNumberFormat, Long>, public interface AccountNumberFormatRepository extends JpaRepository<AccountNumberFormat, Long>,
JpaSpecificationExecutor<AccountNumberFormat> { JpaSpecificationExecutor<AccountNumberFormat> {
public static final String FIND_ACCOUNT_NUMBER_FORMAT_FOR_ENTITY = "from AccountNumberFormat anf where anf.accountTypeEnum = :accountTypeEnum"; public static final String FIND_ACCOUNT_NUMBER_FORMAT_FOR_ENTITY = "select anf from AccountNumberFormat anf where anf.accountTypeEnum = :accountTypeEnum";
@Query(FIND_ACCOUNT_NUMBER_FORMAT_FOR_ENTITY) @Query(FIND_ACCOUNT_NUMBER_FORMAT_FOR_ENTITY)
AccountNumberFormat findOneByAccountTypeEnum(@Param("accountTypeEnum") Integer accountTypeEnum); AccountNumberFormat findOneByAccountTypeEnum(@Param("accountTypeEnum") Integer accountTypeEnum);
@@ -21,11 +21,14 @@ package org.apache.fineract.infrastructure.accountnumberformat.service;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.accountnumberformat.data.AccountNumberFormatDataValidator; import org.apache.fineract.infrastructure.accountnumberformat.data.AccountNumberFormatDataValidator;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper;
import org.apache.fineract.infrastructure.accountnumberformat.domain.EntityAccountType; import org.apache.fineract.infrastructure.accountnumberformat.domain.EntityAccountType;
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -74,8 +77,12 @@ public class AccountNumberFormatWritePlatformServiceJpaRepositoryImpl implements
.withEntityId(accountNumberFormat.getId()) // .withEntityId(accountNumberFormat.getId()) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException ee) {
Throwable throwable = ExceptionUtils.getRootCause(ee.getCause()) ;
handleDataIntegrityIssues(command, throwable, ee);
return CommandProcessingResult.empty();
} }
} }
@@ -110,8 +117,12 @@ public class AccountNumberFormatWritePlatformServiceJpaRepositoryImpl implements
.with(actualChanges) // .with(actualChanges) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
} catch (final PersistenceException ee) {
Throwable throwable = ExceptionUtils.getRootCause(ee.getCause()) ;
handleDataIntegrityIssues(command, throwable, ee);
return CommandProcessingResult.empty();
} }
} }
@@ -126,13 +137,12 @@ public class AccountNumberFormatWritePlatformServiceJpaRepositoryImpl implements
.build(); .build();
} }
/* /*
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains(AccountNumberFormatConstants.ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME)) { if (realCause.getMessage().contains(AccountNumberFormatConstants.ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME)) {
final Integer accountTypeId = command.integerValueSansLocaleOfParameterNamed(AccountNumberFormatConstants.accountTypeParamName); final Integer accountTypeId = command.integerValueSansLocaleOfParameterNamed(AccountNumberFormatConstants.accountTypeParamName);
@@ -22,11 +22,11 @@ import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "c_cache") @Table(name = "c_cache")
public class PlatformCache extends AbstractPersistable<Long> { public class PlatformCache extends AbstractPersistableCustom<Long> {
@Column(name = "cache_type_enum") @Column(name = "cache_type_enum")
private Integer cacheType; private Integer cacheType;
@@ -33,17 +33,17 @@ import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException; import org.apache.fineract.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_code", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_name" }, name = "code_name") }) @Table(name = "m_code", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_name" }, name = "code_name") })
public class Code extends AbstractPersistable<Long> { public class Code extends AbstractPersistableCustom<Long> {
@Column(name = "code_name", length = 100) @Column(name = "code_name", length = 100)
private String name; private String name;
@Column(name = "is_system_defined") @Column(name = "is_system_defined")
private final boolean systemDefined; private boolean systemDefined;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true) @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true)
private Set<CodeValue> values; private Set<CodeValue> values;
@@ -32,11 +32,11 @@ import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.codes.CodeConstants.CODEVALUE_JSON_INPUT_PARAMS; import org.apache.fineract.infrastructure.codes.CodeConstants.CODEVALUE_JSON_INPUT_PARAMS;
import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.data.CodeValueData;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_code_value", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_id", "code_value" }, name = "code_value_duplicate") }) @Table(name = "m_code_value", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_id", "code_value" }, name = "code_value_duplicate") })
public class CodeValue extends AbstractPersistable<Long> { public class CodeValue extends AbstractPersistableCustom<Long> {
@Column(name = "code_value", length = 100) @Column(name = "code_value", length = 100)
private String label; private String label;
@@ -20,6 +20,9 @@ package org.apache.fineract.infrastructure.codes.service;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.codes.domain.Code; import org.apache.fineract.infrastructure.codes.domain.Code;
import org.apache.fineract.infrastructure.codes.domain.CodeRepository; import org.apache.fineract.infrastructure.codes.domain.CodeRepository;
import org.apache.fineract.infrastructure.codes.exception.CodeNotFoundException; import org.apache.fineract.infrastructure.codes.exception.CodeNotFoundException;
@@ -70,8 +73,12 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(code.getId()).build(); return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(code.getId()).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleCodeDataIntegrityIssues(command, dve); handleCodeDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException ee) {
Throwable throwable = ExceptionUtils.getRootCause(ee.getCause()) ;
handleCodeDataIntegrityIssues(command, throwable, ee);
return CommandProcessingResult.empty();
} }
} }
@@ -98,8 +105,12 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
.with(changes) // .with(changes) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleCodeDataIntegrityIssues(command, dve); handleCodeDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return null; return CommandProcessingResult.empty();
}catch (final PersistenceException ee) {
Throwable throwable = ExceptionUtils.getRootCause(ee.getCause()) ;
handleCodeDataIntegrityIssues(command, throwable, ee);
return CommandProcessingResult.empty();
} }
} }
@@ -133,8 +144,7 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleCodeDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleCodeDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("code_name")) { if (realCause.getMessage().contains("code_name")) {
final String name = command.stringValueOfParameterNamed("name"); final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException("error.msg.code.duplicate.name", "A code with name '" + name + "' already exists", throw new PlatformDataIntegrityException("error.msg.code.duplicate.name", "A code with name '" + name + "' already exists",
@@ -23,11 +23,11 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "c_external_service", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name_UNIQUE") }) @Table(name = "c_external_service", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name_UNIQUE") })
public class ExternalService extends AbstractPersistable<Long> { public class ExternalService extends AbstractPersistableCustom<Long> {
@Column(name = "name", length = 50) @Column(name = "name", length = 50)
private String name; private String name;
@@ -23,6 +23,9 @@ import java.io.Serializable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
@Embeddable @Embeddable
public class ExternalServicePropertiesPK implements Serializable { public class ExternalServicePropertiesPK implements Serializable {
@@ -49,4 +52,29 @@ public class ExternalServicePropertiesPK implements Serializable {
return externalServiceId; return externalServiceId;
} }
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
final ExternalServicePropertiesPK rhs = (ExternalServicePropertiesPK) obj;
return new EqualsBuilder() //
.append(this.externalServiceId, rhs.externalServiceId) //
.append(this.name, rhs.name) //
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37) //
.append(this.externalServiceId) //
.append(this.name) //
.toHashCode();
}
} }
@@ -52,7 +52,6 @@ public class ExternalServicesProperties {
this.value = value; this.value = value;
} }
public static ExternalServicesProperties fromJson(final ExternalService externalService, final JsonCommand command) { public static ExternalServicesProperties fromJson(final ExternalService externalService, final JsonCommand command) {
final String name = command.stringValueOfParameterNamed(EXTERNALSERVICEPROPERTIES_JSON_INPUT_PARAMS.NAME.getValue()); final String name = command.stringValueOfParameterNamed(EXTERNALSERVICEPROPERTIES_JSON_INPUT_PARAMS.NAME.getValue());
final String value = command.stringValueOfParameterNamed(EXTERNALSERVICEPROPERTIES_JSON_INPUT_PARAMS.VALUE.getValue()); final String value = command.stringValueOfParameterNamed(EXTERNALSERVICEPROPERTIES_JSON_INPUT_PARAMS.VALUE.getValue());
@@ -80,5 +79,4 @@ public class ExternalServicesProperties {
public ExternalServicesPropertiesData toData() { public ExternalServicesPropertiesData toData() {
return new ExternalServicesPropertiesData(this.externalServicePropertiesPK.getName(), this.value); return new ExternalServicesPropertiesData(this.externalServicePropertiesPK.getName(), this.value);
} }
} }
@@ -20,9 +20,12 @@ package org.apache.fineract.infrastructure.configuration.domain;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ExternalServicesPropertiesRepository extends JpaRepository<ExternalServicesProperties, ExternalServicePropertiesPK>, public interface ExternalServicesPropertiesRepository extends JpaRepository<ExternalServicesProperties, ExternalServicePropertiesPK>,
JpaSpecificationExecutor<ExternalServicesProperties> { JpaSpecificationExecutor<ExternalServicesProperties> {
ExternalServicesProperties findOneByExternalServicePropertiesPK(ExternalServicePropertiesPK externalServicesProptiesPK); @Query("SELECT ep from ExternalServicesProperties ep where ep.externalServicePropertiesPK.name=:name and ep.externalServicePropertiesPK.externalServiceId=:externalServiceId")
ExternalServicesProperties findOneByExternalServicePropertiesPK(@Param("name") String name, @Param("externalServiceId") Long externalServiceId);
} }
@@ -34,7 +34,7 @@ public class ExternalServicesPropertiesRepositoryWrapper {
public ExternalServicesProperties findOneByIdAndName(Long id, String name, String externalServiceName) { public ExternalServicesProperties findOneByIdAndName(Long id, String name, String externalServiceName) {
final ExternalServicesProperties externalServicesProperties = this.repository final ExternalServicesProperties externalServicesProperties = this.repository
.findOneByExternalServicePropertiesPK(new ExternalServicePropertiesPK(id, name)); .findOneByExternalServicePropertiesPK(name,id);
if (externalServicesProperties == null) throw new ExternalServiceConfigurationNotFoundException(externalServiceName, name); if (externalServicesProperties == null) throw new ExternalServiceConfigurationNotFoundException(externalServiceName, name);
return externalServicesProperties; return externalServicesProperties;
} }
@@ -30,14 +30,14 @@ import org.apache.fineract.infrastructure.configuration.data.GlobalConfiguration
import org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyCannotBeModfied; import org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyCannotBeModfied;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.security.exception.ForcePasswordResetException; import org.apache.fineract.infrastructure.security.exception.ForcePasswordResetException;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "c_configuration") @Table(name = "c_configuration")
public class GlobalConfigurationProperty extends AbstractPersistable<Long> { public class GlobalConfigurationProperty extends AbstractPersistableCustom<Long> {
@Column(name = "name", nullable = false) @Column(name = "name", nullable = false)
private final String name; private String name;
@Column(name = "enabled", nullable = false) @Column(name = "enabled", nullable = false)
private boolean enabled; private boolean enabled;
@@ -49,7 +49,7 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
private Date dateValue; private Date dateValue;
@Column(name = "description", nullable = true) @Column(name = "description", nullable = true)
private final String description; private String description;
@Column(name = "is_trap_door", nullable = false) @Column(name = "is_trap_door", nullable = false)
private boolean isTrapDoor; private boolean isTrapDoor;
@@ -18,7 +18,9 @@
*/ */
package org.apache.fineract.infrastructure.core.data; package org.apache.fineract.infrastructure.core.data;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
public class ApiParameterError { public class ApiParameterError {
@@ -57,6 +59,8 @@ public class ApiParameterError {
*/ */
private List<ApiErrorMessageArg> args = new ArrayList<>(); private List<ApiErrorMessageArg> args = new ArrayList<>();
private final transient SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
public static ApiParameterError generalError(final String globalisationMessageCode, final String defaultUserMessage, public static ApiParameterError generalError(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) { final Object... defaultUserMessageArgs) {
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs); return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
@@ -86,7 +90,12 @@ public class ApiParameterError {
final List<ApiErrorMessageArg> messageArgs = new ArrayList<>(); final List<ApiErrorMessageArg> messageArgs = new ArrayList<>();
if (defaultUserMessageArgs != null) { if (defaultUserMessageArgs != null) {
for (final Object object : defaultUserMessageArgs) { for (final Object object : defaultUserMessageArgs) {
messageArgs.add(ApiErrorMessageArg.from(object)); if(object instanceof Date){
final String formattedDate = dateFormatter.format(object);
messageArgs.add(ApiErrorMessageArg.from(formattedDate));
} else {
messageArgs.add(ApiErrorMessageArg.from(object));
}
} }
} }
this.args = messageArgs; this.args = messageArgs;
@@ -22,16 +22,17 @@ import java.io.Serializable;
import java.util.Date; import java.util.Date;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne; import javax.persistence.OneToOne;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.apache.fineract.useradministration.domain.AppUser;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.data.domain.Auditable; import org.springframework.data.domain.Auditable;
import org.springframework.data.jpa.domain.AbstractAuditable; import org.springframework.data.jpa.domain.AbstractAuditable;
import org.springframework.data.jpa.domain.AbstractPersistable;
/** /**
* A custom copy of {@link AbstractAuditable} to override the column names used * A custom copy of {@link AbstractAuditable} to override the column names used
@@ -46,21 +47,21 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
* the type of the auditing type's identifier * the type of the auditing type's identifier
*/ */
@MappedSuperclass @MappedSuperclass
public abstract class AbstractAuditableCustom<U, PK extends Serializable> extends AbstractPersistable<PK> implements Auditable<U, PK> { public abstract class AbstractAuditableCustom<U, PK extends Serializable> extends AbstractPersistableCustom<PK> implements Auditable<AppUser, Long> {
private static final long serialVersionUID = 141481953116476081L; private static final long serialVersionUID = 141481953116476081L;
@OneToOne @OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "createdby_id") @JoinColumn(name = "createdby_id")
private U createdBy; private AppUser createdBy;
@Column(name = "created_date") @Column(name = "created_date")
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
private Date createdDate; private Date createdDate;
@OneToOne @OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "lastmodifiedby_id") @JoinColumn(name = "lastmodifiedby_id")
private U lastModifiedBy; private AppUser lastModifiedBy;
@Column(name = "lastmodified_date") @Column(name = "lastmodified_date")
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@@ -72,7 +73,7 @@ public abstract class AbstractAuditableCustom<U, PK extends Serializable> extend
* @see org.springframework.data.domain.Auditable#getCreatedBy() * @see org.springframework.data.domain.Auditable#getCreatedBy()
*/ */
@Override @Override
public U getCreatedBy() { public AppUser getCreatedBy() {
return this.createdBy; return this.createdBy;
} }
@@ -84,7 +85,7 @@ public abstract class AbstractAuditableCustom<U, PK extends Serializable> extend
* org.springframework.data.domain.Auditable#setCreatedBy(java.lang.Object) * org.springframework.data.domain.Auditable#setCreatedBy(java.lang.Object)
*/ */
@Override @Override
public void setCreatedBy(final U createdBy) { public void setCreatedBy(final AppUser createdBy) {
this.createdBy = createdBy; this.createdBy = createdBy;
} }
@@ -119,7 +120,7 @@ public abstract class AbstractAuditableCustom<U, PK extends Serializable> extend
* @see org.springframework.data.domain.Auditable#getLastModifiedBy() * @see org.springframework.data.domain.Auditable#getLastModifiedBy()
*/ */
@Override @Override
public U getLastModifiedBy() { public AppUser getLastModifiedBy() {
return this.lastModifiedBy; return this.lastModifiedBy;
} }
@@ -132,7 +133,7 @@ public abstract class AbstractAuditableCustom<U, PK extends Serializable> extend
* .Object) * .Object)
*/ */
@Override @Override
public void setLastModifiedBy(final U lastModifiedBy) { public void setLastModifiedBy(final AppUser lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy; this.lastModifiedBy = lastModifiedBy;
} }
@@ -0,0 +1,70 @@
/**
* 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.domain;
import java.io.Serializable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import org.springframework.data.domain.Persistable;
@MappedSuperclass
public abstract class AbstractPersistableCustom<PK extends Serializable> implements Persistable<Long> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/*
* (non-Javadoc)
*
* @see org.springframework.data.domain.Persistable#getId()
*/
@Override
public Long getId() {
return id;
}
/**
* Sets the id of the entity.
*
* @param id the id to set
*/
protected void setId(final Long id) {
this.id = id;
}
/*
* (non-Javadoc)
*
* @see org.springframework.data.domain.Persistable#isNew()
*/
@Override
public boolean isNew() {
return null == this.id;
}
//We have removed toString(), hashCode() and equals() methods. By adding them end up issues with OpenJPA
}
@@ -0,0 +1,46 @@
/**
* 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.domain;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.openjpa.jdbc.sql.BooleanRepresentationFactory;
import org.apache.openjpa.jdbc.sql.MySQLDictionary;
public class MySQLDictionaryCustom extends MySQLDictionary {
public MySQLDictionaryCustom(){
super();
this.supportsSubselect = true;
this.booleanRepresentation = BooleanRepresentationFactory.BOOLEAN;
this.supportsGetGeneratedKeys = false ;
this.allowsAliasInBulkClause = true ;
this.useWildCardForCount = true ;
}
@Override
public void connectedConfiguration(Connection conn) throws SQLException {
super.connectedConfiguration(conn);
this.supportsSubselect = true;
this.supportsGetGeneratedKeys = false ;
this.allowsAliasInBulkClause = true ;
this.useWildCardForCount = true ;
}
}
@@ -106,6 +106,7 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
poolConfiguration.setRemoveAbandonedTimeout(tenantConnectionObj.getRemoveAbandonedTimeout()); poolConfiguration.setRemoveAbandonedTimeout(tenantConnectionObj.getRemoveAbandonedTimeout());
poolConfiguration.setLogAbandoned(tenantConnectionObj.isLogAbandoned()); poolConfiguration.setLogAbandoned(tenantConnectionObj.isLogAbandoned());
poolConfiguration.setAbandonWhenPercentageFull(tenantConnectionObj.getAbandonWhenPercentageFull()); poolConfiguration.setAbandonWhenPercentageFull(tenantConnectionObj.getAbandonWhenPercentageFull());
poolConfiguration.setDefaultAutoCommit(true);
/** /**
* Vishwas- Do we need to enable the below properties and add * Vishwas- Do we need to enable the below properties and add
@@ -40,13 +40,13 @@ import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
@Entity @Entity
@Table(name = "stretchy_report", uniqueConstraints = { @UniqueConstraint(columnNames = { "report_name" }, name = "unq_report_name") }) @Table(name = "stretchy_report", uniqueConstraints = { @UniqueConstraint(columnNames = { "report_name" }, name = "unq_report_name") })
public final class Report extends AbstractPersistable<Long> { public final class Report extends AbstractPersistableCustom<Long> {
@Column(name = "report_name", nullable = false, unique = true) @Column(name = "report_name", nullable = false, unique = true)
private String reportName; private String reportName;
@@ -74,7 +74,7 @@ public final class Report extends AbstractPersistable<Long> {
private String reportSql; private String reportSql;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "report", orphanRemoval = true, fetch=FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "report", orphanRemoval = true, fetch=FetchType.EAGER)
private final Set<ReportParameterUsage> reportParameterUsages = new HashSet<>(); private Set<ReportParameterUsage> reportParameterUsages = new HashSet<>();
public static Report fromJson(final JsonCommand command, final Collection<String> reportTypes) { public static Report fromJson(final JsonCommand command, final Collection<String> reportTypes) {
@@ -21,11 +21,11 @@ package org.apache.fineract.infrastructure.dataqueries.domain;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "stretchy_parameter") @Table(name = "stretchy_parameter")
public class ReportParameter extends AbstractPersistable<Long> { public class ReportParameter extends AbstractPersistableCustom<Long> {
protected ReportParameter() { protected ReportParameter() {
// //
@@ -24,13 +24,11 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "stretchy_report_parameter") @Table(name = "stretchy_report_parameter")
public final class ReportParameterUsage extends AbstractPersistable<Long> { public final class ReportParameterUsage extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "report_id", nullable = false) @JoinColumn(name = "report_id", nullable = false)
@@ -53,7 +51,7 @@ public final class ReportParameterUsage extends AbstractPersistable<Long> {
this.reportParameterName = reportParameterName; this.reportParameterName = reportParameterName;
} }
@Override /*@Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
if (obj == null) { return false; } if (obj == null) { return false; }
if (obj == this) { return true; } if (obj == this) { return true; }
@@ -75,7 +73,7 @@ public final class ReportParameterUsage extends AbstractPersistable<Long> {
.append(this.parameter.getId()) // .append(this.parameter.getId()) //
.append(this.reportParameterName) // .append(this.reportParameterName) //
.toHashCode(); .toHashCode();
} }*/
public boolean hasIdOf(final Long id) { public boolean hasIdOf(final Long id) {
return getId().equals(id); return getId().equals(id);
@@ -28,10 +28,12 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.PersistenceException;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.codes.service.CodeReadPlatformService; import org.apache.fineract.infrastructure.codes.service.CodeReadPlatformService;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -65,6 +67,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet; import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData; import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
@@ -264,7 +267,18 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// show duplicate datatable error msg // show duplicate datatable error msg
if (realCause.getMessage() if (realCause.getMessage()
.contains("Duplicate entry") || cause.getMessage() .contains("Duplicate entry") || cause.getMessage()
.contains("Duplicate entry")) { throw new PlatformDataIntegrityException("error.msg.datatable.registered", .contains("Duplicate entry")) {
throw new PlatformDataIntegrityException("error.msg.datatable.registered",
"Datatable `" + dataTableName + "` is already registered against an application table.", "dataTableName",
dataTableName); }
logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}catch (final PersistenceException dve) {
final Throwable cause = dve.getCause() ;
if (cause.getMessage()
.contains("Duplicate entry")) {
throw new PlatformDataIntegrityException("error.msg.datatable.registered",
"Datatable `" + dataTableName + "` is already registered against an application table.", "dataTableName", "Datatable `" + dataTableName + "` is already registered against an application table.", "dataTableName",
dataTableName); } dataTableName); }
logAsErrorUnexpectedDataIntegrityException(dve); logAsErrorUnexpectedDataIntegrityException(dve);
@@ -374,6 +388,19 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
logAsErrorUnexpectedDataIntegrityException(dve); logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
}catch(final PersistenceException e) {
final Throwable cause = e.getCause() ;
if (cause.getMessage()
.contains("Duplicate entry")) {
throw new PlatformDataIntegrityException(
"error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName
+ "` and application table with identifier `" + appTableId + "`.",
"dataTableName", dataTableName, appTableId); }
logAsErrorUnexpectedDataIntegrityException(e);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
} }
} }
@@ -405,6 +432,17 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
+ "` and application table with identifier `" + appTableId + "`.", + "` and application table with identifier `" + appTableId + "`.",
"dataTableName", dataTableName, appTableId); } "dataTableName", dataTableName, appTableId); }
logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}catch (final PersistenceException dve) {
final Throwable cause = dve.getCause() ;
if (cause.getMessage()
.contains("Duplicate entry")) { throw new PlatformDataIntegrityException(
"error.msg.datatable.entry.duplicate", "An entry already exists for datatable `" + dataTableName
+ "` and application table with identifier `" + appTableId + "`.",
"dataTableName", dataTableName, appTableId); }
logAsErrorUnexpectedDataIntegrityException(dve); logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue",
"Unknown data integrity issue with resource."); "Unknown data integrity issue with resource.");
@@ -574,6 +612,21 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} }
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
}catch (final PersistenceException | BadSqlGrammarException ee) {
Throwable realCause = ExceptionUtils.getRootCause(ee.getCause()) ;
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("datatable");
if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
} else if (realCause.getMessage().contains("Table") && realCause.getMessage().contains("already exists")) {
baseDataValidator.reset().parameter("datatableName").value(datatableName).failWithCode("datatable.already.exists");
} else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
} else if (realCause.getMessage().contains("Row") && realCause.getMessage().contains("large")) {
baseDataValidator.reset().parameter("row").failWithCode("size.too.large");
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withResourceIdAsString(datatableName).build(); return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withResourceIdAsString(datatableName).build();
@@ -942,7 +995,22 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} }
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }catch (final PersistenceException ee) {
Throwable realCause = ExceptionUtils.getRootCause(ee.getCause()) ;
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("datatable");
if (realCause.getMessage().toLowerCase().contains("duplicate column name")) {
baseDataValidator.reset().parameter("name").failWithCode("duplicate.column.name");
} else if (realCause.getMessage().contains("Table") && realCause.getMessage().contains("already exists")) {
baseDataValidator.reset().parameter("datatableName").value(datatableName).failWithCode("datatable.already.exists");
} else if (realCause.getMessage().contains("Column") && realCause.getMessage().contains("big")) {
baseDataValidator.reset().parameter("column").failWithCode("length.too.big");
} else if (realCause.getMessage().contains("Row") && realCause.getMessage().contains("large")) {
baseDataValidator.reset().parameter("row").failWithCode("size.too.large");
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
} }
@Transactional @Transactional
@@ -22,7 +22,10 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -100,8 +103,12 @@ public class ReportWritePlatformServiceImpl implements ReportWritePlatformServic
.withEntityId(report.getId()) // .withEntityId(report.getId()) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleReportDataIntegrityIssues(command, dve); handleReportDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleReportDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -137,8 +144,12 @@ public class ReportWritePlatformServiceImpl implements ReportWritePlatformServic
.with(changes) // .with(changes) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleReportDataIntegrityIssues(command, dve); handleReportDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleReportDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -169,10 +180,9 @@ public class ReportWritePlatformServiceImpl implements ReportWritePlatformServic
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleReportDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleReportDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause(); if (realCause.getMessage().contains("unq_report_name") || realCause.getMessage().contains("report_name_UNIQUE")) {
if (realCause.getMessage().contains("unq_report_name")) {
final String name = command.stringValueOfParameterNamed("reportName"); final String name = command.stringValueOfParameterNamed("reportName");
throw new PlatformDataIntegrityException("error.msg.report.duplicate.name", "A report with name '" + name + "' already exists", throw new PlatformDataIntegrityException("error.msg.report.duplicate.name", "A report with name '" + name + "' already exists",
"name", name); "name", name);
@@ -24,11 +24,11 @@ import javax.persistence.Table;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.documentmanagement.command.DocumentCommand; import org.apache.fineract.infrastructure.documentmanagement.command.DocumentCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_document") @Table(name = "m_document")
public class Document extends AbstractPersistable<Long> { public class Document extends AbstractPersistableCustom<Long> {
@Column(name = "parent_entity_type", length = 50) @Column(name = "parent_entity_type", length = 50)
private String parentEntityType; private String parentEntityType;
@@ -22,11 +22,11 @@ import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_image") @Table(name = "m_image")
public final class Image extends AbstractPersistable<Long> { public final class Image extends AbstractPersistableCustom<Long> {
@Column(name = "location", length = 500) @Column(name = "location", length = 500)
private String location; private String location;
@@ -30,11 +30,11 @@ import javax.persistence.Table;
import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.entityaccess.FineractEntityAccessConstants; import org.apache.fineract.infrastructure.entityaccess.FineractEntityAccessConstants;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_entity_to_entity_access") @Table(name = "m_entity_to_entity_access")
public class FineractEntityAccess extends AbstractPersistable<Long> { public class FineractEntityAccess extends AbstractPersistableCustom<Long> {
@Column(name = "entity_type", length = 50) @Column(name = "entity_type", length = 50)
private String entityType; private String entityType;
@@ -27,11 +27,11 @@ import javax.persistence.Entity;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_entity_relation") @Table(name = "m_entity_relation")
public class FineractEntityRelation extends AbstractPersistable<Long> { public class FineractEntityRelation extends AbstractPersistableCustom<Long> {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "relationId", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "relationId", orphanRemoval = true)
private Set<FineractEntityToEntityMapping> fineractEntityToEntityMapping = new HashSet<>(); private Set<FineractEntityToEntityMapping> fineractEntityToEntityMapping = new HashSet<>();
@@ -24,6 +24,6 @@ import org.springframework.data.repository.query.Param;
public interface FineractEntityRelationRepository extends JpaRepository<FineractEntityRelation, Long>{ public interface FineractEntityRelationRepository extends JpaRepository<FineractEntityRelation, Long>{
@Query("from FineractEntityRelation fea where fea.codeName= :codeName") @Query("select fea from FineractEntityRelation fea where fea.codeName= :codeName")
FineractEntityRelation findOneByCodeName(@Param("codeName") String codeName); FineractEntityRelation findOneByCodeName(@Param("codeName") String codeName);
} }
@@ -34,11 +34,11 @@ import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.entityaccess.api.FineractEntityApiResourceConstants; import org.apache.fineract.infrastructure.entityaccess.api.FineractEntityApiResourceConstants;
import org.apache.fineract.infrastructure.entityaccess.exception.FineractEntityToEntityMappingDateException; import org.apache.fineract.infrastructure.entityaccess.exception.FineractEntityToEntityMappingDateException;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_entity_to_entity_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "rel_id", "from_id", "to_id" }) }) @Table(name = "m_entity_to_entity_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "rel_id", "from_id", "to_id" }) })
public class FineractEntityToEntityMapping extends AbstractPersistable<Long> { public class FineractEntityToEntityMapping extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "rel_id") @JoinColumn(name = "rel_id")
@@ -50,11 +50,11 @@ public class FineractEntityToEntityMapping extends AbstractPersistable<Long> {
@Column(name = "to_id") @Column(name = "to_id")
private Long toId; private Long toId;
@Column(name = "start_date", nullable = false) @Column(name = "start_date", nullable = true)
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
private Date startDate; private Date startDate;
@Column(name = "end_date", nullable = false) @Column(name = "end_date", nullable = true)
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
private Date endDate; private Date endDate;
@@ -27,6 +27,6 @@ public interface FineractEntityToEntityMappingRepository extends JpaRepository<F
@Query("from FineractEntityToEntityMapping feem where feem.fromId= :fromId and feem.toId= :toId and feem.relationId= :relId") @Query("select feem from FineractEntityToEntityMapping feem where feem.fromId= :fromId and feem.toId= :toId and feem.relationId= :relId")
FineractEntityToEntityMapping findListByProductId(@Param("relId")FineractEntityRelation relId, @Param("toId")Long toId, @Param("fromId")Long fromId ); FineractEntityToEntityMapping findListByProductId(@Param("relId")FineractEntityRelation relId, @Param("toId")Long toId, @Param("fromId")Long fromId );
} }
@@ -21,6 +21,9 @@ package org.apache.fineract.infrastructure.entityaccess.service;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
@@ -107,8 +110,12 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
return new CommandProcessingResultBuilder().withEntityId(newMap.getId()).withCommandId(command.commandId()).build(); return new CommandProcessingResultBuilder().withEntityId(newMap.getId()).withCommandId(command.commandId()).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -136,8 +143,12 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
return new CommandProcessingResultBuilder(). // return new CommandProcessingResultBuilder(). //
withEntityId(mapForUpdate.getId()).withCommandId(command.commandId()).build(); withEntityId(mapForUpdate.getId()).withCommandId(command.commandId()).build();
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -154,9 +165,8 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
} }
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
realCause.printStackTrace(); realCause.printStackTrace();
if (realCause.getMessage().contains("rel_id_from_id_to_id")) { if (realCause.getMessage().contains("rel_id_from_id_to_id")) {
final String fromId = command.stringValueOfParameterNamed(FineractEntityApiResourceConstants.fromEnityType); final String fromId = command.stringValueOfParameterNamed(FineractEntityApiResourceConstants.fromEnityType);
@@ -169,7 +179,7 @@ public class FineractEntityAccessWriteServiceImpl implements FineractEntityAcces
throw new PlatformDataIntegrityException("error.msg.entity.mapping", "Unknown data integrity issue with resource."); throw new PlatformDataIntegrityException("error.msg.entity.mapping", "Unknown data integrity issue with resource.");
} }
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) { private void logAsErrorUnexpectedDataIntegrityException(final Exception dve) {
logger.error(dve.getMessage(), dve); logger.error(dve.getMessage(), dve);
} }
@@ -24,11 +24,11 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_hook_configuration") @Table(name = "m_hook_configuration")
public class HookConfiguration extends AbstractPersistable<Long> { public class HookConfiguration extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "hook_id", referencedColumnName = "id", nullable = false) @JoinColumn(name = "hook_id", referencedColumnName = "id", nullable = false)
@@ -28,12 +28,12 @@ import org.springframework.data.repository.query.Param;
public interface HookRepository extends JpaRepository<Hook, Long>, public interface HookRepository extends JpaRepository<Hook, Long>,
JpaSpecificationExecutor<Hook> { JpaSpecificationExecutor<Hook> {
@Query("select hook from Hook hook inner join hook.events event where event.entityName = :entityName and event.actionName = :actionName and hook.isActive = 1") @Query("select hook from Hook hook inner join hook.events event where event.entityName = :entityName and event.actionName = :actionName and hook.isActive = true")
List<Hook> findAllHooksListeningToEvent( List<Hook> findAllHooksListeningToEvent(
@Param("entityName") String entityName, @Param("entityName") String entityName,
@Param("actionName") String actionName); @Param("actionName") String actionName);
@Query("from Hook hook where hook.template.id = :templateId ") @Query("select hook from Hook hook where hook.template.id = :templateId ")
Hook findOneByTemplateId(@Param("templateId") Long templateId); Hook findOneByTemplateId(@Param("templateId") Long templateId);
} }
@@ -24,11 +24,11 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_hook_registered_events") @Table(name = "m_hook_registered_events")
public class HookResource extends AbstractPersistable<Long> { public class HookResource extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "hook_id", referencedColumnName = "id", nullable = false) @JoinColumn(name = "hook_id", referencedColumnName = "id", nullable = false)
@@ -32,17 +32,17 @@ import javax.persistence.Table;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_hook_templates") @Table(name = "m_hook_templates")
public class HookTemplate extends AbstractPersistable<Long> { public class HookTemplate extends AbstractPersistableCustom<Long> {
@Column(name = "name", nullable = false, length = 100) @Column(name = "name", nullable = false, length = 100)
private String name; private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "template", orphanRemoval = true, fetch=FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "template", orphanRemoval = true, fetch=FetchType.EAGER)
private final Set<Schema> fields = new HashSet<>(); private Set<Schema> fields = new HashSet<>();
private HookTemplate(final String name) { private HookTemplate(final String name) {
@@ -27,6 +27,6 @@ public interface HookTemplateRepository extends
JpaRepository<HookTemplate, Long>, JpaRepository<HookTemplate, Long>,
JpaSpecificationExecutor<HookTemplate> { JpaSpecificationExecutor<HookTemplate> {
@Query("from HookTemplate template where template.name = :name") @Query("select template from HookTemplate template where template.name = :name")
HookTemplate findOne(@Param("name") String name); HookTemplate findOne(@Param("name") String name);
} }
@@ -24,11 +24,11 @@ import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_hook_schema") @Table(name = "m_hook_schema")
public class Schema extends AbstractPersistable<Long> { public class Schema extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "hook_template_id", referencedColumnName = "id", nullable = false) @JoinColumn(name = "hook_template_id", referencedColumnName = "id", nullable = false)
@@ -44,7 +44,7 @@ public class Schema extends AbstractPersistable<Long> {
private String placeholder; private String placeholder;
@Column(name = "optional", nullable = false) @Column(name = "optional", nullable = false)
private final boolean optional = false; private boolean optional = false;
public Schema() { public Schema() {
// //
@@ -18,9 +18,26 @@
*/ */
package org.apache.fineract.infrastructure.hooks.service; package org.apache.fineract.infrastructure.hooks.service;
import com.google.gson.JsonArray; import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.actionNameParamName;
import com.google.gson.JsonObject; import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.configParamName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.contentTypeName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.entityNameParamName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.eventsParamName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.nameParamName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.payloadURLName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.templateIdParamName;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.webTemplateName;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
@@ -29,7 +46,13 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.hooks.domain.*; import org.apache.fineract.infrastructure.hooks.domain.Hook;
import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration;
import org.apache.fineract.infrastructure.hooks.domain.HookRepository;
import org.apache.fineract.infrastructure.hooks.domain.HookResource;
import org.apache.fineract.infrastructure.hooks.domain.HookTemplate;
import org.apache.fineract.infrastructure.hooks.domain.HookTemplateRepository;
import org.apache.fineract.infrastructure.hooks.domain.Schema;
import org.apache.fineract.infrastructure.hooks.exception.HookNotFoundException; import org.apache.fineract.infrastructure.hooks.exception.HookNotFoundException;
import org.apache.fineract.infrastructure.hooks.exception.HookTemplateNotFoundException; import org.apache.fineract.infrastructure.hooks.exception.HookTemplateNotFoundException;
import org.apache.fineract.infrastructure.hooks.processor.ProcessorHelper; import org.apache.fineract.infrastructure.hooks.processor.ProcessorHelper;
@@ -44,13 +67,12 @@ import org.springframework.cache.annotation.CacheEvict;
import org.springframework.dao.DataIntegrityViolationException; import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import retrofit.RetrofitError; import retrofit.RetrofitError;
import java.util.*;
import java.util.Map.Entry;
import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.*;
@Service @Service
public class HookWritePlatformServiceJpaRepositoryImpl public class HookWritePlatformServiceJpaRepositoryImpl
implements implements
@@ -117,8 +139,12 @@ public class HookWritePlatformServiceJpaRepositoryImpl
.withCommandId(command.commandId()) .withCommandId(command.commandId())
.withEntityId(hook.getId()).build(); .withEntityId(hook.getId()).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleHookDataIntegrityIssues(command, dve); handleHookDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleHookDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -181,8 +207,12 @@ public class HookWritePlatformServiceJpaRepositoryImpl
.with(changes) // .with(changes) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleHookDataIntegrityIssues(command, dve); handleHookDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return null; return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleHookDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -192,12 +222,9 @@ public class HookWritePlatformServiceJpaRepositoryImpl
public CommandProcessingResult deleteHook(final Long hookId) { public CommandProcessingResult deleteHook(final Long hookId) {
this.context.authenticatedUser(); this.context.authenticatedUser();
final Hook hook = retrieveHookBy(hookId); final Hook hook = retrieveHookBy(hookId);
try { try {
this.hookRepository.delete(hook); this.hookRepository.delete(hook);
this.hookRepository.flush();
} catch (final DataIntegrityViolationException e) { } catch (final DataIntegrityViolationException e) {
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException(
"error.msg.unknown.data.integrity.issue", "error.msg.unknown.data.integrity.issue",
@@ -348,9 +375,8 @@ public class HookWritePlatformServiceJpaRepositoryImpl
} }
} }
private void handleHookDataIntegrityIssues(final JsonCommand command, private void handleHookDataIntegrityIssues(final JsonCommand command, final Throwable realCause,
final DataIntegrityViolationException dve) { final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("hook_name")) { if (realCause.getMessage().contains("hook_name")) {
final String name = command.stringValueOfParameterNamed("name"); final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException(
@@ -31,11 +31,11 @@ import javax.persistence.TemporalType;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.jobs.api.SchedulerJobApiConstants; import org.apache.fineract.infrastructure.jobs.api.SchedulerJobApiConstants;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "job") @Table(name = "job")
public class ScheduledJobDetail extends AbstractPersistable<Long> { public class ScheduledJobDetail extends AbstractPersistableCustom<Long> {
@Column(name = "name") @Column(name = "name")
private String jobName; private String jobName;
@@ -28,14 +28,14 @@ import org.springframework.data.repository.query.Param;
public interface ScheduledJobDetailRepository extends JpaRepository<ScheduledJobDetail, Long>, JpaSpecificationExecutor<ScheduledJobDetail> { public interface ScheduledJobDetailRepository extends JpaRepository<ScheduledJobDetail, Long>, JpaSpecificationExecutor<ScheduledJobDetail> {
@Query("from ScheduledJobDetail jobDetail where jobDetail.jobKey = :jobKey") @Query("select jobDetail from ScheduledJobDetail jobDetail where jobDetail.jobKey = :jobKey")
ScheduledJobDetail findByJobKey(@Param("jobKey") String jobKey); ScheduledJobDetail findByJobKey(@Param("jobKey") String jobKey);
@Query("from ScheduledJobDetail jobDetail where jobDetail.id=:jobId") @Query("select jobDetail from ScheduledJobDetail jobDetail where jobDetail.id=:jobId")
ScheduledJobDetail findByJobId(@Param("jobId") Long jobId); ScheduledJobDetail findByJobId(@Param("jobId") Long jobId);
@Lock(value = LockModeType.PESSIMISTIC_WRITE) @Lock(value = LockModeType.PESSIMISTIC_WRITE)
@Query("from ScheduledJobDetail jobDetail where jobDetail.jobKey = :jobKey") @Query("select jobDetail from ScheduledJobDetail jobDetail where jobDetail.jobKey = :jobKey")
ScheduledJobDetail findByJobKeyWithLock(@Param("jobKey") String jobKey); ScheduledJobDetail findByJobKeyWithLock(@Param("jobKey") String jobKey);
} }
@@ -28,11 +28,11 @@ import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "job_run_history") @Table(name = "job_run_history")
public class ScheduledJobRunHistory extends AbstractPersistable<Long> { public class ScheduledJobRunHistory extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "job_id") @JoinColumn(name = "job_id")
@@ -22,11 +22,11 @@ import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "scheduler_detail") @Table(name = "scheduler_detail")
public class SchedulerDetail extends AbstractPersistable<Long> { public class SchedulerDetail extends AbstractPersistableCustom<Long> {
@Column(name = "execute_misfired_jobs") @Column(name = "execute_misfired_jobs")
private boolean executeInstructionForMisfiredJobs; private boolean executeInstructionForMisfiredJobs;
@@ -23,11 +23,11 @@ import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_report_mailing_job_configuration", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unique_name") }) @Table(name = "m_report_mailing_job_configuration", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unique_name") })
public class ReportMailingJobConfiguration extends AbstractPersistable<Integer> { public class ReportMailingJobConfiguration extends AbstractPersistableCustom<Integer> {
private static final long serialVersionUID = 3099279770861263184L; private static final long serialVersionUID = 3099279770861263184L;
@Column(name = "name", nullable = false) @Column(name = "name", nullable = false)
@@ -28,12 +28,12 @@ import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "m_report_mailing_job_run_history") @Table(name = "m_report_mailing_job_run_history")
public class ReportMailingJobRunHistory extends AbstractPersistable<Long> { public class ReportMailingJobRunHistory extends AbstractPersistableCustom<Long> {
private static final long serialVersionUID = -3757370929988421076L; private static final long serialVersionUID = -3757370929988421076L;
@ManyToOne @ManyToOne
@@ -33,11 +33,11 @@ import org.apache.fineract.infrastructure.sms.SmsApiConstants;
import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.Staff;
import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.domain.Group;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "sms_messages_outbound") @Table(name = "sms_messages_outbound")
public class SmsMessage extends AbstractPersistable<Long> { public class SmsMessage extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "group_id", nullable = true) @JoinColumn(name = "group_id", nullable = true)
@@ -28,11 +28,11 @@ import javax.persistence.Table;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.survey.api.LikelihoodApiConstants; import org.apache.fineract.infrastructure.survey.api.LikelihoodApiConstants;
import org.apache.fineract.infrastructure.survey.data.LikelihoodStatus; import org.apache.fineract.infrastructure.survey.data.LikelihoodStatus;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "ppi_likelihoods_ppi") @Table(name = "ppi_likelihoods_ppi")
public final class Likelihood extends AbstractPersistable<Long> { public final class Likelihood extends AbstractPersistableCustom<Long> {
@Column(name = "ppi_name", nullable = false) @Column(name = "ppi_name", nullable = false)
private String ppiName; private String ppiName;
@@ -29,7 +29,7 @@ import java.util.List;
public interface LikelihoodRepository extends JpaRepository<Likelihood, Long>, JpaSpecificationExecutor<Likelihood> { public interface LikelihoodRepository extends JpaRepository<Likelihood, Long>, JpaSpecificationExecutor<Likelihood> {
@Query("FROM Likelihood WHERE ppi_name =:ppiName AND id !=:id") @Query("select liklihood FROM Likelihood liklihood WHERE ppi_name =:ppiName AND id <>:id")
List<Likelihood> findByPpiNameAndLikeliHoodId(@Param("ppiName") String ppiName,@Param("id") Long likeliHoodId); List<Likelihood> findByPpiNameAndLikeliHoodId(@Param("ppiName") String ppiName,@Param("id") Long likeliHoodId);
} }
@@ -24,11 +24,11 @@ import javax.persistence.Table;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "mix_taxonomy_mapping") @Table(name = "mix_taxonomy_mapping")
public class MixTaxonomyMapping extends AbstractPersistable<Long> { public class MixTaxonomyMapping extends AbstractPersistableCustom<Long> {
@Column(name = "identifier") @Column(name = "identifier")
private String identifier; private String identifier;
@@ -54,13 +54,13 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
import org.apache.fineract.organisation.holiday.api.HolidayApiConstants; import org.apache.fineract.organisation.holiday.api.HolidayApiConstants;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
@Entity @Entity
@Table(name = "m_holiday", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "holiday_name") }) @Table(name = "m_holiday", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "holiday_name") })
public class Holiday extends AbstractPersistable<Long> { public class Holiday extends AbstractPersistableCustom<Long> {
@Column(name = "name", unique = true, nullable = false, length = 100) @Column(name = "name", unique = true, nullable = false, length = 100)
private String name; private String name;
@@ -32,6 +32,6 @@ public interface HolidayRepository extends JpaRepository<Holiday, Long>, JpaSpec
List<Holiday> findByOfficeIdAndGreaterThanDate(@Param("officeId") Long officeId, @Param("date") Date date, List<Holiday> findByOfficeIdAndGreaterThanDate(@Param("officeId") Long officeId, @Param("date") Date date,
@Param("status") Integer status); @Param("status") Integer status);
@Query("from Holiday holiday where holiday.processed = false and holiday.status = :status") @Query("select holiday from Holiday holiday where holiday.processed = false and holiday.status = :status")
List<Holiday> findUnprocessed(@Param("status") Integer status); List<Holiday> findUnprocessed(@Param("status") Integer status);
} }
@@ -24,6 +24,9 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -94,8 +97,12 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(holiday.getId()).build(); return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(holiday.getId()).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -124,8 +131,12 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
return new CommandProcessingResultBuilder().withEntityId(holiday.getId()).with(changes).build(); return new CommandProcessingResultBuilder().withEntityId(holiday.getId()).with(changes).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -168,8 +179,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
return offices; return offices;
} }
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("holiday_name")) { if (realCause.getMessage().contains("holiday_name")) {
final String name = command.stringValueOfParameterNamed("name"); final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException("error.msg.holiday.duplicate.name", "Holiday with name `" + name + "` already exists", throw new PlatformDataIntegrityException("error.msg.holiday.duplicate.name", "Holiday with name `" + name + "` already exists",
@@ -24,29 +24,29 @@ import javax.persistence.Table;
import org.apache.fineract.organisation.monetary.data.CurrencyData; import org.apache.fineract.organisation.monetary.data.CurrencyData;
import org.apache.fineract.organisation.office.domain.OrganisationCurrency; import org.apache.fineract.organisation.office.domain.OrganisationCurrency;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_currency") @Table(name = "m_currency")
public class ApplicationCurrency extends AbstractPersistable<Long> { public class ApplicationCurrency extends AbstractPersistableCustom<Long> {
@Column(name = "code", nullable = false, length = 3) @Column(name = "code", nullable = false, length = 3)
private final String code; private String code;
@Column(name = "decimal_places", nullable = false) @Column(name = "decimal_places", nullable = false)
private final Integer decimalPlaces; private Integer decimalPlaces;
@Column(name = "currency_multiplesof") @Column(name = "currency_multiplesof")
private final Integer inMultiplesOf; private Integer inMultiplesOf;
@Column(name = "name", nullable = false, length = 50) @Column(name = "name", nullable = false, length = 50)
private final String name; private String name;
@Column(name = "internationalized_name_code", nullable = false, length = 50) @Column(name = "internationalized_name_code", nullable = false, length = 50)
private final String nameCode; private String nameCode;
@Column(name = "display_symbol", nullable = true, length = 10) @Column(name = "display_symbol", nullable = true, length = 10)
private final String displaySymbol; private String displaySymbol;
protected ApplicationCurrency() { protected ApplicationCurrency() {
this.code = null; this.code = null;
@@ -25,13 +25,13 @@ import javax.persistence.Embeddable;
public class MonetaryCurrency { public class MonetaryCurrency {
@Column(name = "currency_code", length = 3, nullable = false) @Column(name = "currency_code", length = 3, nullable = false)
private final String code; private String code;
@Column(name = "currency_digits", nullable = false) @Column(name = "currency_digits", nullable = false)
private final int digitsAfterDecimal; private int digitsAfterDecimal;
@Column(name = "currency_multiplesof") @Column(name = "currency_multiplesof")
private final Integer inMultiplesOf; private Integer inMultiplesOf;
protected MonetaryCurrency() { protected MonetaryCurrency() {
this.code = null; this.code = null;
@@ -29,16 +29,16 @@ import javax.persistence.Embeddable;
public class Money implements Comparable<Money> { public class Money implements Comparable<Money> {
@Column(name = "currency_code", length = 3) @Column(name = "currency_code", length = 3)
private final String currencyCode; private String currencyCode;
@Column(name = "currency_digits") @Column(name = "currency_digits")
private final int currencyDigitsAfterDecimal; private int currencyDigitsAfterDecimal;
@Column(name = "currency_multiplesof") @Column(name = "currency_multiplesof")
private final Integer inMultiplesOf; private Integer inMultiplesOf;
@Column(name = "amount", scale = 6, precision = 19) @Column(name = "amount", scale = 6, precision = 19)
private final BigDecimal amount; private BigDecimal amount;
public static Money total(final Money... monies) { public static Money total(final Money... monies) {
if (monies.length == 0) { throw new IllegalArgumentException("Money array must not be empty"); } if (monies.length == 0) { throw new IllegalArgumentException("Money array must not be empty"); }
@@ -37,19 +37,19 @@ import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.organisation.office.exception.CannotUpdateOfficeWithParentOfficeSameAsSelf; import org.apache.fineract.organisation.office.exception.CannotUpdateOfficeWithParentOfficeSameAsSelf;
import org.apache.fineract.organisation.office.exception.RootOfficeParentCannotBeUpdated; import org.apache.fineract.organisation.office.exception.RootOfficeParentCannotBeUpdated;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "m_office", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name_org"), @Table(name = "m_office", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name_org"),
@UniqueConstraint(columnNames = { "external_id" }, name = "externalid_org") }) @UniqueConstraint(columnNames = { "external_id" }, name = "externalid_org") })
public class Office extends AbstractPersistable<Long> { public class Office extends AbstractPersistableCustom<Long> {
@OneToMany(fetch = FetchType.LAZY) @OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id") @JoinColumn(name = "parent_id")
private final List<Office> children = new LinkedList<>(); private List<Office> children = new LinkedList<>();
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id") @JoinColumn(name = "parent_id")
@@ -35,11 +35,11 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.monetary.domain.Money;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_office_transaction") @Table(name = "m_office_transaction")
public class OfficeTransaction extends AbstractPersistable<Long> { public class OfficeTransaction extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "from_office_id") @JoinColumn(name = "from_office_id")
@@ -23,32 +23,32 @@ import javax.persistence.Entity;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
/** /**
* Represents currencies allowed for this MFI/organisation. * Represents currencies allowed for this MFI/organisation.
*/ */
@Entity @Entity
@Table(name = "m_organisation_currency") @Table(name = "m_organisation_currency")
public class OrganisationCurrency extends AbstractPersistable<Long> { public class OrganisationCurrency extends AbstractPersistableCustom<Long> {
@Column(name = "code", nullable = false, length = 3) @Column(name = "code", nullable = false, length = 3)
private final String code; private String code;
@Column(name = "decimal_places", nullable = false) @Column(name = "decimal_places", nullable = false)
private final Integer decimalPlaces; private Integer decimalPlaces;
@Column(name = "currency_multiplesof") @Column(name = "currency_multiplesof")
private final Integer inMultiplesOf; private Integer inMultiplesOf;
@Column(name = "name", nullable = false, length = 50) @Column(name = "name", nullable = false, length = 50)
private final String name; private String name;
@Column(name = "internationalized_name_code", nullable = false, length = 50) @Column(name = "internationalized_name_code", nullable = false, length = 50)
private final String nameCode; private String nameCode;
@Column(name = "display_symbol", nullable = true, length = 10) @Column(name = "display_symbol", nullable = true, length = 10)
private final String displaySymbol; private String displaySymbol;
protected OrganisationCurrency() { protected OrganisationCurrency() {
this.code = null; this.code = null;
@@ -20,6 +20,9 @@ package org.apache.fineract.organisation.office.service;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -105,8 +108,12 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
.withOfficeId(office.getId()) // .withOfficeId(office.getId()) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleOfficeDataIntegrityIssues(command, dve); handleOfficeDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleOfficeDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -148,8 +155,12 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
.with(changes) // .with(changes) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleOfficeDataIntegrityIssues(command, dve); handleOfficeDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleOfficeDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -211,9 +222,8 @@ public class OfficeWritePlatformServiceJpaRepositoryImpl implements OfficeWriteP
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleOfficeDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleOfficeDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("externalid_org")) { if (realCause.getMessage().contains("externalid_org")) {
final String externalId = command.stringValueOfParameterNamed("externalId"); final String externalId = command.stringValueOfParameterNamed("externalId");
throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId `" + externalId throw new PlatformDataIntegrityException("error.msg.office.duplicate.externalId", "Office with externalId `" + externalId
@@ -24,12 +24,12 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "m_loanproduct_provisioning_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "product_id" }, name = "product_id") }) @Table(name = "m_loanproduct_provisioning_mapping", uniqueConstraints = { @UniqueConstraint(columnNames = { "product_id" }, name = "product_id") })
public class LoanProductProvisionCriteria extends AbstractPersistable<Long> { public class LoanProductProvisionCriteria extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "criteria_id", referencedColumnName = "id", nullable = false) @JoinColumn(name = "criteria_id", referencedColumnName = "id", nullable = false)
@@ -27,11 +27,11 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_provision_category", uniqueConstraints = { @UniqueConstraint(columnNames = { "category_name" }, name = "category_name") }) @Table(name = "m_provision_category", uniqueConstraints = { @UniqueConstraint(columnNames = { "category_name" }, name = "category_name") })
public class ProvisioningCategory extends AbstractPersistable<Long> { public class ProvisioningCategory extends AbstractPersistableCustom<Long> {
@Column(name = "category_name", nullable = false, unique = true) @Column(name = "category_name", nullable = false, unique = true)
private String categoryName; private String categoryName;
@@ -116,7 +116,7 @@ public class ProvisioningCriteria extends AbstractAuditableCustom<AppUser, Long>
public void update(ProvisioningCriteriaDefinitionData data, GLAccount liability, GLAccount expense) { public void update(ProvisioningCriteriaDefinitionData data, GLAccount liability, GLAccount expense) {
for(ProvisioningCriteriaDefinition def: provisioningCriteriaDefinition) { for(ProvisioningCriteriaDefinition def: provisioningCriteriaDefinition) {
if(data.getId() == def.getId()) { if(data.getId().equals(def.getId())) {
def.update(data.getMinAge(), data.getMaxAge(), data.getProvisioningPercentage(), liability, expense) ; def.update(data.getMinAge(), data.getMaxAge(), data.getProvisioningPercentage(), liability, expense) ;
break ; break ;
} }
@@ -20,6 +20,7 @@ package org.apache.fineract.organisation.provisioning.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
@@ -27,11 +28,11 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table; import javax.persistence.Table;
import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_provisioning_criteria_definition") @Table(name = "m_provisioning_criteria_definition")
public class ProvisioningCriteriaDefinition extends AbstractPersistable<Long> { public class ProvisioningCriteriaDefinition extends AbstractPersistableCustom<Long> {
@ManyToOne(optional = false) @ManyToOne(optional = false)
@JoinColumn(name = "criteria_id", referencedColumnName = "id", nullable = false) @JoinColumn(name = "criteria_id", referencedColumnName = "id", nullable = false)
@@ -20,6 +20,9 @@ package org.apache.fineract.organisation.provisioning.service;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -65,8 +68,12 @@ public class ProvisioningCategoryWritePlatformServiceJpaRepositoryImpl implement
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCategory.getId()) return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCategory.getId())
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -96,8 +103,12 @@ public class ProvisioningCategoryWritePlatformServiceJpaRepositoryImpl implement
} }
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(categoryId).with(changes).build(); return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(categoryId).with(changes).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -110,9 +121,8 @@ public class ProvisioningCategoryWritePlatformServiceJpaRepositoryImpl implement
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("category_name")) { if (realCause.getMessage().contains("category_name")) {
final String name = command.stringValueOfParameterNamed("category_name"); final String name = command.stringValueOfParameterNamed("category_name");
throw new PlatformDataIntegrityException("error.msg.provisioning.duplicate.categoryname", "Provisioning Cateory with name `" throw new PlatformDataIntegrityException("error.msg.provisioning.duplicate.categoryname", "Provisioning Cateory with name `"
@@ -23,6 +23,9 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.accounting.glaccount.domain.GLAccountRepository; import org.apache.fineract.accounting.glaccount.domain.GLAccountRepository;
import org.apache.fineract.accounting.provisioning.service.ProvisioningEntriesReadPlatformService; import org.apache.fineract.accounting.provisioning.service.ProvisioningEntriesReadPlatformService;
@@ -84,8 +87,12 @@ public class ProvisioningCriteriaWritePlatformServiceJpaRepositoryImpl implement
this.provisioningCriteriaRepository.save(provisioningCriteria); this.provisioningCriteriaRepository.save(provisioningCriteria);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCriteria.getId()).build(); return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCriteria.getId()).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -114,12 +121,16 @@ public class ProvisioningCriteriaWritePlatformServiceJpaRepositoryImpl implement
final Map<String, Object> changes = provisioningCriteria.update(command, products) ; final Map<String, Object> changes = provisioningCriteria.update(command, products) ;
if(!changes.isEmpty()) { if(!changes.isEmpty()) {
updateProvisioningCriteriaDefinitions(provisioningCriteria, command) ; updateProvisioningCriteriaDefinitions(provisioningCriteria, command) ;
provisioningCriteriaRepository.save(provisioningCriteria) ; provisioningCriteriaRepository.saveAndFlush(provisioningCriteria) ;
} }
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCriteria.getId()).build(); return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(provisioningCriteria.getId()).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve); handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -153,9 +164,7 @@ public class ProvisioningCriteriaWritePlatformServiceJpaRepositoryImpl implement
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("criteria_name")) { if (realCause.getMessage().contains("criteria_name")) {
final String name = command.stringValueOfParameterNamed("criteria_name"); final String name = command.stringValueOfParameterNamed("criteria_name");
throw new PlatformDataIntegrityException("error.msg.provisioning.duplicate.criterianame", "Provisioning Criteria with name `" throw new PlatformDataIntegrityException("error.msg.provisioning.duplicate.criterianame", "Provisioning Criteria with name `"
@@ -22,21 +22,29 @@ import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import javax.persistence.*; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.data.EnumOptionData;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.infrastructure.documentmanagement.domain.Image; import org.apache.fineract.infrastructure.documentmanagement.domain.Image;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@Table(name = "m_staff", uniqueConstraints = { @UniqueConstraint(columnNames = { "display_name" }, name = "display_name"), @Table(name = "m_staff", uniqueConstraints = { @UniqueConstraint(columnNames = { "display_name" }, name = "display_name"),
@UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE"), @UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE"),
@UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") }) @UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") })
public class Staff extends AbstractPersistable<Long> { public class Staff extends AbstractPersistableCustom<Long> {
@Column(name = "firstname", length = 50) @Column(name = "firstname", length = 50)
private String firstname; private String firstname;
@@ -57,7 +65,7 @@ public class Staff extends AbstractPersistable<Long> {
@JoinColumn(name = "office_id", nullable = false) @JoinColumn(name = "office_id", nullable = false)
private Office office; private Office office;
@Column(name = "is_loan_officer ", nullable = false) @Column(name = "is_loan_officer", nullable = false)
private boolean loanOfficer; private boolean loanOfficer;
@Column(name = "organisational_role_enum", nullable = true) @Column(name = "organisational_role_enum", nullable = true)
@@ -66,7 +74,7 @@ public class Staff extends AbstractPersistable<Long> {
@Column(name = "is_active", nullable = false) @Column(name = "is_active", nullable = false)
private boolean active; private boolean active;
@Column(name = "joining_date", nullable = false) @Column(name = "joining_date", nullable = true)
@Temporal(TemporalType.DATE) @Temporal(TemporalType.DATE)
private Date joiningDate; private Date joiningDate;
@@ -20,7 +20,10 @@ package org.apache.fineract.organisation.staff.service;
import java.util.Map; import java.util.Map;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -74,8 +77,12 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
.withEntityId(staff.getId()).withOfficeId(officeId) // .withEntityId(staff.getId()).withOfficeId(officeId) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleStaffDataIntegrityIssues(command, dve); handleStaffDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleStaffDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -104,8 +111,12 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(staffId) return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(staffId)
.withOfficeId(staffForUpdate.officeId()).with(changesOnly).build(); .withOfficeId(staffForUpdate.officeId()).with(changesOnly).build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleStaffDataIntegrityIssues(command, dve); handleStaffDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleStaffDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -113,8 +124,7 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleStaffDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleStaffDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("external_id")) { if (realCause.getMessage().contains("external_id")) {
@@ -22,7 +22,7 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.staff.domain.Staff; import org.apache.fineract.organisation.staff.domain.Staff;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.*; import javax.persistence.*;
import java.util.Date; import java.util.Date;
@@ -40,7 +40,7 @@ import java.util.Map;
@Entity @Entity
@Table(name = "m_cashiers", uniqueConstraints = { @UniqueConstraint(name = "ux_cashiers_staff_teller", columnNames = { "staff_id", @Table(name = "m_cashiers", uniqueConstraints = { @UniqueConstraint(name = "ux_cashiers_staff_teller", columnNames = { "staff_id",
"teller_id" }) }) "teller_id" }) })
public class Cashier extends AbstractPersistable<Long> { public class Cashier extends AbstractPersistableCustom<Long> {
// ManyToOne(fetch = FetchType.LAZY) // ManyToOne(fetch = FetchType.LAZY)
// JoinColumn(name = "office_id", nullable = false) // JoinColumn(name = "office_id", nullable = false)
@@ -22,7 +22,7 @@ package org.apache.fineract.organisation.teller.domain;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.*; import javax.persistence.*;
@@ -33,7 +33,7 @@ import java.util.Map;
@Entity @Entity
@Table(name = "m_cashier_transactions") @Table(name = "m_cashier_transactions")
public class CashierTransaction extends AbstractPersistable<Long> { public class CashierTransaction extends AbstractPersistableCustom<Long> {
@Transient @Transient
private Office office; private Office office;
@@ -58,10 +58,10 @@ public class CashierTransaction extends AbstractPersistable<Long> {
@Column(name = "txn_note", nullable = true) @Column(name = "txn_note", nullable = true)
private String txnNote; private String txnNote;
@Column(name = "entity_type", nullable = false) @Column(name = "entity_type", nullable = true)
private String entityType; private String entityType;
@Column(name = "entity_id", nullable = false) @Column(name = "entity_id", nullable = true)
private Long entityId; private Long entityId;
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@@ -39,24 +39,24 @@ import org.apache.fineract.accounting.glaccount.domain.GLAccount;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_tellers", uniqueConstraints = { @Table(name = "m_tellers", uniqueConstraints = {
@UniqueConstraint(name = "ux_tellers_name", columnNames = {"name"}) @UniqueConstraint(name = "ux_tellers_name", columnNames = {"name"})
}) })
public class Teller extends AbstractPersistable<Long> { public class Teller extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "office_id", nullable = false) @JoinColumn(name = "office_id", nullable = false)
private Office office; private Office office;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "debit_account_id", nullable = false) @JoinColumn(name = "debit_account_id", nullable = true)
private GLAccount debitAccount; private GLAccount debitAccount;
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "credit_account_id", nullable = false) @JoinColumn(name = "credit_account_id", nullable = true)
private GLAccount creditAccount; private GLAccount creditAccount;
@Column(name = "name", nullable = false, length = 100) @Column(name = "name", nullable = false, length = 100)
@@ -66,11 +66,11 @@ public class Teller extends AbstractPersistable<Long> {
private String description; private String description;
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@Column(name = "valid_from", nullable = false) @Column(name = "valid_from", nullable = true)
private Date startDate; private Date startDate;
@Temporal(TemporalType.TIMESTAMP) @Temporal(TemporalType.TIMESTAMP)
@Column(name = "valid_to", nullable = false) @Column(name = "valid_to", nullable = true)
private Date endDate; private Date endDate;
@Column(name = "state", nullable = false) @Column(name = "state", nullable = false)
@@ -79,9 +79,6 @@ public class Teller extends AbstractPersistable<Long> {
@OneToMany(mappedBy = "teller", fetch = FetchType.LAZY) @OneToMany(mappedBy = "teller", fetch = FetchType.LAZY)
private Set<Cashier> cashiers; private Set<Cashier> cashiers;
@OneToMany(mappedBy = "teller", fetch = FetchType.LAZY)
private Set<TellerTransaction> tellerTransactions;
public Teller() { public Teller() {
super(); super();
} }
@@ -287,11 +284,8 @@ public class Teller extends AbstractPersistable<Long> {
this.cashiers = cashiers; this.cashiers = cashiers;
} }
public Set<TellerTransaction> getTransactions() { public void initializeLazyCollections() {
return tellerTransactions; this.office.getId();
} this.cashiers.size();
}
public void setTransactions(Set<TellerTransaction> tellerTransactions) {
this.tellerTransactions = tellerTransactions;
}
} }
@@ -21,6 +21,7 @@ package org.apache.fineract.organisation.teller.domain;
import org.apache.fineract.organisation.teller.exception.TellerNotFoundException; import org.apache.fineract.organisation.teller.exception.TellerNotFoundException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service @Service
public class TellerRepositoryWrapper { public class TellerRepositoryWrapper {
@@ -32,9 +33,23 @@ public class TellerRepositoryWrapper {
this.repository = repository; this.repository = repository;
} }
@Transactional(readOnly=true)
public Teller findOneWithNotFoundDetection(final Long id) { public Teller findOneWithNotFoundDetection(final Long id) {
final Teller teller = this.repository.findOne(id); final Teller teller = this.repository.findOne(id);
if (teller == null) { throw new TellerNotFoundException(id); } if (teller == null) { throw new TellerNotFoundException(id); }
teller.initializeLazyCollections();
return teller; return teller;
} }
public Teller save(final Teller teller) {
return this.repository.save(teller) ;
}
public Teller saveAndFlush(final Teller teller) {
return this.repository.saveAndFlush(teller) ;
}
public void delete(final Teller teller) {
this.repository.delete(teller);
}
} }
@@ -20,14 +20,14 @@ package org.apache.fineract.organisation.teller.domain;
import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.Client;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.*; import javax.persistence.*;
import java.util.Date; import java.util.Date;
@Entity @Entity
@Table(name = "m_teller_transactions") @Table(name = "m_teller_transactions")
public class TellerTransaction extends AbstractPersistable<Long> { public class TellerTransaction extends AbstractPersistableCustom<Long> {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "office_id", nullable = false) @JoinColumn(name = "office_id", nullable = false)
@@ -21,6 +21,9 @@ package org.apache.fineract.organisation.teller.service;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.PersistenceException;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.fineract.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY; import org.apache.fineract.accounting.common.AccountingConstants.FINANCIAL_ACTIVITY;
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount; import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount;
import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccountRepositoryWrapper; import org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccountRepositoryWrapper;
@@ -45,11 +48,9 @@ import org.apache.fineract.organisation.teller.domain.CashierTransaction;
import org.apache.fineract.organisation.teller.domain.CashierTransactionRepository; import org.apache.fineract.organisation.teller.domain.CashierTransactionRepository;
import org.apache.fineract.organisation.teller.domain.CashierTxnType; import org.apache.fineract.organisation.teller.domain.CashierTxnType;
import org.apache.fineract.organisation.teller.domain.Teller; import org.apache.fineract.organisation.teller.domain.Teller;
import org.apache.fineract.organisation.teller.domain.TellerRepository;
import org.apache.fineract.organisation.teller.domain.TellerRepositoryWrapper; import org.apache.fineract.organisation.teller.domain.TellerRepositoryWrapper;
import org.apache.fineract.organisation.teller.exception.CashierExistForTellerException; import org.apache.fineract.organisation.teller.exception.CashierExistForTellerException;
import org.apache.fineract.organisation.teller.exception.CashierNotFoundException; import org.apache.fineract.organisation.teller.exception.CashierNotFoundException;
import org.apache.fineract.organisation.teller.exception.TellerNotFoundException;
import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer; import org.apache.fineract.organisation.teller.serialization.TellerCommandFromApiJsonDeserializer;
import org.apache.fineract.portfolio.client.domain.ClientTransaction; import org.apache.fineract.portfolio.client.domain.ClientTransaction;
import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUser;
@@ -67,7 +68,6 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer; private final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final TellerRepository tellerRepository;
private final TellerRepositoryWrapper tellerRepositoryWrapper; private final TellerRepositoryWrapper tellerRepositoryWrapper;
private final OfficeRepositoryWrapper officeRepositoryWrapper; private final OfficeRepositoryWrapper officeRepositoryWrapper;
private final StaffRepository staffRepository; private final StaffRepository staffRepository;
@@ -78,14 +78,13 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
@Autowired @Autowired
public TellerWritePlatformServiceJpaImpl(final PlatformSecurityContext context, public TellerWritePlatformServiceJpaImpl(final PlatformSecurityContext context,
final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer, final TellerRepository tellerRepository, final TellerCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final TellerRepositoryWrapper tellerRepositoryWrapper, final OfficeRepositoryWrapper officeRepositoryWrapper, final TellerRepositoryWrapper tellerRepositoryWrapper, final OfficeRepositoryWrapper officeRepositoryWrapper,
final StaffRepository staffRepository, CashierRepository cashierRepository, CashierTransactionRepository cashierTxnRepository, final StaffRepository staffRepository, CashierRepository cashierRepository, CashierTransactionRepository cashierTxnRepository,
JournalEntryRepository glJournalEntryRepository, JournalEntryRepository glJournalEntryRepository,
FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper) { FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper) {
this.context = context; this.context = context;
this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.tellerRepository = tellerRepository;
this.tellerRepositoryWrapper = tellerRepositoryWrapper; this.tellerRepositoryWrapper = tellerRepositoryWrapper;
this.officeRepositoryWrapper = officeRepositoryWrapper; this.officeRepositoryWrapper = officeRepositoryWrapper;
this.staffRepository = staffRepository; this.staffRepository = staffRepository;
@@ -111,7 +110,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
final Teller teller = Teller.fromJson(tellerOffice, command); final Teller teller = Teller.fromJson(tellerOffice, command);
// pre save to generate id for use in office hierarchy // pre save to generate id for use in office hierarchy
this.tellerRepository.save(teller); this.tellerRepositoryWrapper.save(teller);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) // .withCommandId(command.commandId()) //
@@ -119,8 +118,12 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
.withOfficeId(teller.getOffice().getId()) // .withOfficeId(teller.getOffice().getId()) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleTellerDataIntegrityIssues(command, dve); handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleTellerDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -140,7 +143,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
final Map<String, Object> changes = teller.update(tellerOffice, command); final Map<String, Object> changes = teller.update(tellerOffice, command);
if (!changes.isEmpty()) { if (!changes.isEmpty()) {
this.tellerRepository.saveAndFlush(teller); this.tellerRepositoryWrapper.saveAndFlush(teller);
} }
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -150,8 +153,12 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
.with(changes) // .with(changes) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleTellerDataIntegrityIssues(command, dve); handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleTellerDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -163,15 +170,10 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
final Long userOfficeId = currentUser.getOffice().getId(); final Long userOfficeId = currentUser.getOffice().getId();
final Office userOffice = this.officeRepositoryWrapper.findOfficeHierarchy(userOfficeId); final Office userOffice = this.officeRepositoryWrapper.findOfficeHierarchy(userOfficeId);
final Teller tellerToReturn = this.tellerRepository.findOne(tellerId); final Teller tellerToReturn = this.tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
if (tellerToReturn != null) { final Long tellerOfficeId = tellerToReturn.officeId();
final Long tellerOfficeId = tellerToReturn.officeId(); if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(tellerOfficeId)) { throw new NoAuthorizationException(
if (userOffice.doesNotHaveAnOfficeInHierarchyWithId(tellerOfficeId)) { throw new NoAuthorizationException(
"User does not have sufficient priviledges to act on the provided office."); } "User does not have sufficient priviledges to act on the provided office."); }
} else {
throw new TellerNotFoundException(tellerId);
}
return tellerToReturn; return tellerToReturn;
} }
@@ -188,7 +190,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
.equalsIgnoreCase(tellerId.toString())) { throw new CashierExistForTellerException(tellerId); } .equalsIgnoreCase(tellerId.toString())) { throw new CashierExistForTellerException(tellerId); }
} }
tellerRepository.delete(teller); tellerRepositoryWrapper.delete(teller);
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
.withEntityId(teller.getId()) // .withEntityId(teller.getId()) //
.build(); .build();
@@ -199,9 +201,8 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
* Guaranteed to throw an exception no matter what the data integrity issue * Guaranteed to throw an exception no matter what the data integrity issue
* is. * is.
*/ */
private void handleTellerDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { private void handleTellerDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) {
final Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("m_tellers_name_unq")) { if (realCause.getMessage().contains("m_tellers_name_unq")) {
final String name = command.stringValueOfParameterNamed("name"); final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException("error.msg.teller.duplicate.name", "Teller with name `" + name + "` already exists", throw new PlatformDataIntegrityException("error.msg.teller.duplicate.name", "Teller with name `" + name + "` already exists",
@@ -223,8 +224,7 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
Long minEndTime; Long minEndTime;
String startTime = " "; String startTime = " ";
String endTime = " "; String endTime = " ";
final Teller teller = this.tellerRepository.findOne(tellerId); final Teller teller = this.tellerRepositoryWrapper.findOneWithNotFoundDetection(tellerId);
if (teller == null) { throw new TellerNotFoundException(tellerId); }
final Office tellerOffice = teller.getOffice(); final Office tellerOffice = teller.getOffice();
final Long staffId = command.longValueOfParameterNamed("staffId"); final Long staffId = command.longValueOfParameterNamed("staffId");
@@ -262,8 +262,12 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
.withSubEntityId(cashier.getId()) // .withSubEntityId(cashier.getId()) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleTellerDataIntegrityIssues(command, dve); handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleTellerDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -298,8 +302,12 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
.with(changes) // .with(changes) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleTellerDataIntegrityIssues(command, dve); handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleTellerDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -321,8 +329,12 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
this.cashierRepository.delete(cashier); this.cashierRepository.delete(cashier);
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleTellerDataIntegrityIssues(command, dve); handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleTellerDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
return new CommandProcessingResultBuilder() // return new CommandProcessingResultBuilder() //
@@ -444,8 +456,12 @@ public class TellerWritePlatformServiceJpaImpl implements TellerWritePlatformSer
.withSubEntityId(cashierTxn.getId()) // .withSubEntityId(cashierTxn.getId()) //
.build(); .build();
} catch (final DataIntegrityViolationException dve) { } catch (final DataIntegrityViolationException dve) {
handleTellerDataIntegrityIssues(command, dve); handleTellerDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
return CommandProcessingResult.empty(); return CommandProcessingResult.empty();
}catch (final PersistenceException dve) {
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()) ;
handleTellerDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
} }
} }
@@ -20,7 +20,7 @@ package org.apache.fineract.organisation.workingdays.domain;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.organisation.workingdays.api.WorkingDaysApiConstants; import org.apache.fineract.organisation.workingdays.api.WorkingDaysApiConstants;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
@@ -31,7 +31,7 @@ import java.util.Map;
@Entity @Entity
@Table(name = "m_working_days") @Table(name = "m_working_days")
public class WorkingDays extends AbstractPersistable<Long> { public class WorkingDays extends AbstractPersistableCustom<Long> {
@Column(name = "recurrence", length = 100, nullable = true) @Column(name = "recurrence", length = 100, nullable = true)
private String recurrence; private String recurrence;
@@ -26,11 +26,11 @@ import javax.persistence.Table;
import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_portfolio_account_associations") @Table(name = "m_portfolio_account_associations")
public class AccountAssociations extends AbstractPersistable<Long> { public class AccountAssociations extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "loan_account_id", nullable = true) @JoinColumn(name = "loan_account_id", nullable = true)
@@ -26,9 +26,9 @@ import org.springframework.data.repository.query.Param;
public interface AccountAssociationsRepository extends JpaRepository<AccountAssociations, Long>, public interface AccountAssociationsRepository extends JpaRepository<AccountAssociations, Long>,
JpaSpecificationExecutor<AccountAssociations> { JpaSpecificationExecutor<AccountAssociations> {
@Query("from AccountAssociations aa where aa.loanAccount.id= :loanId and aa.associationType = :associationType") @Query("select aa from AccountAssociations aa where aa.loanAccount.id= :loanId and aa.associationType = :associationType")
AccountAssociations findByLoanIdAndType(@Param("loanId") Long loanId, @Param("associationType") Integer accountAssociationType); AccountAssociations findByLoanIdAndType(@Param("loanId") Long loanId, @Param("associationType") Integer accountAssociationType);
@Query("from AccountAssociations aa where aa.savingsAccount.id= :savingsId and aa.associationType = :associationType") @Query("select aa from AccountAssociations aa where aa.savingsAccount.id= :savingsId and aa.associationType = :associationType")
AccountAssociations findBySavingsIdAndType(@Param("savingsId") Long savingsId, @Param("associationType") Integer accountAssociationType); AccountAssociations findBySavingsIdAndType(@Param("savingsId") Long savingsId, @Param("associationType") Integer accountAssociationType);
} }
@@ -35,11 +35,11 @@ import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_account_transfer_details") @Table(name = "m_account_transfer_details")
public class AccountTransferDetails extends AbstractPersistable<Long> { public class AccountTransferDetails extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "from_office_id", nullable = false) @JoinColumn(name = "from_office_id", nullable = false)
@@ -77,9 +77,9 @@ public class AccountTransferDetails extends AbstractPersistable<Long> {
private Integer transferType; private Integer transferType;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "accountTransferDetails", orphanRemoval = true, fetch=FetchType.EAGER) @OneToMany(cascade = CascadeType.ALL, mappedBy = "accountTransferDetails", orphanRemoval = true, fetch=FetchType.EAGER)
private final List<AccountTransferTransaction> accountTransferTransactions = new ArrayList<>(); private List<AccountTransferTransaction> accountTransferTransactions = new ArrayList<>();
@OneToOne(mappedBy = "accountTransferDetails", cascade = CascadeType.ALL, optional = true, orphanRemoval = true, fetch = FetchType.LAZY) @OneToOne(mappedBy = "accountTransferDetails", cascade = CascadeType.ALL, optional = true, orphanRemoval = true, fetch = FetchType.EAGER)
private AccountTransferStandingInstruction accountTransferStandingInstruction; private AccountTransferStandingInstruction accountTransferStandingInstruction;
public static AccountTransferDetails savingsToSavingsTransfer(final Office fromOffice, final Client fromClient, public static AccountTransferDetails savingsToSavingsTransfer(final Office fromOffice, final Client fromClient,
@@ -29,15 +29,15 @@ import org.springframework.data.repository.query.Param;
public interface AccountTransferRepository extends JpaRepository<AccountTransferTransaction, Long>, public interface AccountTransferRepository extends JpaRepository<AccountTransferTransaction, Long>,
JpaSpecificationExecutor<AccountTransferTransaction> { JpaSpecificationExecutor<AccountTransferTransaction> {
@Query("from AccountTransferTransaction att where att.accountTransferDetails.fromLoanAccount.id= :accountNumber and att.reversed=false") @Query("select att from AccountTransferTransaction att where att.accountTransferDetails.fromLoanAccount.id= :accountNumber and att.reversed=false")
List<AccountTransferTransaction> findByFromLoanId(@Param("accountNumber") Long accountNumber); List<AccountTransferTransaction> findByFromLoanId(@Param("accountNumber") Long accountNumber);
@Query("from AccountTransferTransaction att where (att.accountTransferDetails.fromLoanAccount.id= :accountNumber or att.accountTransferDetails.toLoanAccount.id=:accountNumber) and att.reversed=false order by att.id desc") @Query("select att from AccountTransferTransaction att where (att.accountTransferDetails.fromLoanAccount.id= :accountNumber or att.accountTransferDetails.toLoanAccount.id=:accountNumber) and att.reversed=false order by att.id desc")
List<AccountTransferTransaction> findAllByLoanId(@Param("accountNumber") Long accountNumber); List<AccountTransferTransaction> findAllByLoanId(@Param("accountNumber") Long accountNumber);
@Query("from AccountTransferTransaction att where att.toLoanTransaction.id= :loanTransactionId and att.reversed=false") @Query("select att from AccountTransferTransaction att where att.toLoanTransaction.id= :loanTransactionId and att.reversed=false")
AccountTransferTransaction findByToLoanTransactionId(@Param("loanTransactionId") Long loanTransactionId); AccountTransferTransaction findByToLoanTransactionId(@Param("loanTransactionId") Long loanTransactionId);
@Query("from AccountTransferTransaction att where att.fromLoanTransaction.id IN :loanTransactions and att.reversed=false") @Query("select att from AccountTransferTransaction att where att.fromLoanTransaction.id IN :loanTransactions and att.reversed=false")
List<AccountTransferTransaction> findByFromLoanTransactions(@Param("loanTransactions") Collection<Long> loanTransactions); List<AccountTransferTransaction> findByFromLoanTransactions(@Param("loanTransactions") Collection<Long> loanTransactions);
} }
@@ -54,11 +54,11 @@ import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidati
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.joda.time.MonthDay; import org.joda.time.MonthDay;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_account_transfer_standing_instructions", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name") }) @Table(name = "m_account_transfer_standing_instructions", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "name") })
public class AccountTransferStandingInstruction extends AbstractPersistable<Long> { public class AccountTransferStandingInstruction extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "account_transfer_details_id", nullable = true) @JoinColumn(name = "account_transfer_details_id", nullable = true)
@@ -35,11 +35,11 @@ import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction; import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
@Entity @Entity
@Table(name = "m_account_transfer_transaction") @Table(name = "m_account_transfer_transaction")
public class AccountTransferTransaction extends AbstractPersistable<Long> { public class AccountTransferTransaction extends AbstractPersistableCustom<Long> {
@ManyToOne @ManyToOne
@JoinColumn(name = "account_transfer_details_id", nullable = true) @JoinColumn(name = "account_transfer_details_id", nullable = true)

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