This is an automated email from the ASF dual-hosted git repository.
aleks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 02fb166b5b FINERACT-2239: New command processing - resource notes
02fb166b5b is described below
commit 02fb166b5ba070cac5420637cfbce2c366dcc6ea
Author: Aleks <[email protected]>
AuthorDate: Sun Feb 1 02:26:44 2026 +0100
FINERACT-2239: New command processing - resource notes
---
config/docker/compose/fineract.yml | 2 -
config/docker/env/fineract-common.env | 2 +-
.../note/service/AcmeNoteWritePlatformService.java | 25 +-
.../note/starter/TestDefaultConfiguration.java | 12 -
.../note/starter/TestOverrideConfiguration.java | 12 -
docker-compose.yml | 1 +
.../infrastructure/cache/data/CacheData.java | 7 +-
.../portfolio/note/data/NoteCreateRequest.java | 14 +-
.../portfolio/note/data/NoteCreateResponse.java | 8 +-
.../fineract/portfolio/note/data/NoteData.java | 48 ++-
.../portfolio/note/data/NoteDeleteRequest.java | 13 +-
.../portfolio/note/data/NoteDeleteResponse.java | 6 +-
.../portfolio/note/data/NoteUpdateRequest.java | 16 +-
.../portfolio/note/data/NoteUpdateResponse.java | 9 +-
.../note/service/NoteWritePlatformService.java | 19 +-
.../BuyDownFeeWritePlatformServiceImpl.java | 12 +-
.../CapitalizedIncomeWritePlatformServiceImpl.java | 12 +-
.../ProgressiveLoanAccountConfiguration.java | 13 +-
.../infrastructure/core/config/SecurityConfig.java | 44 +++
.../starter/LoanAccountConfiguration.java | 12 +-
.../portfolio/note/api/NotesApiResource.java | 238 +++++------
.../note/api/NotesApiResourceSwagger.java | 82 ----
.../{NoteCommand.java => NoteCreateCommand.java} | 19 +-
.../{NoteCommand.java => NoteDeleteCommand.java} | 19 +-
.../{NoteCommand.java => NoteUpdateCommand.java} | 19 +-
.../fineract/portfolio/note/domain/Note.java | 27 +-
...dHandler.java => NoteCreateCommandHandler.java} | 33 +-
...dHandler.java => NoteDeleteCommandHandler.java} | 35 +-
...dHandler.java => NoteUpdateCommandHandler.java} | 34 +-
.../portfolio/note/listener/NoteListener.java | 49 +++
.../NoteCommandFromApiJsonDeserializer.java | 102 -----
.../NoteWritePlatformServiceJpaRepositoryImpl.java | 438 ++++-----------------
.../note/starter/NoteAutoConfiguration.java | 5 +-
...nsferWritePlatformServiceJpaRepositoryImpl.java | 9 +-
.../transfer/starter/TransferConfiguration.java | 11 +-
.../src/main/resources/application.properties | 32 ++
.../main/resources/ValidationMessages.properties | 5 +
.../fineract/integrationtests/NotesTest.java | 7 +-
.../integrationtests/common/NotesHelper.java | 10 +-
39 files changed, 548 insertions(+), 913 deletions(-)
diff --git a/config/docker/compose/fineract.yml
b/config/docker/compose/fineract.yml
index ae5323c41c..801b73fc65 100644
--- a/config/docker/compose/fineract.yml
+++ b/config/docker/compose/fineract.yml
@@ -16,8 +16,6 @@
# under the License.
#
-version: "3.8"
-
services:
fineract:
# user: "${FINERACT_USER}:${FINERACT_GROUP}"
diff --git a/config/docker/env/fineract-common.env
b/config/docker/env/fineract-common.env
index b77bb24b0e..4b0dc24650 100644
--- a/config/docker/env/fineract-common.env
+++ b/config/docker/env/fineract-common.env
@@ -56,4 +56,4 @@ FINERACT_REMOTE_JOB_MESSAGE_HANDLER_SPRING_EVENTS_ENABLED=true
FINERACT_INSECURE_HTTP_CLIENT=true
SPRING_PROFILES_ACTIVE=test,diagnostics
OTEL_SERVICE_NAME=fineract
-JAVA_TOOL_OPTIONS="-Xmx1G -XX:MinRAMPercentage=25 -XX:MaxRAMPercentage=80
-XX:TieredStopAtLevel=1 -XX:+UseContainerSupport -XX:+UseStringDeduplication
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.security=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.management/javax.management=ALL-UNNAMED [...]
+JAVA_TOOL_OPTIONS="
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5000 -Xmx1G
-XX:MinRAMPercentage=25 -XX:MaxRAMPercentage=80 -XX:TieredStopAtLevel=1
-XX:+UseContainerSupport -XX:+UseStringDeduplication
--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.uti
[...]
diff --git
a/custom/acme/note/service/src/main/java/com/acme/fineract/portfolio/note/service/AcmeNoteWritePlatformService.java
b/custom/acme/note/service/src/main/java/com/acme/fineract/portfolio/note/service/AcmeNoteWritePlatformService.java
index 14b194f20a..ad15721bae 100644
---
a/custom/acme/note/service/src/main/java/com/acme/fineract/portfolio/note/service/AcmeNoteWritePlatformService.java
+++
b/custom/acme/note/service/src/main/java/com/acme/fineract/portfolio/note/service/AcmeNoteWritePlatformService.java
@@ -19,9 +19,12 @@
package com.acme.fineract.portfolio.note.service;
import lombok.extern.slf4j.Slf4j;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import org.apache.fineract.portfolio.client.domain.Client;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
+import org.apache.fineract.portfolio.note.data.NoteDeleteRequest;
+import org.apache.fineract.portfolio.note.data.NoteDeleteResponse;
+import org.apache.fineract.portfolio.note.data.NoteUpdateRequest;
+import org.apache.fineract.portfolio.note.data.NoteUpdateResponse;
import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -38,27 +41,17 @@ public class AcmeNoteWritePlatformService implements
NoteWritePlatformService, I
}
@Override
- public CommandProcessingResult createNote(JsonCommand command) {
+ public NoteCreateResponse createNote(NoteCreateRequest request) {
throw new UnsupportedOperationException("createNote() is not yet
implemented.");
}
@Override
- public void createLoanTransactionNote(Long loanTransactionId, String note)
{
- throw new UnsupportedOperationException("createLoanTransactionNote()
is not yet implemented.");
- }
-
- @Override
- public CommandProcessingResult updateNote(JsonCommand command) {
+ public NoteUpdateResponse updateNote(NoteUpdateRequest request) {
throw new UnsupportedOperationException("updateNote() is not yet
implemented.");
}
@Override
- public CommandProcessingResult deleteNote(JsonCommand command) {
+ public NoteDeleteResponse deleteNote(NoteDeleteRequest request) {
throw new UnsupportedOperationException("deleteNote() is not yet
implemented.");
}
-
- @Override
- public void createAndPersistClientNote(Client client, JsonCommand command)
{
- log.warn("createAndPersistClientNote() is intentionally left empty and
does nothing.");
- }
}
diff --git
a/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestDefaultConfiguration.java
b/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestDefaultConfiguration.java
index 8a2395af1b..1706c8c4c3 100644
---
a/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestDefaultConfiguration.java
+++
b/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestDefaultConfiguration.java
@@ -21,7 +21,6 @@ package com.acme.fineract.portfolio.note.starter;
import static org.mockito.Mockito.mock;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
-import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import
org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import
org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
@@ -29,7 +28,6 @@ import
org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
-import
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
import
org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -38,11 +36,6 @@ import org.springframework.jdbc.core.JdbcTemplate;
public class TestDefaultConfiguration {
// NOTE: unfortunately an abastract base class that contains all these
mock functions won't work
- @Bean
- public FromJsonHelper fromJsonHelper() {
- return mock(FromJsonHelper.class);
- }
-
@Bean
public RoutingDataSourceServiceFactory routingDataSourceServiceFactory() {
return mock(RoutingDataSourceServiceFactory.class);
@@ -82,9 +75,4 @@ public class TestDefaultConfiguration {
public LoanTransactionRepository loanTransactionRepository() {
return mock(LoanTransactionRepository.class);
}
-
- @Bean
- public NoteCommandFromApiJsonDeserializer
fromApiJsonDeserializer(FromJsonHelper fromJsonHelper) {
- return new NoteCommandFromApiJsonDeserializer(fromJsonHelper);
- }
}
diff --git
a/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestOverrideConfiguration.java
b/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestOverrideConfiguration.java
index 10f8d6cce0..cc89614e01 100644
---
a/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestOverrideConfiguration.java
+++
b/custom/acme/note/starter/src/test/java/com/acme/fineract/portfolio/note/starter/TestOverrideConfiguration.java
@@ -20,7 +20,6 @@ package com.acme.fineract.portfolio.note.starter;
import static org.mockito.Mockito.mock;
-import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import
org.apache.fineract.infrastructure.core.service.database.RoutingDataSource;
import
org.apache.fineract.infrastructure.core.service.database.RoutingDataSourceServiceFactory;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
@@ -28,7 +27,6 @@ import
org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
-import
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -37,11 +35,6 @@ import org.springframework.jdbc.core.JdbcTemplate;
public class TestOverrideConfiguration {
// NOTE: unfortunately an abastract base class that contains all these
mock functions won't work
- @Bean
- public FromJsonHelper fromJsonHelper() {
- return mock(FromJsonHelper.class);
- }
-
@Bean
public RoutingDataSourceServiceFactory routingDataSourceServiceFactory() {
return mock(RoutingDataSourceServiceFactory.class);
@@ -81,9 +74,4 @@ public class TestOverrideConfiguration {
public LoanTransactionRepository loanTransactionRepository() {
return mock(LoanTransactionRepository.class);
}
-
- @Bean
- public NoteCommandFromApiJsonDeserializer
fromApiJsonDeserializer(FromJsonHelper fromJsonHelper) {
- return new NoteCommandFromApiJsonDeserializer(fromJsonHelper);
- }
}
diff --git a/docker-compose.yml b/docker-compose.yml
index f37fb6f2ca..89723ea21c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -29,6 +29,7 @@ services:
service: fineract
ports:
- "8443:8443"
+ - "5000:5000"
depends_on:
db:
condition: service_healthy
diff --git
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/data/CacheData.java
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/data/CacheData.java
index 771b6d553b..6d6eaea5fc 100644
---
a/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/data/CacheData.java
+++
b/fineract-core/src/main/java/org/apache/fineract/infrastructure/cache/data/CacheData.java
@@ -18,6 +18,8 @@
*/
package org.apache.fineract.infrastructure.cache.data;
+import java.io.Serial;
+import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -28,7 +30,10 @@ import
org.apache.fineract.infrastructure.core.data.EnumOptionData;
@Data
@NoArgsConstructor
@AllArgsConstructor
-public final class CacheData {
+public final class CacheData implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
@SuppressWarnings("unused")
private EnumOptionData cacheType;
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteCreateRequest.java
similarity index 68%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
copy to
fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteCreateRequest.java
index 05a1082086..b5e7edfed9 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteCreateRequest.java
@@ -18,19 +18,31 @@
*/
package org.apache.fineract.portfolio.note.data;
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import org.apache.fineract.portfolio.note.domain.NoteType;
+@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class NoteRequest implements Serializable {
+public class NoteCreateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
+ @Hidden
+ private Long resourceId;
+ @Hidden
+ private NoteType type;
+ @Size(max = 1000, message =
"{org.apache.fineract.portfolio.note.note.size}")
+ @NotNull(message = "{org.apache.fineract.portfolio.note.note.not-null}")
private String note;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteCreateResponse.java
similarity index 86%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
copy to
fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteCreateResponse.java
index 05a1082086..403a50a6db 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteCreateResponse.java
@@ -21,16 +21,20 @@ package org.apache.fineract.portfolio.note.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class NoteRequest implements Serializable {
+public class NoteCreateResponse implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
- private String note;
+ private Long entityId;
+ private Long officeId;
+ private Long resourceId;
}
diff --git
a/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteData.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteData.java
index 091e76792e..6f998732a8 100644
---
a/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteData.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteData.java
@@ -18,31 +18,37 @@
*/
package org.apache.fineract.portfolio.note.data;
+import java.io.Serial;
+import java.io.Serializable;
import java.time.OffsetDateTime;
+import lombok.AllArgsConstructor;
import lombok.Builder;
-import lombok.Getter;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
-/**
- * Immutable data object represent note or case information about a client,
loan or loan transaction.
- */
-@Getter
@Builder
-public class NoteData {
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class NoteData implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
- private final Long id;
- private final Long clientId;
- private final Long groupId;
- private final Long loanId;
- private final Long loanTransactionId;
- private final Long depositAccountId;
- private final Long savingAccountId;
- private final EnumOptionData noteType;
- private final String note;
- private final Long createdById;
- private final String createdByUsername;
- private final OffsetDateTime createdOn;
- private final Long updatedById;
- private final String updatedByUsername;
- private final OffsetDateTime updatedOn;
+ private Long id;
+ private Long clientId;
+ private Long groupId;
+ private Long loanId;
+ private Long loanTransactionId;
+ private Long depositAccountId;
+ private Long savingAccountId;
+ private EnumOptionData noteType;
+ private String note;
+ private Long createdById;
+ private String createdByUsername;
+ private OffsetDateTime createdOn;
+ private Long updatedById;
+ private String updatedByUsername;
+ private OffsetDateTime updatedOn;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteDeleteRequest.java
similarity index 78%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
copy to
fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteDeleteRequest.java
index 05a1082086..6ef1049587 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteDeleteRequest.java
@@ -18,19 +18,28 @@
*/
package org.apache.fineract.portfolio.note.data;
+import io.swagger.v3.oas.annotations.Hidden;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import org.apache.fineract.portfolio.note.domain.NoteType;
+@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class NoteRequest implements Serializable {
+public class NoteDeleteRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
- private String note;
+ @Hidden
+ private Long id;
+ @Hidden
+ private Long resourceId;
+ @Hidden
+ private NoteType type;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteDeleteResponse.java
similarity index 90%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
copy to
fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteDeleteResponse.java
index 05a1082086..cfae896ab0 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteDeleteResponse.java
@@ -21,16 +21,18 @@ package org.apache.fineract.portfolio.note.data;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class NoteRequest implements Serializable {
+public class NoteDeleteResponse implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
- private String note;
+ private Long resourceId;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteUpdateRequest.java
similarity index 67%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
copy to
fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteUpdateRequest.java
index 05a1082086..bca0cec30f 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteUpdateRequest.java
@@ -18,19 +18,33 @@
*/
package org.apache.fineract.portfolio.note.data;
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
import java.io.Serial;
import java.io.Serializable;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import org.apache.fineract.portfolio.note.domain.NoteType;
+@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class NoteRequest implements Serializable {
+public class NoteUpdateRequest implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
+ @Hidden
+ private Long id;
+ @Hidden
+ private Long resourceId;
+ @Hidden
+ private NoteType type;
+ @Size(max = 1000, message =
"{org.apache.fineract.portfolio.note.note.size}")
+ @NotNull(message = "{org.apache.fineract.portfolio.note.note.not-null}")
private String note;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteUpdateResponse.java
similarity index 84%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
rename to
fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteUpdateResponse.java
index 05a1082086..5ddf70056b 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/data/NoteRequest.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/data/NoteUpdateResponse.java
@@ -20,17 +20,22 @@ package org.apache.fineract.portfolio.note.data;
import java.io.Serial;
import java.io.Serializable;
+import java.util.Map;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
-public class NoteRequest implements Serializable {
+public class NoteUpdateResponse implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
- private String note;
+ private Long officeId;
+ private Long resourceId;
+ private Map<String, Object> changes;
}
diff --git
a/fineract-core/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformService.java
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformService.java
index 1d8afbd1f4..6db5a9fc62 100644
---
a/fineract-core/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformService.java
+++
b/fineract-core/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformService.java
@@ -18,19 +18,18 @@
*/
package org.apache.fineract.portfolio.note.service;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import org.apache.fineract.portfolio.client.domain.Client;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
+import org.apache.fineract.portfolio.note.data.NoteDeleteRequest;
+import org.apache.fineract.portfolio.note.data.NoteDeleteResponse;
+import org.apache.fineract.portfolio.note.data.NoteUpdateRequest;
+import org.apache.fineract.portfolio.note.data.NoteUpdateResponse;
public interface NoteWritePlatformService {
- CommandProcessingResult createNote(JsonCommand command);
+ NoteCreateResponse createNote(NoteCreateRequest request);
- void createLoanTransactionNote(Long loanTransactionId, String note);
+ NoteUpdateResponse updateNote(NoteUpdateRequest request);
- CommandProcessingResult updateNote(JsonCommand command);
-
- CommandProcessingResult deleteNote(JsonCommand command);
-
- void createAndPersistClientNote(Client client, JsonCommand command);
+ NoteDeleteResponse deleteNote(NoteDeleteRequest request);
}
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
index 213265bd0b..414c6e2ec2 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/BuyDownFeeWritePlatformServiceImpl.java
@@ -49,9 +49,11 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import
org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeeBalanceRepository;
-import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.domain.NoteType;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import
org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@@ -63,11 +65,11 @@ public class BuyDownFeeWritePlatformServiceImpl implements
BuyDownFeePlatformSer
private final LoanTransactionRepository loanTransactionRepository;
private final PaymentDetailWritePlatformService
paymentDetailWritePlatformService;
private final LoanJournalEntryPoster loanJournalEntryPoster;
- private final NoteWritePlatformService noteWritePlatformService;
private final ExternalIdFactory externalIdFactory;
private final LoanBuyDownFeeBalanceRepository
loanBuyDownFeeBalanceRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final CodeValueRepository codeValueRepository;
+ private final ApplicationEventPublisher eventPublisher;
@Transactional
@Override
@@ -108,7 +110,8 @@ public class BuyDownFeeWritePlatformServiceImpl implements
BuyDownFeePlatformSer
// Add note if provided
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
-
noteWritePlatformService.createLoanTransactionNote(buyDownFeeTransaction.getId(),
noteText);
+
eventPublisher.publishEvent(NoteCreateRequest.builder().type(NoteType.LOAN_TRANSACTION)
+
.resourceId(buyDownFeeTransaction.getId()).note(noteText).build());
}
loanJournalEntryPoster.postJournalEntriesForLoanTransaction(buyDownFeeTransaction,
false, false);
@@ -177,7 +180,8 @@ public class BuyDownFeeWritePlatformServiceImpl implements
BuyDownFeePlatformSer
// Create a note if provided
final String noteText = command.stringValueOfParameterNamed("note");
if (StringUtils.isNotBlank(noteText)) {
-
noteWritePlatformService.createLoanTransactionNote(savedBuyDownFeeAdjustment.getId(),
noteText);
+
eventPublisher.publishEvent(NoteCreateRequest.builder().type(NoteType.LOAN_TRANSACTION)
+
.resourceId(savedBuyDownFeeAdjustment.getId()).note(noteText).build());
}
loanJournalEntryPoster.postJournalEntriesForLoanTransaction(savedBuyDownFeeAdjustment,
false, false);
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
index 896c54c6df..2c804898ca 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/CapitalizedIncomeWritePlatformServiceImpl.java
@@ -48,9 +48,11 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import
org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
-import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.domain.NoteType;
import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail;
import
org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@@ -62,7 +64,6 @@ public class CapitalizedIncomeWritePlatformServiceImpl
implements CapitalizedInc
private final LoanTransactionRepository loanTransactionRepository;
private final PaymentDetailWritePlatformService
paymentDetailWritePlatformService;
private final LoanJournalEntryPoster journalEntryPoster;
- private final NoteWritePlatformService noteWritePlatformService;
private final ExternalIdFactory externalIdFactory;
private final LoanCapitalizedIncomeBalanceRepository
capitalizedIncomeBalanceRepository;
private final ReprocessLoanTransactionsService
reprocessLoanTransactionsService;
@@ -71,6 +72,7 @@ public class CapitalizedIncomeWritePlatformServiceImpl
implements CapitalizedInc
private final BusinessEventNotifierService businessEventNotifierService;
private final CodeValueRepository codeValueRepository;
private final LoanScheduleService loanScheduleService;
+ private final ApplicationEventPublisher eventPublisher;
@Transactional
@Override
@@ -107,7 +109,8 @@ public class CapitalizedIncomeWritePlatformServiceImpl
implements CapitalizedInc
// Create a note if provided
final String noteText = command.stringValueOfParameterNamed("note");
if (noteText != null && !noteText.isEmpty()) {
-
noteWritePlatformService.createLoanTransactionNote(capitalizedIncomeTransaction.getId(),
noteText);
+
eventPublisher.publishEvent(NoteCreateRequest.builder().type(NoteType.LOAN_TRANSACTION)
+
.resourceId(capitalizedIncomeTransaction.getId()).note(noteText).build());
}
// Create journal entries immediately for this transaction
@@ -156,7 +159,8 @@ public class CapitalizedIncomeWritePlatformServiceImpl
implements CapitalizedInc
// Create a note if provided
final String noteText = command.stringValueOfParameterNamed("note");
if (noteText != null && !noteText.isEmpty()) {
-
noteWritePlatformService.createLoanTransactionNote(savedCapitalizedIncomeAdjustment.getId(),
noteText);
+
eventPublisher.publishEvent(NoteCreateRequest.builder().type(NoteType.LOAN_TRANSACTION)
+
.resourceId(savedCapitalizedIncomeAdjustment.getId()).note(noteText).build());
}
// Create journal entries immediately for this transaction
journalEntryPoster.postJournalEntriesForLoanTransaction(savedCapitalizedIncomeAdjustment,
false, false);
diff --git
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
index 6b7a543b0d..936e0f8e1e 100644
---
a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
+++
b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/ProgressiveLoanAccountConfiguration.java
@@ -42,9 +42,9 @@ import
org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
import
org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanTransactionValidator;
import
org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanTransactionValidatorImpl;
import
org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
-import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
import
org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -56,15 +56,14 @@ public class ProgressiveLoanAccountConfiguration {
public CapitalizedIncomePlatformService
capitalizedIncomePlatformService(ProgressiveLoanTransactionValidator
loanTransactionValidator,
LoanAssembler loanAssembler, LoanTransactionRepository
loanTransactionRepository,
PaymentDetailWritePlatformService
paymentDetailWritePlatformService, LoanJournalEntryPoster journalEntryPoster,
- NoteWritePlatformService noteWritePlatformService,
ExternalIdFactory externalIdFactory,
- LoanCapitalizedIncomeBalanceRepository
capitalizedIncomeBalanceRepository,
+ ExternalIdFactory externalIdFactory,
LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository,
ReprocessLoanTransactionsService reprocessLoanTransactionsService,
LoanBalanceService loanBalanceService,
LoanLifecycleStateMachine loanLifecycleStateMachine,
BusinessEventNotifierService businessEventNotifierService,
- CodeValueRepository codeValueRepository, LoanScheduleService
loanScheduleService) {
+ CodeValueRepository codeValueRepository, LoanScheduleService
loanScheduleService, ApplicationEventPublisher eventPublisher) {
return new
CapitalizedIncomeWritePlatformServiceImpl(loanTransactionValidator,
loanAssembler, loanTransactionRepository,
- paymentDetailWritePlatformService, journalEntryPoster,
noteWritePlatformService, externalIdFactory,
- capitalizedIncomeBalanceRepository,
reprocessLoanTransactionsService, loanBalanceService, loanLifecycleStateMachine,
- businessEventNotifierService, codeValueRepository,
loanScheduleService);
+ paymentDetailWritePlatformService, journalEntryPoster,
externalIdFactory, capitalizedIncomeBalanceRepository,
+ reprocessLoanTransactionsService, loanBalanceService,
loanLifecycleStateMachine, businessEventNotifierService,
+ codeValueRepository, loanScheduleService, eventPublisher);
}
@Bean
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
index c8849f0039..438923e6f4 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
@@ -157,6 +157,50 @@ public class SecurityConfig {
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ,
"READ_CURRENCY")
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/currencies"))
.hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"UPDATE_CURRENCY")
+ // notes: read
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.GET,
"/api/*/clients/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ,
"READ_CLIENTNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.GET,
"/api/*/loans/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ,
"READ_LOANNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.GET,
"/api/*/loanTransactions/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ,
"READ_LOANTRANSACTIONNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.GET,
"/api/*/savings/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ,
"READ_SAVINGNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.GET,
"/api/*/groups/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ,
"READ_GROUPNOTE")
+ // notes: create
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/clients/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"CREATE_CLIENTNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/loans/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"CREATE_LOANNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/loanTransactions/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"CREATE_LOANTRANSACTIONNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/savings/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"CREATE_SAVINGNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/groups/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"CREATE_GROUPNOTE")
+ // notes: update
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT,
"/api/*/clients/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"UPDATE_CLIENTNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT,
"/api/*/loans/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"UPDATE_LOANNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT,
"/api/*/loanTransactions/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"UPDATE_LOANTRANSACTIONNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT,
"/api/*/savings/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"UPDATE_SAVINGNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT,
"/api/*/groups/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"UPDATE_GROUPNOTE")
+ // notes: delete
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE,
"/api/*/clients/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"DELETE_CLIENTNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE,
"/api/*/loans/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"DELETE_LOANNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE,
"/api/*/loanTransactions/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"DELETE_LOANTRANSACTIONNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE,
"/api/*/savings/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"DELETE_SAVINGNOTE")
+ .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE,
"/api/*/groups/*/notes"))
+ .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE,
"DELETE_GROUPNOTE")
.requestMatchers(API_MATCHER.matcher(HttpMethod.POST,
"/api/*/twofactor/validate")).fullyAuthenticated()
.requestMatchers(API_MATCHER.matcher("/api/*/twofactor")).fullyAuthenticated()
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
index 5a0e5f0139..3db3920349 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java
@@ -175,7 +175,6 @@ import
org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
import
org.apache.fineract.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
import
org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
-import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
import
org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService;
import
org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService;
import org.apache.fineract.portfolio.rate.service.RateAssembler;
@@ -184,6 +183,7 @@ import
org.apache.fineract.portfolio.repaymentwithpostdatedchecks.service.Repaym
import
org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
import org.apache.fineract.portfolio.savings.service.GSIMReadPlatformService;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@@ -397,12 +397,12 @@ public class LoanAccountConfiguration {
public BuyDownFeePlatformService
buyDownFeePlatformService(ProgressiveLoanTransactionValidator
loanTransactionValidator,
LoanAssembler loanAssembler, LoanTransactionRepository
loanTransactionRepository,
PaymentDetailWritePlatformService
paymentDetailWritePlatformService, LoanJournalEntryPoster
loanJournalEntryPoster,
- NoteWritePlatformService noteWritePlatformService,
ExternalIdFactory externalIdFactory,
- LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository,
BusinessEventNotifierService businessEventNotifierService,
- CodeValueRepository codeValueRepository) {
+ ExternalIdFactory externalIdFactory,
LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository,
+ BusinessEventNotifierService businessEventNotifierService,
CodeValueRepository codeValueRepository,
+ ApplicationEventPublisher eventPublisher) {
return new
BuyDownFeeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler,
loanTransactionRepository,
- paymentDetailWritePlatformService, loanJournalEntryPoster,
noteWritePlatformService, externalIdFactory,
- loanBuyDownFeeBalanceRepository, businessEventNotifierService,
codeValueRepository);
+ paymentDetailWritePlatformService, loanJournalEntryPoster,
externalIdFactory, loanBuyDownFeeBalanceRepository,
+ businessEventNotifierService, codeValueRepository,
eventPublisher);
}
@Bean
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResource.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResource.java
index 849997c0c9..f18db73c58 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResource.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResource.java
@@ -19,13 +19,8 @@
package org.apache.fineract.portfolio.note.api;
import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.Parameter;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.parameters.RequestBody;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
@@ -35,201 +30,160 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
-import java.util.Arrays;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
+import java.util.function.Supplier;
import lombok.RequiredArgsConstructor;
-import org.apache.fineract.commands.domain.CommandWrapper;
-import org.apache.fineract.commands.service.CommandWrapperBuilder;
-import
org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
-import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import
org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
-import
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.command.core.CommandPipeline;
+import org.apache.fineract.portfolio.note.command.NoteCreateCommand;
+import org.apache.fineract.portfolio.note.command.NoteDeleteCommand;
+import org.apache.fineract.portfolio.note.command.NoteUpdateCommand;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
import org.apache.fineract.portfolio.note.data.NoteData;
-import org.apache.fineract.portfolio.note.data.NoteRequest;
+import org.apache.fineract.portfolio.note.data.NoteDeleteRequest;
+import org.apache.fineract.portfolio.note.data.NoteDeleteResponse;
+import org.apache.fineract.portfolio.note.data.NoteUpdateRequest;
+import org.apache.fineract.portfolio.note.data.NoteUpdateResponse;
import org.apache.fineract.portfolio.note.domain.NoteType;
import
org.apache.fineract.portfolio.note.exception.NoteResourceNotSupportedException;
import org.apache.fineract.portfolio.note.service.NoteReadPlatformService;
import org.springframework.stereotype.Component;
@Path("/v1/{resourceType}/{resourceId}/notes")
+@Consumes({ MediaType.APPLICATION_JSON })
+@Produces({ MediaType.APPLICATION_JSON })
@Component
-@Tag(name = "Notes", description = "Notes API allows to enter notes for
supported resources.")
+@Tag(name = "Notes", description = """
+ Notes API allows to enter notes for supported resources.
+ """)
@RequiredArgsConstructor
public class NotesApiResource {
- public static final String CLIENTNOTE = "CLIENTNOTE";
- public static final String LOANNOTE = "LOANNOTE";
- public static final String LOANTRANSACTIONNOTE = "LOANTRANSACTIONNOTE";
- public static final String SAVINGNOTE = "SAVINGNOTE";
- public static final String GROUPNOTE = "GROUPNOTE";
- public static final String INVALIDNOTE = "INVALIDNOTE";
- private static final Set<String> NOTE_DATA_PARAMETERS = new HashSet<>(
- Arrays.asList("id", "resourceId", "clientId", "groupId", "loanId",
"loanTransactionId", "depositAccountId", "savingAccountId",
- "noteType", "note", "createdById", "createdByUsername",
"createdOn", "updatedById", "updatedByUsername", "updatedOn"));
- private final PlatformSecurityContext context;
private final NoteReadPlatformService readPlatformService;
- private final DefaultToApiJsonSerializer<NoteData> toApiJsonSerializer;
- private final ApiRequestParameterHelper apiRequestParameterHelper;
- private final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService;
+ private final CommandPipeline commandPipeline;
@GET
- @Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Retrieve a Resource's description", description =
"Retrieves a Resource's Notes\n\n"
- + "Note: Notes are returned in descending createOn order.\n" +
"\n" + "Example Requests:\n" + "\n" + "clients/2/notes\n" + "\n"
- + "\n" + "groups/2/notes?fields=note,createdOn,createdByUsername")
- public List<NoteData> retrieveNotesByResource(
- @PathParam("resourceType") @Parameter(description =
"resourceType") final String resourceType,
- @PathParam("resourceId") @Parameter(description = "resourceId")
final Long resourceId) {
+ @Operation(summary = "Retrieve a Resource's description", description = """
+ Retrieves a resource's notes
- final NoteType noteType = NoteType.fromApiUrl(resourceType);
+ Note: results are returned in descending createOn order.
+
+ Example Requests:
+
+ - clients/2/notes
+ - groups/2/notes?fields=note,createdOn,createdByUsername
+ """)
+ public List<NoteData> retrieveNotesByResource(@PathParam("resourceType")
final String resourceType,
+ @PathParam("resourceId") final Long resourceId) {
+ final var noteType = NoteType.fromApiUrl(resourceType);
if (noteType == null) {
throw new NoteResourceNotSupportedException(resourceType);
}
-
this.context.authenticatedUser().validateHasReadPermission(getResourceDetails(noteType,
resourceId).entityName());
-
- final Integer noteTypeId = noteType.getValue();
-
- return readPlatformService.retrieveNotesByResource(resourceId,
noteTypeId);
+ return readPlatformService.retrieveNotesByResource(resourceId,
noteType.getValue());
}
@GET
@Path("{noteId}")
- @Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Retrieve a Resource Note", description = "Retrieves
a Resource Note\n\n" + "Example Requests:\n" + "\n"
- + "clients/1/notes/76\n" + "\n" + "\n" + "groups/1/notes/20\n" +
"\n" + "\n"
- + "clients/1/notes/76?fields=note,createdOn,createdByUsername\n" +
"\n" + "\n"
- + "groups/1/notes/20?fields=note,createdOn,createdByUsername")
- public NoteData retrieveNote(@PathParam("resourceType")
@Parameter(description = "resourceType") final String resourceType,
- @PathParam("resourceId") @Parameter(description = "resourceId")
final Long resourceId,
- @PathParam("noteId") @Parameter(description = "noteId") final Long
noteId) {
-
+ @Operation(summary = "Retrieve a Resource Note", description = """
+ Retrieves a resource Note
+
+ Example Requests:
+
+ - clients/1/notes/76
+ - groups/1/notes/20
+ - clients/1/notes/76?fields=note,createdOn,createdByUsername
+ - groups/1/notes/20?fields=note,createdOn,createdByUsername
+ """)
+ public NoteData retrieveNote(@PathParam("resourceType") final String
resourceType, @PathParam("resourceId") final Long resourceId,
+ @PathParam("noteId") final Long noteId) {
final NoteType noteType = NoteType.fromApiUrl(resourceType);
if (noteType == null) {
throw new NoteResourceNotSupportedException(resourceType);
}
-
this.context.authenticatedUser().validateHasReadPermission(getResourceDetails(noteType,
resourceId).entityName());
-
- final Integer noteTypeId = noteType.getValue();
-
- final NoteData note = this.readPlatformService.retrieveNote(noteId,
resourceId, noteTypeId);
- return note;
+ return readPlatformService.retrieveNote(noteId, resourceId,
noteType.getValue());
}
@POST
- @Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Add a Resource Note", description = "Adds a new note
to a supported resource.\n\n" + "Example Requests:\n" + "\n"
- + "clients/1/notes\n" + "\n" + "\n" + "groups/1/notes")
- @RequestBody(required = true, content = @Content(schema =
@Schema(implementation = NoteRequest.class)))
- @ApiResponses({
- @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
NotesApiResourceSwagger.PostResourceTypeResourceIdNotesResponse.class))) })
- public CommandProcessingResult addNewNote(@PathParam("resourceType")
@Parameter(description = "resourceType") final String resourceType,
- @PathParam("resourceId") @Parameter(description = "resourceId")
final Long resourceId,
- @Parameter(hidden = true) final NoteRequest noteRequest) {
+ @Operation(summary = "Add a Resource Note", description = """
+ Adds a new note to a supported resource.
- final NoteType noteType = NoteType.fromApiUrl(resourceType);
+ Example Requests:
- if (noteType == null) {
+ - clients/1/notes
+ - groups/1/notes
+ """)
+ public NoteCreateResponse addNewNote(@PathParam("resourceType") final
String resourceType,
+ @PathParam("resourceId") final Long resourceId, @Valid final
NoteCreateRequest request) {
+ final var type = NoteType.fromApiUrl(resourceType);
+
+ if (type == null) {
throw new NoteResourceNotSupportedException(resourceType);
}
- final CommandWrapper resourceDetails = getResourceDetails(noteType,
resourceId);
- final CommandWrapper commandRequest = new
CommandWrapperBuilder().createNote(resourceDetails, resourceType, resourceId)
- .withJson(toApiJsonSerializer.serialize(noteRequest)).build();
+ request.setResourceId(resourceId);
+ request.setType(type);
+
+ final var command = new NoteCreateCommand();
+
+ command.setPayload(request);
+
+ final Supplier<NoteCreateResponse> response =
commandPipeline.send(command);
- return
commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ return response.get();
}
@PUT
@Path("{noteId}")
- @Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Update a Resource Note", description = "Updates a
Resource Note")
- @RequestBody(required = true, content = @Content(schema =
@Schema(implementation = NoteRequest.class)))
- @ApiResponses({
- @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
NotesApiResourceSwagger.PutResourceTypeResourceIdNotesNoteIdResponse.class))) })
- public CommandProcessingResult updateNote(@PathParam("resourceType")
@Parameter(description = "resourceType") final String resourceType,
- @PathParam("resourceId") @Parameter(description = "resourceId")
final Long resourceId,
- @PathParam("noteId") @Parameter(description = "noteId") final Long
noteId,
- @Parameter(hidden = true) final NoteRequest noteRequest) {
-
- final NoteType noteType = NoteType.fromApiUrl(resourceType);
-
- if (noteType == null) {
+ @Operation(summary = "Update a Resource Note", description = """
+ Updates a Resource Note
+ """)
+ public NoteUpdateResponse updateNote(@PathParam("resourceType") final
String resourceType,
+ @PathParam("resourceId") final Long resourceId,
@PathParam("noteId") final Long noteId,
+ @Valid final NoteUpdateRequest request) {
+ final var type = NoteType.fromApiUrl(resourceType);
+
+ if (type == null) {
throw new NoteResourceNotSupportedException(resourceType);
}
- final CommandWrapper resourceDetails = getResourceDetails(noteType,
resourceId);
+ request.setId(noteId);
+ request.setResourceId(resourceId);
+ request.setType(type);
- final CommandWrapper commandRequest = new
CommandWrapperBuilder().updateNote(resourceDetails, resourceType, resourceId,
noteId)
- .withJson(toApiJsonSerializer.serialize(noteRequest)).build();
+ final var command = new NoteUpdateCommand();
- return
commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ command.setPayload(request);
+
+ final Supplier<NoteUpdateResponse> response =
commandPipeline.send(command);
+
+ return response.get();
}
@DELETE
@Path("{noteId}")
- @Consumes({ MediaType.APPLICATION_JSON })
- @Produces({ MediaType.APPLICATION_JSON })
- @Operation(summary = "Delete a Resource Note", description = "Deletes a
Resource Note")
- @ApiResponses({
- @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
NotesApiResourceSwagger.DeleteResourceTypeResourceIdNotesNoteIdResponse.class)))
})
- public CommandProcessingResult deleteNote(@PathParam("resourceType")
@Parameter(description = "resourceType") final String resourceType,
- @PathParam("resourceId") @Parameter(description = "resourceId")
final Long resourceId,
- @PathParam("noteId") @Parameter(description = "noteId") final Long
noteId) {
-
- final NoteType noteType = NoteType.fromApiUrl(resourceType);
-
- if (noteType == null) {
+ @Operation(summary = "Delete a Resource Note", description = """
+ Deletes a Resource Note
+ """)
+ public NoteDeleteResponse deleteNote(@PathParam("resourceType") final
String resourceType,
+ @PathParam("resourceId") final Long resourceId,
@PathParam("noteId") final Long noteId) {
+ final var type = NoteType.fromApiUrl(resourceType);
+
+ if (type == null) {
throw new NoteResourceNotSupportedException(resourceType);
}
- final CommandWrapper resourceDetails = getResourceDetails(noteType,
resourceId);
+ var request =
NoteDeleteRequest.builder().id(noteId).resourceId(resourceId).type(type).build();
- final CommandWrapper commandRequest = new
CommandWrapperBuilder().deleteNote(resourceDetails, resourceType, resourceId,
noteId)
- .build();
+ final var command = new NoteDeleteCommand();
- return
commandsSourceWritePlatformService.logCommandSource(commandRequest);
- }
+ command.setPayload(request);
- private CommandWrapper getResourceDetails(final NoteType type, final Long
resourceId) {
- CommandWrapperBuilder resourceDetails = new CommandWrapperBuilder();
- String resourceNameForPermissions;
- switch (type) {
- case CLIENT -> {
- resourceNameForPermissions = CLIENTNOTE;
- resourceDetails.withClientId(resourceId);
- }
- case LOAN -> {
- resourceNameForPermissions = LOANNOTE;
- resourceDetails.withLoanId(resourceId);
- }
- case LOAN_TRANSACTION -> {
- resourceNameForPermissions = LOANTRANSACTIONNOTE;
- // updating loanId, to distinguish saving transaction note and
- // loan transaction note as we are using subEntityId for both.
- resourceDetails.withLoanId(resourceId);
- resourceDetails.withSubEntityId(resourceId);
- }
- case SAVING_ACCOUNT -> {
- resourceNameForPermissions = SAVINGNOTE;
- resourceDetails.withSavingsId(resourceId);
- }
- case GROUP -> {
- resourceNameForPermissions = GROUPNOTE;
- resourceDetails.withGroupId(resourceId);
- }
- default -> resourceNameForPermissions = INVALIDNOTE;
- }
- return
resourceDetails.withEntityName(resourceNameForPermissions).build();
+ final Supplier<NoteDeleteResponse> response =
commandPipeline.send(command);
+
+ return response.get();
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResourceSwagger.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResourceSwagger.java
deleted file mode 100644
index e53cd454f8..0000000000
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/api/NotesApiResourceSwagger.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.note.api;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-
-/**
- * Created by Chirag Gupta on 12/29/17.
- */
-public final class NotesApiResourceSwagger {
-
- private NotesApiResourceSwagger() {}
-
- @Schema(description = "PostResourceTypeResourceIdNotesRequest")
- public static final class PostResourceTypeResourceIdNotesRequest {
-
- private PostResourceTypeResourceIdNotesRequest() {}
-
- @Schema(example = "a note about the client")
- public String note;
- }
-
- @Schema(description = "PostResourceTypeResourceIdNotesResponse")
- public static final class PostResourceTypeResourceIdNotesResponse {
-
- private PostResourceTypeResourceIdNotesResponse() {}
-
- @Schema(example = "1")
- public Long officeId;
- @Schema(example = "1")
- public Long clientId;
- @Schema(example = "76")
- public Long resourceId;
- }
-
- @Schema(description = "PutResourceTypeResourceIdNotesNoteIdResponse")
- public static final class PutResourceTypeResourceIdNotesNoteIdResponse {
-
- private PutResourceTypeResourceIdNotesNoteIdResponse() {}
-
- static final class PutNotesChanges {
-
- private PutNotesChanges() {}
-
- @Schema(example = "a note about the client")
- public String note;
- }
-
- @Schema(example = "1")
- public Long officeId;
- @Schema(example = "1")
- public Long clientId;
- @Schema(example = "76")
- public Long resourceId;
- public PutNotesChanges changes;
- }
-
- @Schema(description = "DeleteResourceTypeResourceIdNotesNoteIdResponse")
- public static final class DeleteResourceTypeResourceIdNotesNoteIdResponse {
-
- private DeleteResourceTypeResourceIdNotesNoteIdResponse() {}
-
- @Schema(example = "76")
- public Long resourceId;
- }
-}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCreateCommand.java
similarity index 75%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
copy to
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCreateCommand.java
index 6f2419d11d..2206107914 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCreateCommand.java
@@ -18,16 +18,11 @@
*/
package org.apache.fineract.portfolio.note.command;
-/**
- * Immutable command used for create or update of notes.
- */
-public class NoteCommand {
-
- @SuppressWarnings("unused")
- private final String note;
-
- public NoteCommand(final String note) {
- this.note = note;
- }
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
-}
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class NoteCreateCommand extends Command<NoteCreateRequest> {}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteDeleteCommand.java
similarity index 75%
copy from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
copy to
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteDeleteCommand.java
index 6f2419d11d..ba97ea2f6a 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteDeleteCommand.java
@@ -18,16 +18,11 @@
*/
package org.apache.fineract.portfolio.note.command;
-/**
- * Immutable command used for create or update of notes.
- */
-public class NoteCommand {
-
- @SuppressWarnings("unused")
- private final String note;
-
- public NoteCommand(final String note) {
- this.note = note;
- }
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.portfolio.note.data.NoteDeleteRequest;
-}
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class NoteDeleteCommand extends Command<NoteDeleteRequest> {}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteUpdateCommand.java
similarity index 75%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
rename to
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteUpdateCommand.java
index 6f2419d11d..2671bb2f92 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteCommand.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/command/NoteUpdateCommand.java
@@ -18,16 +18,11 @@
*/
package org.apache.fineract.portfolio.note.command;
-/**
- * Immutable command used for create or update of notes.
- */
-public class NoteCommand {
-
- @SuppressWarnings("unused")
- private final String note;
-
- public NoteCommand(final String note) {
- this.note = note;
- }
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.portfolio.note.data.NoteUpdateRequest;
-}
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class NoteUpdateCommand extends Command<NoteUpdateRequest> {}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
index ecc28837fc..db71517173 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/domain/Note.java
@@ -23,10 +23,9 @@ import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
-import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.commons.lang3.Strings;
import
org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.group.domain.Group;
@@ -74,13 +73,11 @@ public class Note extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
@JoinColumn(name = "share_account_id", nullable = true)
private ShareAccount shareAccount;
- public static Note clientNoteFromJson(final Client client, final
JsonCommand command) {
- final String note = command.stringValueOfParameterNamed("note");
+ public static Note clientNote(final Client client, final String note) {
return new Note(client, note);
}
- public static Note groupNoteFromJson(final Group group, final JsonCommand
command) {
- final String note = command.stringValueOfParameterNamed("note");
+ public static Note groupNote(final Group group, final String note) {
return new Note(group, note);
}
@@ -164,20 +161,12 @@ public class Note extends
AbstractAuditableWithUTCDateTimeCustom<Long> {
this.noteTypeId = NoteType.SHARE_ACCOUNT.getValue();
}
- public Map<String, Object> update(final JsonCommand command) {
- final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
-
- final String noteParamName = "note";
- if (command.isChangeInStringParameterNamed(noteParamName, this.note)) {
- final String newValue =
command.stringValueOfParameterNamed(noteParamName);
- actualChanges.put(noteParamName, newValue);
- this.note = StringUtils.defaultIfEmpty(newValue, null);
+ public Map<String, Object> update(final String note) {
+ if (!Strings.CI.equals(note, this.note)) {
+ this.note = StringUtils.defaultIfEmpty(note, null);
+ return Map.of("note", note);
}
- return actualChanges;
- }
-
- public boolean isNotAgainstClientWithIdOf(final Long clientId) {
- return !this.client.identifiedBy(clientId);
+ return Map.of();
}
public String getNote() {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/DeleteNoteCommandHandler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteCreateCommandHandler.java
similarity index 52%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/DeleteNoteCommandHandler.java
rename to
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteCreateCommandHandler.java
index b6483c928e..d5cd721a9d 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/DeleteNoteCommandHandler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteCreateCommandHandler.java
@@ -18,27 +18,34 @@
*/
package org.apache.fineract.portfolio.note.handler;
-import org.apache.fineract.commands.handler.NewCommandSourceHandler;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import io.github.resilience4j.retry.annotation.Retry;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.command.core.CommandHandler;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
-@Service
-public class DeleteNoteCommandHandler implements NewCommandSourceHandler {
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class NoteCreateCommandHandler implements
CommandHandler<NoteCreateRequest, NoteCreateResponse> {
private final NoteWritePlatformService writePlatformService;
- @Autowired
- public DeleteNoteCommandHandler(final NoteWritePlatformService
writePlatformService) {
- this.writePlatformService = writePlatformService;
+ @Retry(name = "commandNoteCreate", fallbackMethod = "fallback")
+ @Override
+ @Transactional
+ public NoteCreateResponse handle(Command<NoteCreateRequest> command) {
+ return writePlatformService.createNote(command.getPayload());
}
- @Transactional
@Override
- public CommandProcessingResult processCommand(final JsonCommand command) {
- return this.writePlatformService.deleteNote(command);
+ public NoteCreateResponse fallback(Command<NoteCreateRequest> command,
Throwable t) {
+ // NOTE: fallback method needs to be in the same class
+ return CommandHandler.super.fallback(command, t);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/UpdateNoteCommandHandler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteDeleteCommandHandler.java
similarity index 52%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/UpdateNoteCommandHandler.java
rename to
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteDeleteCommandHandler.java
index 69df2a0fd8..7df6ecfb75 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/UpdateNoteCommandHandler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteDeleteCommandHandler.java
@@ -18,29 +18,34 @@
*/
package org.apache.fineract.portfolio.note.handler;
-import org.apache.fineract.commands.handler.NewCommandSourceHandler;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import io.github.resilience4j.retry.annotation.Retry;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.command.core.CommandHandler;
+import org.apache.fineract.portfolio.note.data.NoteDeleteRequest;
+import org.apache.fineract.portfolio.note.data.NoteDeleteResponse;
import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
-@Service
-public class UpdateNoteCommandHandler implements NewCommandSourceHandler {
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class NoteDeleteCommandHandler implements
CommandHandler<NoteDeleteRequest, NoteDeleteResponse> {
private final NoteWritePlatformService writePlatformService;
- @Autowired
- public UpdateNoteCommandHandler(final NoteWritePlatformService
noteWritePlatformService) {
- this.writePlatformService = noteWritePlatformService;
+ @Retry(name = "commandNoteDelete", fallbackMethod = "fallback")
+ @Override
+ @Transactional
+ public NoteDeleteResponse handle(Command<NoteDeleteRequest> command) {
+ return writePlatformService.deleteNote(command.getPayload());
}
- @Transactional
@Override
- public CommandProcessingResult processCommand(final JsonCommand command) {
-
- return this.writePlatformService.updateNote(command);
+ public NoteDeleteResponse fallback(Command<NoteDeleteRequest> command,
Throwable t) {
+ // NOTE: fallback method needs to be in the same class
+ return CommandHandler.super.fallback(command, t);
}
-
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/CreateNoteCommandHandler.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteUpdateCommandHandler.java
similarity index 52%
rename from
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/CreateNoteCommandHandler.java
rename to
fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteUpdateCommandHandler.java
index 351714e564..009f7539b8 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/CreateNoteCommandHandler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/handler/NoteUpdateCommandHandler.java
@@ -18,28 +18,34 @@
*/
package org.apache.fineract.portfolio.note.handler;
-import org.apache.fineract.commands.handler.NewCommandSourceHandler;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import io.github.resilience4j.retry.annotation.Retry;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.command.core.Command;
+import org.apache.fineract.command.core.CommandHandler;
+import org.apache.fineract.portfolio.note.data.NoteUpdateRequest;
+import org.apache.fineract.portfolio.note.data.NoteUpdateResponse;
import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
+import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
-@Service
-public class CreateNoteCommandHandler implements NewCommandSourceHandler {
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class NoteUpdateCommandHandler implements
CommandHandler<NoteUpdateRequest, NoteUpdateResponse> {
private final NoteWritePlatformService writePlatformService;
- @Autowired
- public CreateNoteCommandHandler(final NoteWritePlatformService
writePlatformService) {
- this.writePlatformService = writePlatformService;
+ @Retry(name = "commandNoteUpdate", fallbackMethod = "fallback")
+ @Override
+ @Transactional
+ public NoteUpdateResponse handle(Command<NoteUpdateRequest> command) {
+ return writePlatformService.updateNote(command.getPayload());
}
- @Transactional
@Override
- public CommandProcessingResult processCommand(final JsonCommand command) {
- return this.writePlatformService.createNote(command);
+ public NoteUpdateResponse fallback(Command<NoteUpdateRequest> command,
Throwable t) {
+ // NOTE: fallback method needs to be in the same class
+ return CommandHandler.super.fallback(command, t);
}
-
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/listener/NoteListener.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/listener/NoteListener.java
new file mode 100644
index 0000000000..e3ac4f2eb6
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/listener/NoteListener.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.note.listener;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@RequiredArgsConstructor
+@Component
+class NoteListener {
+
+ private final NoteWritePlatformService noteWritePlatformService;
+
+ @EventListener
+ void onCreate(NoteCreateRequest request) {
+ noteWritePlatformService.createNote(request);
+ }
+
+ @EventListener
+ void onUpdate(NoteCreateRequest request) {
+ noteWritePlatformService.createNote(request);
+ }
+
+ @EventListener
+ void onDelete(NoteCreateRequest request) {
+ noteWritePlatformService.createNote(request);
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/serialization/NoteCommandFromApiJsonDeserializer.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/serialization/NoteCommandFromApiJsonDeserializer.java
deleted file mode 100644
index a2c2b9408c..0000000000
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/serialization/NoteCommandFromApiJsonDeserializer.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.portfolio.note.serialization;
-
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.fineract.infrastructure.core.data.ApiParameterError;
-import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
-import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
-import
org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
-import
org.apache.fineract.infrastructure.core.serialization.AbstractFromApiJsonDeserializer;
-import
org.apache.fineract.infrastructure.core.serialization.FromApiJsonDeserializer;
-import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
-import org.apache.fineract.portfolio.note.command.NoteCommand;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * Implementation of {@link FromApiJsonDeserializer} for {@link NoteCommand}
's.
- */
-@Component
-public final class NoteCommandFromApiJsonDeserializer extends
AbstractFromApiJsonDeserializer<NoteCommand> {
-
- public static final String NOTE = "note";
- /**
- * The parameters supported for this command.
- */
- private static final Set<String> SUPPORTED_PARAMETERS = new
HashSet<>(List.of(NOTE));
-
- private final FromJsonHelper fromApiJsonHelper;
-
- @Autowired
- public NoteCommandFromApiJsonDeserializer(final FromJsonHelper
fromApiJsonHelper) {
- this.fromApiJsonHelper = fromApiJsonHelper;
- }
-
- @Override
- public NoteCommand commandFromApiJson(final String json) {
-
- if (StringUtils.isBlank(json)) {
- throw new InvalidJsonException();
- }
-
- final Type typeOfMap = new TypeToken<Map<String, Object>>() {
-
- }.getType();
- this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
SUPPORTED_PARAMETERS);
-
- final JsonElement element = this.fromApiJsonHelper.parse(json);
- final String note = this.fromApiJsonHelper.extractStringNamed(NOTE,
element);
-
- return new NoteCommand(note);
- }
-
- public void validateNote(final String json) {
- if (StringUtils.isBlank(json)) {
- throw new InvalidJsonException();
- }
-
- final Type typeOfMap = new TypeToken<Map<String, Object>>() {
-
- }.getType();
- this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
SUPPORTED_PARAMETERS);
- final JsonElement element = this.fromApiJsonHelper.parse(json);
-
- final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
-
- final DataValidatorBuilder baseDataValidator = new
DataValidatorBuilder(dataValidationErrors).resource(NOTE);
-
- final String note = this.fromApiJsonHelper.extractStringNamed(NOTE,
element);
-
baseDataValidator.reset().parameter(NOTE).value(note).notBlank().notExceedingLengthOf(1000);
-
- if (!dataValidationErrors.isEmpty()) {
- throw new
PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.",
- dataValidationErrors);
- }
-
- }
-}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
index 44500747ef..62158bc44b 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/service/NoteWritePlatformServiceJpaRepositoryImpl.java
@@ -18,30 +18,26 @@
*/
package org.apache.fineract.portfolio.note.service;
-import java.util.Map;
import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.fineract.infrastructure.core.api.JsonCommand;
-import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
-import
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
-import org.apache.fineract.portfolio.client.domain.Client;
+import org.apache.commons.lang3.Strings;
+import org.apache.commons.lang3.tuple.Pair;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
-import org.apache.fineract.portfolio.client.exception.ClientNotFoundException;
-import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.group.exception.GroupNotFoundException;
-import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
-import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import
org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFoundException;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
+import org.apache.fineract.portfolio.note.data.NoteDeleteRequest;
+import org.apache.fineract.portfolio.note.data.NoteDeleteResponse;
+import org.apache.fineract.portfolio.note.data.NoteUpdateRequest;
+import org.apache.fineract.portfolio.note.data.NoteUpdateResponse;
import org.apache.fineract.portfolio.note.domain.Note;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
import org.apache.fineract.portfolio.note.domain.NoteType;
import org.apache.fineract.portfolio.note.exception.NoteNotFoundException;
import
org.apache.fineract.portfolio.note.exception.NoteResourceNotSupportedException;
-import
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
-import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
import
org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException;
@@ -53,419 +49,135 @@ public class NoteWritePlatformServiceJpaRepositoryImpl
implements NoteWritePlatf
private final GroupRepository groupRepository;
private final LoanRepositoryWrapper loanRepository;
private final LoanTransactionRepository loanTransactionRepository;
- private final NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final SavingsAccountRepository savingsAccountRepository;
public NoteWritePlatformServiceJpaRepositoryImpl(final NoteRepository
noteRepository, final ClientRepositoryWrapper clientRepository,
final GroupRepository groupRepository, final LoanRepositoryWrapper
loanRepository,
- final LoanTransactionRepository loanTransactionRepository, final
NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer,
- final SavingsAccountRepository savingsAccountRepository) {
+ final LoanTransactionRepository loanTransactionRepository, final
SavingsAccountRepository savingsAccountRepository) {
this.noteRepository = noteRepository;
this.clientRepository = clientRepository;
this.groupRepository = groupRepository;
this.loanRepository = loanRepository;
this.loanTransactionRepository = loanTransactionRepository;
- this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.savingsAccountRepository = savingsAccountRepository;
}
- private CommandProcessingResult createClientNote(final JsonCommand
command) {
-
- final Long resourceId = command.getClientId();
-
- final Client client =
this.clientRepository.findOneWithNotFoundDetection(resourceId);
- if (client == null) {
- throw new ClientNotFoundException(resourceId);
- }
- final Note newNote = Note.clientNoteFromJson(client, command);
-
- this.noteRepository.saveAndFlush(newNote);
-
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(newNote.getId()) //
- .withClientId(client.getId()) //
- .withOfficeId(client.officeId()) //
- .build();
-
- }
-
@Override
- public void createAndPersistClientNote(final Client client, final
JsonCommand command) {
- final String noteText = command.stringValueOfParameterNamed("note");
- if (StringUtils.isNotBlank(noteText)) {
- final Note newNote = new Note(client, noteText);
- this.noteRepository.save(newNote);
- }
- }
-
- private CommandProcessingResult createGroupNote(final JsonCommand command)
{
-
- final Long resourceId = command.getGroupId();
-
- final Group group =
this.groupRepository.findById(resourceId).orElseThrow(() -> new
GroupNotFoundException(resourceId));
- final Note newNote = Note.groupNoteFromJson(group, command);
-
- this.noteRepository.saveAndFlush(newNote);
-
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(newNote.getId()) //
- .withGroupId(group.getId()) //
- .withOfficeId(group.officeId()) //
- .build();
- }
-
- private CommandProcessingResult createLoanNote(final JsonCommand command) {
-
- final Long resourceId = command.getLoanId();
-
- final Loan loan =
this.loanRepository.findOneWithNotFoundDetection(resourceId);
- final String note = command.stringValueOfParameterNamed("note");
- final Note newNote = Note.loanNote(loan, note);
-
- this.noteRepository.saveAndFlush(newNote);
-
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(newNote.getId()) //
- .withOfficeId(loan.getOfficeId()) //
- .withLoanId(loan.getId()) //
- .build();
- }
-
- private CommandProcessingResult createLoanTransactionNote(final
JsonCommand command) {
-
- final Long resourceId = command.subentityId();
-
- final LoanTransaction loanTransaction =
this.loanTransactionRepository.findById(resourceId)
- .orElseThrow(() -> new
LoanTransactionNotFoundException(resourceId));
-
- final Loan loan = loanTransaction.getLoan();
-
- final String note = command.stringValueOfParameterNamed("note");
- final Note newNote = Note.loanTransactionNote(loan, loanTransaction,
note);
-
- this.noteRepository.saveAndFlush(newNote);
-
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(newNote.getId()) //
- .withOfficeId(loan.getOfficeId())//
- .withLoanId(loan.getId())// Loan can be associated
- .build();
- }
-
- private CommandProcessingResult createSavingAccountNote(final JsonCommand
command) {
- final Long resourceId = command.getSavingsId();
- final SavingsAccount savingAccount =
this.savingsAccountRepository.findById(resourceId)
- .orElseThrow(() -> new
SavingsAccountNotFoundException(resourceId));
-
- final String note = command.stringValueOfParameterNamed("note");
- final Note newNote = Note.savingNote(savingAccount, note);
-
- this.noteRepository.saveAndFlush(newNote);
+ public NoteCreateResponse createNote(final NoteCreateRequest request) {
+ Note note;
+ Long officeId;
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(newNote.getId()) //
- .withOfficeId(savingAccount.getClient().getOffice().getId()) //
- .withSavingsId(savingAccount.getId()) //
- .build();
- }
-
- @Override
- public CommandProcessingResult createNote(final JsonCommand command) {
-
- this.fromApiJsonDeserializer.validateNote(command.json());
-
- final String resourceUrl = getResourceUrlFromCommand(command); //
command.getSupportedEntityType();
- final NoteType type = NoteType.fromApiUrl(resourceUrl);
- switch (type) {
+ switch (request.getType()) {
case CLIENT: {
- return createClientNote(command);
+ final var client =
this.clientRepository.findOneWithNotFoundDetection(request.getResourceId());
+ note = noteRepository.saveAndFlush(Note.clientNote(client,
request.getNote()));
+ officeId = client.officeId();
}
+ break;
case GROUP: {
- return createGroupNote(command);
+ final var group =
groupRepository.findById(request.getResourceId())
+ .orElseThrow(() -> new
GroupNotFoundException(request.getResourceId()));
+ note = noteRepository.saveAndFlush(Note.groupNote(group,
request.getNote()));
+ officeId = group.officeId();
}
+ break;
case LOAN: {
- return createLoanNote(command);
+ final var loan =
loanRepository.findOneWithNotFoundDetection(request.getResourceId());
+ note = noteRepository.saveAndFlush(Note.loanNote(loan,
request.getNote()));
+ officeId = loan.getOfficeId();
}
+ break;
case LOAN_TRANSACTION: {
- return createLoanTransactionNote(command);
+ final var loanTransaction =
this.loanTransactionRepository.findById(request.getResourceId())
+ .orElseThrow(() -> new
LoanTransactionNotFoundException(request.getResourceId()));
+ note =
noteRepository.saveAndFlush(Note.loanTransactionNote(loanTransaction.getLoan(),
loanTransaction, request.getNote()));
+ officeId = loanTransaction.getLoan().getOfficeId();
}
+ break;
case SAVING_ACCOUNT: {
- return createSavingAccountNote(command);
+ final var savingAccount =
savingsAccountRepository.findById(request.getResourceId())
+ .orElseThrow(() -> new
SavingsAccountNotFoundException(request.getResourceId()));
+ note =
noteRepository.saveAndFlush(Note.savingNote(savingAccount, request.getNote()));
+ officeId = savingAccount.getClient().getOffice().getId();
}
+ break;
default:
- throw new NoteResourceNotSupportedException(resourceUrl);
+ throw new
NoteResourceNotSupportedException(request.getType().getApiUrl());
}
+ return
NoteCreateResponse.builder().entityId(note.getId()).resourceId(note.getId()).officeId(officeId).build();
}
@Override
- public void createLoanTransactionNote(final Long loanTransactionId, final
String note) {
- final LoanTransaction loanTransaction =
this.loanTransactionRepository.findById(loanTransactionId)
- .orElseThrow(() -> new
LoanTransactionNotFoundException(loanTransactionId));
-
- final Loan loan = loanTransaction.getLoan();
-
- final Note newNote = Note.loanTransactionNote(loan, loanTransaction,
note);
-
- this.noteRepository.save(newNote);
- }
-
- private String getResourceUrlFromCommand(JsonCommand command) {
-
- final String resourceUrl;
-
- if (command.getClientId() != null) {
- resourceUrl = NoteType.CLIENT.getApiUrl();
- } else if (command.getGroupId() != null) {
- resourceUrl = NoteType.GROUP.getApiUrl();
- } else if (command.getLoanId() != null) {
- if (command.subentityId() != null) {
- resourceUrl = NoteType.LOAN_TRANSACTION.getApiUrl();
- } else {
- resourceUrl = NoteType.LOAN.getApiUrl();
- }
- } else if (command.getSavingsId() != null) {
- // TODO: SAVING_TRANSACTION type need to be add.
- resourceUrl = NoteType.SAVING_ACCOUNT.getApiUrl();
- } else {
- resourceUrl = "";
- }
-
- return resourceUrl;
- }
-
- private CommandProcessingResult updateClientNote(final JsonCommand
command) {
-
- final Long resourceId = command.getClientId();
- final Long noteId = command.entityId();
-
- final NoteType type = NoteType.CLIENT;
-
- final Client client =
this.clientRepository.findOneWithNotFoundDetection(resourceId);
-
- final Note noteForUpdate =
this.noteRepository.findByClientAndId(client, noteId);
- if (noteForUpdate == null) {
- throw new NoteNotFoundException(noteId, resourceId,
type.name().toLowerCase());
- }
-
- final Map<String, Object> changes = noteForUpdate.update(command);
-
- if (!changes.isEmpty()) {
- this.noteRepository.saveAndFlush(noteForUpdate);
- }
+ public NoteUpdateResponse updateNote(final NoteUpdateRequest request) {
+ final var result = getNote(request.getType(), request.getResourceId(),
request.getId());
+ final var note = result.getLeft();
+ final var response =
NoteUpdateResponse.builder().officeId(result.getRight()).resourceId(request.getResourceId());
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(noteForUpdate.getId()) //
- .withClientId(client.getId()) //
- .withOfficeId(client.officeId()) //
- .with(changes) //
- .build();
- }
-
- private CommandProcessingResult updateGroupNote(final JsonCommand command)
{
-
- final Long resourceId = command.getGroupId();
- final Long noteId = command.entityId();
-
- final NoteType type = NoteType.GROUP;
-
- final Group group =
this.groupRepository.findById(resourceId).orElseThrow(() -> new
GroupNotFoundException(resourceId));
-
- final Note noteForUpdate = this.noteRepository.findByGroupAndId(group,
noteId);
-
- if (noteForUpdate == null) {
- throw new NoteNotFoundException(noteId, resourceId,
type.name().toLowerCase());
+ if (!Strings.CI.equals(note.getNote(), request.getNote())) {
+ response.changes(note.update(request.getNote()));
+ noteRepository.saveAndFlush(note);
}
- final Map<String, Object> changes = noteForUpdate.update(command);
-
- if (!changes.isEmpty()) {
- this.noteRepository.saveAndFlush(noteForUpdate);
- }
-
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(noteForUpdate.getId()) //
- .withGroupId(group.getId()) //
- .withOfficeId(group.officeId()) //
- .with(changes).build();
- }
-
- private CommandProcessingResult updateLoanNote(final JsonCommand command) {
-
- final Long resourceId = command.getLoanId();
- final Long noteId = command.entityId();
-
- final NoteType type = NoteType.LOAN;
-
- final Loan loan =
this.loanRepository.findOneWithNotFoundDetection(resourceId);
- final Note noteForUpdate = this.noteRepository.findByLoanAndId(loan,
noteId);
- if (noteForUpdate == null) {
- throw new NoteNotFoundException(noteId, resourceId,
type.name().toLowerCase());
- }
-
- final Map<String, Object> changes = noteForUpdate.update(command);
-
- if (!changes.isEmpty()) {
- this.noteRepository.saveAndFlush(noteForUpdate);
- }
-
- return new
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(noteForUpdate.getId())
-
.withLoanId(loan.getId()).withOfficeId(loan.getOfficeId()).with(changes).build();
- }
-
- private CommandProcessingResult updateLoanTransactionNote(final
JsonCommand command) {
-
- final Long resourceId = command.subentityId();
- final Long noteId = command.entityId();
-
- final NoteType type = NoteType.LOAN_TRANSACTION;
-
- final LoanTransaction loanTransaction =
this.loanTransactionRepository.findById(resourceId)
- .orElseThrow(() -> new
LoanTransactionNotFoundException(resourceId));
- final Loan loan = loanTransaction.getLoan();
-
- final Note noteForUpdate =
this.noteRepository.findByLoanTransactionAndId(loanTransaction, noteId);
-
- if (noteForUpdate == null) {
- throw new NoteNotFoundException(noteId, resourceId,
type.name().toLowerCase());
- }
-
- final Map<String, Object> changes = noteForUpdate.update(command);
-
- if (!changes.isEmpty()) {
- this.noteRepository.saveAndFlush(noteForUpdate);
- }
-
- return new
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(noteForUpdate.getId())
-
.withLoanId(loan.getId()).withOfficeId(loan.getOfficeId()).with(changes).build();
- }
-
- private CommandProcessingResult updateSavingAccountNote(final JsonCommand
command) {
- final Long resourceId = command.getSavingsId();
- final Long noteId = command.entityId();
- final NoteType type = NoteType.SAVING_ACCOUNT;
- final SavingsAccount savingAccount =
this.savingsAccountRepository.findById(resourceId)
- .orElseThrow(() -> new
SavingsAccountNotFoundException(resourceId));
-
- final Note noteForUpdate =
this.noteRepository.findBySavingsAccountAndId(savingAccount, noteId);
- if (noteForUpdate == null) {
- throw new NoteNotFoundException(noteId, resourceId,
type.name().toLowerCase());
- }
- final Map<String, Object> changes = noteForUpdate.update(command);
- if (!changes.isEmpty()) {
- this.noteRepository.saveAndFlush(noteForUpdate);
- }
-
- return new CommandProcessingResultBuilder() //
- .withCommandId(command.commandId()) //
- .withEntityId(noteForUpdate.getId()) //
- .withOfficeId(savingAccount.getClient().getOffice().getId()) //
- .withSavingsId(savingAccount.getId()) //
- .with(changes) //
- .build();
+ return response.build();
}
@Override
- public CommandProcessingResult updateNote(final JsonCommand command) {
-
- this.fromApiJsonDeserializer.validateNote(command.json());
+ public NoteDeleteResponse deleteNote(final NoteDeleteRequest request) {
+ var note = getNote(request.getType(), request.getResourceId(),
request.getId());
- final String resourceUrl = getResourceUrlFromCommand(command); //
command.getSupportedEntityType();
- final NoteType type = NoteType.fromApiUrl(resourceUrl);
+ noteRepository.delete(note.getLeft());
- switch (type) {
- case CLIENT: {
- return updateClientNote(command);
- }
- case GROUP: {
- return updateGroupNote(command);
- }
- case LOAN: {
- return updateLoanNote(command);
- }
- case LOAN_TRANSACTION: {
- return updateLoanTransactionNote(command);
- }
- case SAVING_ACCOUNT: {
- return updateSavingAccountNote(command);
- }
- default:
- throw new NoteResourceNotSupportedException(resourceUrl);
- }
+ return
NoteDeleteResponse.builder().resourceId(request.getId()).build();
}
- @Override
- public CommandProcessingResult deleteNote(final JsonCommand command) {
-
- final Note noteForDelete = getNoteForDelete(command);
-
- this.noteRepository.delete(noteForDelete);
- return new CommandProcessingResultBuilder() //
- .withCommandId(null) //
- .withEntityId(command.entityId()) //
- .build();
- }
+ private Pair<Note, Long> getNote(NoteType type, Long resourceId, Long
noteId) {
+ Note note = null;
+ Long officeId = null;
- private Note getNoteForDelete(final JsonCommand command) {
- final String resourceUrl = getResourceUrlFromCommand(command);//
command.getSupportedEntityType();
- final Long noteId = command.entityId();
- final NoteType type = NoteType.fromApiUrl(resourceUrl);
- Long resourceId = null;
- Note noteForUpdate = null;
switch (type) {
case CLIENT: {
- resourceId = command.getClientId();
- final Client client =
this.clientRepository.findOneWithNotFoundDetection(resourceId);
- noteForUpdate = this.noteRepository.findByClientAndId(client,
noteId);
+ final var client =
clientRepository.findOneWithNotFoundDetection(resourceId);
+ note = noteRepository.findByClientAndId(client, noteId);
+ officeId = client.officeId();
}
break;
case GROUP: {
- final Long groupId = command.getGroupId();
- resourceId = groupId;
- Group group =
this.groupRepository.findById(groupId).orElseThrow(() -> new
GroupNotFoundException(groupId));
- noteForUpdate = this.noteRepository.findByGroupAndId(group,
noteId);
+ final var group =
groupRepository.findById(resourceId).orElseThrow(() -> new
GroupNotFoundException(resourceId));
+ note = noteRepository.findByGroupAndId(group, noteId);
+ officeId = group.officeId();
}
break;
case LOAN: {
- resourceId = command.getLoanId();
- final Loan loan =
this.loanRepository.findOneWithNotFoundDetection(resourceId);
- noteForUpdate = this.noteRepository.findByLoanAndId(loan,
noteId);
+ final var loan =
loanRepository.findOneWithNotFoundDetection(resourceId);
+ note = noteRepository.findByLoanAndId(loan, noteId);
+ officeId = loan.getOfficeId();
}
break;
case LOAN_TRANSACTION: {
- resourceId = command.subentityId();
- final Long loanTransactionId = resourceId;
- final LoanTransaction loanTransaction =
this.loanTransactionRepository.findById(loanTransactionId)
- .orElseThrow(() -> new
LoanTransactionNotFoundException(loanTransactionId));
- noteForUpdate =
this.noteRepository.findByLoanTransactionAndId(loanTransaction, noteId);
+ final var loanTransaction =
loanTransactionRepository.findById(resourceId)
+ .orElseThrow(() -> new
LoanTransactionNotFoundException(resourceId));
+ note =
noteRepository.findByLoanTransactionAndId(loanTransaction, noteId);
+ officeId = loanTransaction.getLoan().getOfficeId();
}
break;
case SAVING_ACCOUNT: {
- final Long savinsAccountId = command.getSavingsId();
- final SavingsAccount savingAccount =
this.savingsAccountRepository.findById(savinsAccountId)
- .orElseThrow(() -> new
SavingsAccountNotFoundException(savinsAccountId));
-
- noteForUpdate =
this.noteRepository.findBySavingsAccountAndId(savingAccount, noteId);
+ final var savingAccount =
savingsAccountRepository.findById(resourceId)
+ .orElseThrow(() -> new
SavingsAccountNotFoundException(resourceId));
+ note = noteRepository.findBySavingsAccountAndId(savingAccount,
noteId);
+ officeId = savingAccount.getClient().getOffice().getId();
}
break;
case SHARE_ACCOUNT:
- log.error("TODO Implement getNoteForDelete for SHARE_ACCOUNT");
- break;
case SAVINGS_TRANSACTION:
- log.error("TODO Implement getNoteForDelete for
SAVINGS_TRANSACTION");
+ log.error("Not yet implemented: {}", type);
break;
}
- if (noteForUpdate == null) {
+
+ if (note == null) {
throw new NoteNotFoundException(noteId, resourceId,
type.name().toLowerCase());
}
- return noteForUpdate;
- }
+ return Pair.of(note, officeId);
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
index 8fab6f156e..c61fd8f8de 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/note/starter/NoteAutoConfiguration.java
@@ -23,7 +23,6 @@ import
org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import
org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
-import
org.apache.fineract.portfolio.note.serialization.NoteCommandFromApiJsonDeserializer;
import org.apache.fineract.portfolio.note.service.NoteReadPlatformService;
import org.apache.fineract.portfolio.note.service.NoteReadPlatformServiceImpl;
import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
@@ -47,8 +46,8 @@ public class NoteAutoConfiguration {
@ConditionalOnMissingBean
public NoteWritePlatformService noteWritePlatformService(NoteRepository
noteRepository, ClientRepositoryWrapper clientRepository,
GroupRepository groupRepository, LoanRepositoryWrapper
loanRepository, LoanTransactionRepository loanTransactionRepository,
- NoteCommandFromApiJsonDeserializer fromApiJsonDeserializer,
SavingsAccountRepository savingsAccountRepository) {
+ SavingsAccountRepository savingsAccountRepository) {
return new NoteWritePlatformServiceJpaRepositoryImpl(noteRepository,
clientRepository, groupRepository, loanRepository,
- loanTransactionRepository, fromApiJsonDeserializer,
savingsAccountRepository);
+ loanTransactionRepository, savingsAccountRepository);
}
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java
index cdd191aebc..c697bbd238 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java
@@ -57,7 +57,8 @@ import
org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService;
import
org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
+import org.apache.fineract.portfolio.note.data.NoteCreateRequest;
+import org.apache.fineract.portfolio.note.domain.NoteType;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import
org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
import
org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
@@ -67,6 +68,7 @@ import
org.apache.fineract.portfolio.transfer.exception.ClientNotAwaitingTransfe
import
org.apache.fineract.portfolio.transfer.exception.ClientNotAwaitingTransferApprovalOrOnHoldException;
import
org.apache.fineract.portfolio.transfer.exception.TransferNotSupportedException;
import
org.apache.fineract.portfolio.transfer.exception.TransferNotSupportedException.TransferNotSupportedReason;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@@ -81,11 +83,11 @@ public class TransferWritePlatformServiceJpaRepositoryImpl
implements TransferWr
private final LoanRepositoryWrapper loanRepositoryWrapper;
private final SavingsAccountRepositoryWrapper
savingsAccountRepositoryWrapper;
private final TransfersDataValidator transfersDataValidator;
- private final NoteWritePlatformService noteWritePlatformService;
private final StaffRepositoryWrapper staffRepositoryWrapper;
private final ClientTransferDetailsRepositoryWrapper
clientTransferDetailsRepositoryWrapper;
private final PlatformSecurityContext context;
private final LoanOfficerService loanOfficerService;
+ private final ApplicationEventPublisher eventPublisher;
@Override
@Transactional
@@ -466,7 +468,8 @@ public class TransferWritePlatformServiceJpaRepositoryImpl
implements TransferWr
client.updateProposedTransferDate(null);
}
- this.noteWritePlatformService.createAndPersistClientNote(client,
jsonCommand);
+
this.eventPublisher.publishEvent(NoteCreateRequest.builder().type(NoteType.CLIENT).resourceId(client.getId())
+
.note(jsonCommand.stringValueOfParameterNamed("note")).build());
this.clientTransferDetailsRepositoryWrapper
.save(ClientTransferDetails.instance(client.getId(),
client.getOffice().getId(), destinationOffice.getId(), transferDate,
transferEventType.getValue(),
DateUtils.getBusinessLocalDate(), this.context.authenticatedUser().getId()));
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/starter/TransferConfiguration.java
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/starter/TransferConfiguration.java
index 9a0c666dc5..f516b0be40 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/starter/TransferConfiguration.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/starter/TransferConfiguration.java
@@ -28,13 +28,13 @@ import
org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService;
import
org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
-import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
import
org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
import
org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.apache.fineract.portfolio.transfer.data.TransfersDataValidator;
import
org.apache.fineract.portfolio.transfer.service.TransferWritePlatformService;
import
org.apache.fineract.portfolio.transfer.service.TransferWritePlatformServiceJpaRepositoryImpl;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -47,14 +47,13 @@ public class TransferConfiguration {
OfficeRepositoryWrapper officeRepository,
CalendarInstanceRepository calendarInstanceRepository,
LoanWritePlatformService loanWritePlatformService,
GroupRepositoryWrapper groupRepository,
LoanRepositoryWrapper loanRepositoryWrapper,
TransfersDataValidator transfersDataValidator,
- NoteWritePlatformService noteWritePlatformService,
StaffRepositoryWrapper staffRepositoryWrapper,
- SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper,
+ StaffRepositoryWrapper staffRepositoryWrapper,
SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper,
SavingsAccountWritePlatformService
savingsAccountWritePlatformService,
ClientTransferDetailsRepositoryWrapper
clientTransferDetailsRepositoryWrapper, PlatformSecurityContext context,
- LoanOfficerService loanOfficerService) {
+ LoanOfficerService loanOfficerService, ApplicationEventPublisher
eventPublisher) {
return new
TransferWritePlatformServiceJpaRepositoryImpl(clientRepositoryWrapper,
officeRepository, calendarInstanceRepository,
groupRepository, loanWritePlatformService,
savingsAccountWritePlatformService, loanRepositoryWrapper,
- savingsAccountRepositoryWrapper, transfersDataValidator,
noteWritePlatformService, staffRepositoryWrapper,
- clientTransferDetailsRepositoryWrapper, context,
loanOfficerService);
+ savingsAccountRepositoryWrapper, transfersDataValidator,
staffRepositoryWrapper, clientTransferDetailsRepositoryWrapper,
+ context, loanOfficerService, eventPublisher);
}
}
diff --git a/fineract-provider/src/main/resources/application.properties
b/fineract-provider/src/main/resources/application.properties
index b3d2a86aeb..93c249625c 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -487,30 +487,58 @@
resilience4j.retry.instances.postInterest.enable-exponential-backoff=${FINERACT_
resilience4j.retry.instances.postInterest.exponential-backoff-multiplier=${FINERACT_PROCESS_POST_INTEREST_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.postInterest.retryExceptions=${FINERACT_PROCESS_POST_INTEREST_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+# business date
+
resilience4j.retry.instances.commandBusinessDateUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.commandBusinessDateUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.commandBusinessDateUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.commandBusinessDateUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.commandBusinessDateUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_BUSINESS_DATE_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+# cache
+
resilience4j.retry.instances.commandCacheSwitch.max-attempts=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.commandCacheSwitch.wait-duration=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.commandCacheSwitch.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.commandCacheSwitch.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.commandCacheSwitch.retryExceptions=${FINERACT_PROCESS_COMMAND_CACHE_SWITCH_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+# currency
+
resilience4j.retry.instances.commandCurrencyUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.commandCurrencyUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.commandCurrencyUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.commandCurrencyUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.commandCurrencyUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_CURRENCY_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+# external event configuration
+
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_WAIT_DURATION:1s}
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.commandExternalEventConfigurationUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_EXTERNAL_EVENT_CONFIGURATION_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+# note
+
+resilience4j.retry.instances.commandNoteCreate.max-attempts=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_MAX_ATTEMPTS:3}
+resilience4j.retry.instances.commandNoteCreate.wait-duration=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_WAIT_DURATION:1s}
+resilience4j.retry.instances.commandNoteCreate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
+resilience4j.retry.instances.commandNoteCreate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
+resilience4j.retry.instances.commandNoteCreate.retryExceptions=${FINERACT_PROCESS_COMMAND_NOTE_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+
+resilience4j.retry.instances.commandNoteUpdate.max-attempts=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_MAX_ATTEMPTS:3}
+resilience4j.retry.instances.commandNoteUpdate.wait-duration=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_WAIT_DURATION:1s}
+resilience4j.retry.instances.commandNoteUpdate.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
+resilience4j.retry.instances.commandNoteUpdate.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
+resilience4j.retry.instances.commandNoteUpdate.retryExceptions=${FINERACT_PROCESS_COMMAND_NOTE_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+
+resilience4j.retry.instances.commandNoteDelete.max-attempts=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_MAX_ATTEMPTS:3}
+resilience4j.retry.instances.commandNoteDelete.wait-duration=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_WAIT_DURATION:1s}
+resilience4j.retry.instances.commandNoteDelete.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
+resilience4j.retry.instances.commandNoteDelete.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
+resilience4j.retry.instances.commandNoteDelete.retryExceptions=${FINERACT_PROCESS_COMMAND_NOTE_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
+
fineract.command.enabled=true
fineract.command.executor=${FINERACT_COMMAND_EXECUTOR:sync}
fineract.command.ring-buffer-size=${FINERACT_COMMAND_RING_BUFFER_SIZE:1024}
@@ -518,6 +546,10 @@
fineract.command.producer-type=${FINERACT_COMMAND_PRODUCER_TYPE:single}
fineract.command.auditable=${FINERACT_COMMAND_AUDITABLE:true}
# this is duplicated on purpose to keep fineract-command independent; once all
modules are migrated we clean up
fineract.command.idempotency-key-header-name=${FINERACT_IDEMPOTENCY_KEY_HEADER_NAME:Idempotency-Key}
+fineract.command.file-dead-letter-queue-enabled=${FINERACT_FILE_DEAD_LETTER_QUEUE_ENABLED:false}
+fineract.command.file-dead-letter-queue-path=${FINERACT_FILE_DEAD_LETTER_QUEUE_PATH:/tmp/fineract-command-audit}
+
+# command
resilience4j.retry.instances.commandAuditProcessing.max-attempts=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_MAX_ATTEMPTS:3}
resilience4j.retry.instances.commandAuditProcessing.wait-duration=${FINERACT_PROCESS_COMMAND_AUDIT_PROCESSING_RETRY_WAIT_DURATION:1s}
diff --git
a/fineract-validation/src/main/resources/ValidationMessages.properties
b/fineract-validation/src/main/resources/ValidationMessages.properties
index 40cbafc564..1320656623 100644
--- a/fineract-validation/src/main/resources/ValidationMessages.properties
+++ b/fineract-validation/src/main/resources/ValidationMessages.properties
@@ -53,3 +53,8 @@ org.apache.fineract.reage.start-date.not-blank=The parameter
'startDate' is mand
org.apache.fineract.reage.number-of-installments.not-blank=The parameter
'numberOfInstallments' is mandatory.
org.apache.fineract.reage.number-of-installments.min=The parameter
'numberOfInstallments' must be at least 1.
org.apache.fineract.frequency-type.invalid=The parameter 'frequencyType' must
be valid PeriodFrequencyType value. Provided value: '${validatedValue}'.
+
+# Note
+
+org.apache.fineract.portfolio.note.note.size=The parameter 'note' cannot
exceed 1000 characters
+org.apache.fineract.portfolio.note.note.not-null=The parameter 'note' cannot
be empty
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/NotesTest.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/NotesTest.java
index 8f81fa897f..a3a499dd3a 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/NotesTest.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/NotesTest.java
@@ -28,8 +28,6 @@ import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import org.apache.fineract.client.models.NoteData;
-import
org.apache.fineract.client.models.PostResourceTypeResourceIdNotesResponse;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.CollateralManagementHelper;
import org.apache.fineract.integrationtests.common.GroupHelper;
@@ -41,6 +39,8 @@ import
org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtens
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import
org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper;
import
org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
+import org.apache.fineract.portfolio.note.data.NoteData;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -217,8 +217,7 @@ public class NotesTest {
// Notes
final String payload = "{\"note\": \"" + noteText + "\"}";
- final PostResourceTypeResourceIdNotesResponse postNoteResponse =
NotesHelper.createSavingsNote(requestSpec, responseSpec, savingsId,
- payload);
+ final NoteCreateResponse postNoteResponse =
NotesHelper.createSavingsNote(requestSpec, responseSpec, savingsId, payload);
Assertions.assertNotNull(postNoteResponse);
Assertions.assertNotNull(postNoteResponse.getResourceId());
diff --git
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/NotesHelper.java
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/NotesHelper.java
index bc3af6174a..21efd202eb 100644
---
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/NotesHelper.java
+++
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/NotesHelper.java
@@ -21,9 +21,9 @@ package org.apache.fineract.integrationtests.common;
import com.google.gson.Gson;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
-import org.apache.fineract.client.models.NoteData;
-import
org.apache.fineract.client.models.PostResourceTypeResourceIdNotesResponse;
import org.apache.fineract.client.util.JSON;
+import org.apache.fineract.portfolio.note.data.NoteCreateResponse;
+import org.apache.fineract.portfolio.note.data.NoteData;
@SuppressWarnings({ "rawtypes", "unchecked" })
public final class NotesHelper {
@@ -210,11 +210,11 @@ public final class NotesHelper {
// Example:
org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
// org.apache.fineract.client.models.PostLoansLoanIdRequest)
@Deprecated(forRemoval = true)
- public static PostResourceTypeResourceIdNotesResponse
createSavingsNote(RequestSpecification requestSpec,
- ResponseSpecification responseSpec, Integer savingsId, String
request) {
+ public static NoteCreateResponse createSavingsNote(RequestSpecification
requestSpec, ResponseSpecification responseSpec,
+ Integer savingsId, String request) {
final String noteURL = SAVINGS_URL + "/" + savingsId + "/notes?" +
Utils.TENANT_IDENTIFIER;
final String response = Utils.performServerPost(requestSpec,
responseSpec, noteURL, request);
- return GSON.fromJson(response,
PostResourceTypeResourceIdNotesResponse.class);
+ return GSON.fromJson(response, NoteCreateResponse.class);
}
public static NoteData retrieveSavingsNote(RequestSpecification
requestSpec, ResponseSpecification responseSpec, Integer savingsId,