This is an automated email from the ASF dual-hosted git repository.
arnold 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 f3aeef2f4 FINERACT-1744 add idempotency key to command_source table
f3aeef2f4 is described below
commit f3aeef2f45d2596d40d33cbf8cbad8b4915603e5
Author: Zoltan Nebli <[email protected]>
AuthorDate: Sat Oct 15 22:57:01 2022 +0200
FINERACT-1744 add idempotency key to command_source table
---
.../fineract/commands/domain/CommandSource.java | 18 +++++--
.../fineract/commands/domain/CommandWrapper.java | 17 +++++--
.../commands/service/CommandWrapperBuilder.java | 9 +++-
.../commands/service/IdempotencyKeyGenerator.java | 30 +++++++++++
...folioCommandSourceWritePlatformServiceImpl.java | 2 +-
.../SynchronousCommandProcessingService.java | 8 ++-
.../importhandler/center/CenterImportHandler.java | 8 ++-
.../importhandler/group/GroupImportHandler.java | 8 ++-
.../interoperation/api/InteropWrapperBuilder.java | 2 +-
.../resources/db/changelog/db.changelog-master.xml | 2 +
.../db/changelog/tenant/changelog-tenant.xml | 1 +
.../0061_add_idempotency_key_to_command_source.xml | 59 ++++++++++++++++++++++
12 files changed, 149 insertions(+), 15 deletions(-)
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java
b/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java
index 60027871f..f2b34637b 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandSource.java
@@ -107,9 +107,13 @@ public class CommandSource extends
AbstractPersistableCustom {
@Column(name = "job_name")
private String jobName;
- public static CommandSource fullEntryFrom(final CommandWrapper wrapper,
final JsonCommand command, final AppUser maker) {
+ @Column(name = "idempotency_key", length = 50)
+ private String idempotencyKey;
+
+ public static CommandSource fullEntryFrom(final CommandWrapper wrapper,
final JsonCommand command, final AppUser maker,
+ String idempotencyKey) {
return new CommandSource(wrapper.actionName(), wrapper.entityName(),
wrapper.getHref(), command.entityId(), command.subentityId(),
- command.json(), maker);
+ command.json(), maker, idempotencyKey);
}
protected CommandSource() {
@@ -117,7 +121,7 @@ public class CommandSource extends
AbstractPersistableCustom {
}
private CommandSource(final String actionName, final String entityName,
final String href, final Long resourceId,
- final Long subresourceId, final String commandSerializedAsJson,
final AppUser maker) {
+ final Long subresourceId, final String commandSerializedAsJson,
final AppUser maker, final String idempotencyKey) {
this.actionName = actionName;
this.entityName = entityName;
this.resourceGetUrl = href;
@@ -127,6 +131,7 @@ public class CommandSource extends
AbstractPersistableCustom {
this.maker = maker;
this.madeOnDate = DateUtils.getOffsetDateTimeOfTenant();
this.processingResult =
CommandProcessingResultType.PROCESSED.getValue();
+ this.idempotencyKey = idempotencyKey;
}
public Long getCreditBureauId() {
@@ -286,4 +291,11 @@ public class CommandSource extends
AbstractPersistableCustom {
this.transactionId = transactionId;
}
+ public String getIdempotencyKey() {
+ return idempotencyKey;
+ }
+
+ public void setIdempotencyKey(String idempotencyKey) {
+ this.idempotencyKey = idempotencyKey;
+ }
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandWrapper.java
b/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandWrapper.java
index cb09f24f6..c28ac3466 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandWrapper.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/commands/domain/CommandWrapper.java
@@ -42,6 +42,8 @@ public class CommandWrapper {
private final Long organisationCreditBureauId;
private final String jobName;
+ private final String idempotencyKey;
+
@SuppressWarnings("unused")
private Long templateId;
@@ -57,9 +59,9 @@ public class CommandWrapper {
public static CommandWrapper fromExistingCommand(final Long commandId,
final String actionName, final String entityName,
final Long resourceId, final Long subresourceId, final String
resourceGetUrl, final Long productId, final Long officeId,
final Long groupId, final Long clientId, final Long loanId, final
Long savingsId, final String transactionId,
- final Long creditBureauId, final Long organisationCreditBureauId) {
+ final Long creditBureauId, final Long organisationCreditBureauId,
final String idempotencyKey) {
return new CommandWrapper(commandId, actionName, entityName,
resourceId, subresourceId, resourceGetUrl, productId, officeId,
- groupId, clientId, loanId, savingsId, transactionId,
creditBureauId, organisationCreditBureauId);
+ groupId, clientId, loanId, savingsId, transactionId,
creditBureauId, organisationCreditBureauId, idempotencyKey);
}
private CommandWrapper(final Long commandId, final String actionName,
final String entityName, final Long resourceId,
@@ -82,12 +84,13 @@ public class CommandWrapper {
this.creditBureauId = null;
this.organisationCreditBureauId = null;
this.jobName = null;
+ this.idempotencyKey = null;
}
public CommandWrapper(final Long officeId, final Long groupId, final Long
clientId, final Long loanId, final Long savingsId,
final String actionName, final String entityName, final Long
entityId, final Long subentityId, final String href,
final String json, final String transactionId, final Long
productId, final Long templateId, final Long creditBureauId,
- final Long organisationCreditBureauId, final String jobName) {
+ final Long organisationCreditBureauId, final String jobName, final
String idempotencyKey) {
this.commandId = null;
this.officeId = officeId;
@@ -108,12 +111,13 @@ public class CommandWrapper {
this.creditBureauId = creditBureauId;
this.organisationCreditBureauId = organisationCreditBureauId;
this.jobName = jobName;
+ this.idempotencyKey = idempotencyKey;
}
private CommandWrapper(final Long commandId, final String actionName,
final String entityName, final Long resourceId,
final Long subresourceId, final String resourceGetUrl, final Long
productId, final Long officeId, final Long groupId,
final Long clientId, final Long loanId, final Long savingsId,
final String transactionId, final Long creditBureauId,
- final Long organisationCreditBureauId) {
+ final Long organisationCreditBureauId, final String
idempotencyKey) {
this.commandId = commandId;
this.officeId = officeId;
@@ -133,6 +137,7 @@ public class CommandWrapper {
this.creditBureauId = creditBureauId;
this.organisationCreditBureauId = organisationCreditBureauId;
this.jobName = null;
+ this.idempotencyKey = idempotencyKey;
}
public Long getCreditBureauId() {
@@ -143,6 +148,10 @@ public class CommandWrapper {
return this.organisationCreditBureauId;
}
+ public String getIdempotencyKey() {
+ return idempotencyKey;
+ }
+
public String getHref() {
return this.href;
}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
index 56892ae07..a7327e7ca 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java
@@ -45,11 +45,18 @@ public class CommandWrapperBuilder {
private Long creditBureauId;
private Long organisationCreditBureauId;
private String jobName;
+ private String idempotencyKey;
public CommandWrapper build() {
return new CommandWrapper(this.officeId, this.groupId, this.clientId,
this.loanId, this.savingsId, this.actionName, this.entityName,
this.entityId, this.subentityId, this.href, this.json,
this.transactionId, this.productId, this.templateId,
- this.creditBureauId, this.organisationCreditBureauId,
this.jobName);
+ this.creditBureauId, this.organisationCreditBureauId,
this.jobName, this.idempotencyKey);
+ }
+
+ public CommandWrapper build(String idempotencyKey) {
+ return new CommandWrapper(this.officeId, this.groupId, this.clientId,
this.loanId, this.savingsId, this.actionName, this.entityName,
+ this.entityId, this.subentityId, this.href, this.json,
this.transactionId, this.productId, this.templateId,
+ this.creditBureauId, this.organisationCreditBureauId,
this.jobName, idempotencyKey);
}
public CommandWrapperBuilder updateCreditBureau() {
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/IdempotencyKeyGenerator.java
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/IdempotencyKeyGenerator.java
new file mode 100644
index 000000000..a9e715507
--- /dev/null
+++
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/IdempotencyKeyGenerator.java
@@ -0,0 +1,30 @@
+/**
+ * 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.commands.service;
+
+import java.util.UUID;
+import org.springframework.stereotype.Component;
+
+@Component
+public class IdempotencyKeyGenerator {
+
+ public String create() {
+ return UUID.randomUUID().toString();
+ }
+}
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java
index 0552172e7..c8ebab8c2 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/PortfolioCommandSourceWritePlatformServiceImpl.java
@@ -130,7 +130,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl
implements Portfolio
commandSourceInput.getResourceGetUrl(),
commandSourceInput.getProductId(), commandSourceInput.getOfficeId(),
commandSourceInput.getGroupId(),
commandSourceInput.getClientId(), commandSourceInput.getLoanId(),
commandSourceInput.getSavingsId(),
commandSourceInput.getTransactionId(), commandSourceInput.getCreditBureauId(),
- commandSourceInput.getOrganisationCreditBureauId());
+ commandSourceInput.getOrganisationCreditBureauId(),
commandSourceInput.getIdempotencyKey());
final JsonElement parsedCommand =
this.fromApiJsonHelper.parse(commandSourceInput.json());
final JsonCommand command =
JsonCommand.fromExistingCommand(makerCheckerId, commandSourceInput.json(),
parsedCommand,
this.fromApiJsonHelper, commandSourceInput.getEntityName(),
commandSourceInput.resourceId(),
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java
index c15376007..537c09ba0 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/commands/service/SynchronousCommandProcessingService.java
@@ -63,6 +63,8 @@ public class SynchronousCommandProcessingService implements
CommandProcessingSer
private final ConfigurationDomainService configurationDomainService;
private final CommandHandlerProvider commandHandlerProvider;
+ private final IdempotencyKeyGenerator idempotencyKeyGenerator;
+
@Transactional
@Override
public CommandProcessingResult executeCommand(final CommandWrapper
wrapper, final JsonCommand command,
@@ -88,7 +90,8 @@ public class SynchronousCommandProcessingService implements
CommandProcessingSer
.orElseThrow(() -> new
CommandNotFoundException(command.commandId()));
commandSourceResult.markAsChecked(maker);
} else {
- commandSourceResult = CommandSource.fullEntryFrom(wrapper,
command, maker);
+ commandSourceResult = CommandSource.fullEntryFrom(wrapper,
command, maker,
+ wrapper.getIdempotencyKey() == null ?
idempotencyKeyGenerator.create() : wrapper.getIdempotencyKey());
}
commandSourceResult.updateResourceId(result.getResourceId());
commandSourceResult.updateForAudit(result.getOfficeId(),
result.getGroupId(), result.getClientId(), result.getLoanId(),
@@ -134,6 +137,9 @@ public class SynchronousCommandProcessingService implements
CommandProcessingSer
public CommandProcessingResult logCommand(CommandSource
commandSourceResult) {
commandSourceResult.markAsAwaitingApproval();
+ if (commandSourceResult.getIdempotencyKey() == null) {
+
commandSourceResult.setIdempotencyKey(idempotencyKeyGenerator.create());
+ }
commandSourceResult =
commandSourceRepository.saveAndFlush(commandSourceResult);
return new
CommandProcessingResultBuilder().withCommandId(commandSourceResult.getId())
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java
index d38440250..e27555147 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java
@@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.List;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
+import org.apache.fineract.commands.service.IdempotencyKeyGenerator;
import
org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.bulkimport.constants.CenterConstants;
import
org.apache.fineract.infrastructure.bulkimport.constants.TemplatePopulateImportConstants;
@@ -62,10 +63,13 @@ public class CenterImportHandler implements ImportHandler {
private Workbook workbook;
private final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService;
+ private final IdempotencyKeyGenerator idempotencyKeyGenerator;
@Autowired
- public CenterImportHandler(final
PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
+ public CenterImportHandler(final
PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
+ IdempotencyKeyGenerator idempotencyKeyGenerator) {
this.commandsSourceWritePlatformService =
commandsSourceWritePlatformService;
+ this.idempotencyKeyGenerator = idempotencyKeyGenerator;
}
@Override
@@ -262,7 +266,7 @@ public class CenterImportHandler implements ImportHandler {
String payload = gsonBuilder.create().toJson(calendarData);
CommandWrapper commandWrapper = new
CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(),
result.getLoanId(), result.getSavingsId(), null, null, null,
null, null, payload, result.getTransactionId(),
- result.getProductId(), null, null, null, null);
+ result.getProductId(), null, null, null, null,
idempotencyKeyGenerator.create());
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.createCalendar(commandWrapper,
TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) //
.withJson(payload) //
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java
index b8835a9a3..b792fcb5b 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java
@@ -27,6 +27,7 @@ import java.util.Collection;
import java.util.List;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
+import org.apache.fineract.commands.service.IdempotencyKeyGenerator;
import
org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.bulkimport.constants.GroupConstants;
import
org.apache.fineract.infrastructure.bulkimport.constants.TemplatePopulateImportConstants;
@@ -62,10 +63,13 @@ public class GroupImportHandler implements ImportHandler {
private List<String> statuses;
private final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService;
+ private final IdempotencyKeyGenerator idempotencyKeyGenerator;
@Autowired
- public GroupImportHandler(final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService) {
+ public GroupImportHandler(final PortfolioCommandSourceWritePlatformService
commandsSourceWritePlatformService,
+ IdempotencyKeyGenerator idempotencyKeyGenerator) {
this.commandsSourceWritePlatformService =
commandsSourceWritePlatformService;
+ this.idempotencyKeyGenerator = idempotencyKeyGenerator;
}
@Override
@@ -241,7 +245,7 @@ public class GroupImportHandler implements ImportHandler {
String payload = gsonBuilder.create().toJson(calendarData);
CommandWrapper commandWrapper = new
CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(),
result.getLoanId(), result.getSavingsId(), null, null, null,
null, null, payload, result.getTransactionId(),
- result.getProductId(), null, null, null, null);
+ result.getProductId(), null, null, null, null,
idempotencyKeyGenerator.create());
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.createCalendar(commandWrapper,
TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) //
.withJson(payload) //
diff --git
a/fineract-provider/src/main/java/org/apache/fineract/interoperation/api/InteropWrapperBuilder.java
b/fineract-provider/src/main/java/org/apache/fineract/interoperation/api/InteropWrapperBuilder.java
index 0f847dabf..20a7c2bc5 100644
---
a/fineract-provider/src/main/java/org/apache/fineract/interoperation/api/InteropWrapperBuilder.java
+++
b/fineract-provider/src/main/java/org/apache/fineract/interoperation/api/InteropWrapperBuilder.java
@@ -37,7 +37,7 @@ public class InteropWrapperBuilder {
public CommandWrapper build() {
return new CommandWrapper(null, null, null, null, null, actionName,
entityName, null, null, href, json, null, null, null, null,
- null, null);
+ null, null, null);
}
public InteropWrapperBuilder withJson(final String json) {
diff --git
a/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
b/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
index 9f9c3b880..266a6ff77 100644
--- a/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
+++ b/fineract-provider/src/main/resources/db/changelog/db.changelog-master.xml
@@ -25,6 +25,8 @@
<property name="current_date" value="CURDATE()" context="mysql"/>
<property name="current_date" value="CURRENT_DATE" context="postgresql"/>
<property name="current_datetime" value="NOW()"/>
+ <property name="uuid" value="uuid()" context="mysql"/>
+ <property name="uuid" value="uuid_generate_v4()" context="postgresql"/>
<include file="tenant-store/initial-switch-changelog-tenant-store.xml"
relativeToChangelogFile="true" context="tenant_store_db AND initial_switch"/>
<include file="tenant-store/changelog-tenant-store.xml"
relativeToChangelogFile="true" context="tenant_store_db AND !initial_switch"/>
<include file="tenant/initial-switch-changelog-tenant.xml"
relativeToChangelogFile="true" context="tenant_db AND initial_switch"/>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
index 31941ab88..d66da7972 100644
---
a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml
@@ -80,4 +80,5 @@
<include file="parts/0058_add_execute_inline_cob_permission.xml"
relativeToChangelogFile="true"/>
<include file="parts/0059_add_spring_batch_loan_id_list_table.xml"
relativeToChangelogFile="true"/>
<include file="parts/0060_add_job_name_to_command_source.xml"
relativeToChangelogFile="true"/>
+ <include file="parts/0061_add_idempotency_key_to_command_source.xml"
relativeToChangelogFile="true"/>
</databaseChangeLog>
diff --git
a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0061_add_idempotency_key_to_command_source.xml
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0061_add_idempotency_key_to_command_source.xml
new file mode 100644
index 000000000..1bb48450d
--- /dev/null
+++
b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0061_add_idempotency_key_to_command_source.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
+ <changeSet author="fineract" id="1" context="postgresql">
+ <sql>
+ CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
+ </sql>
+ </changeSet>
+
+ <changeSet author="fineract" id="2">
+ <addColumn tableName="m_portfolio_command_source">
+ <column defaultValueComputed="NULL" name="idempotency_key"
type="VARCHAR(50)"/>
+ </addColumn>
+ <update tableName="m_portfolio_command_source">
+ <column name="idempotency_key" valueComputed="${uuid}" />
+ <where>idempotency_key is null</where>
+ </update>
+ <addUniqueConstraint columnNames="action_name, entity_name,
idempotency_key" constraintName="UNIQUE_PORTFOLIO_COMMAND_SOURCE"
+ tableName="m_portfolio_command_source"/>
+ <createIndex indexName="portfolio_command_source_composite_index"
tableName="m_portfolio_command_source">
+ <column name="action_name"/>
+ <column name="entity_name"/>
+ <column name="idempotency_key"/>
+ </createIndex>
+ </changeSet>
+
+ <changeSet author="fineract" id="3" context="postgresql">
+ <addNotNullConstraint columnName="idempotency_key"
+ constraintName="mpcs_idempotency_key_nn"
+ tableName="m_portfolio_command_source"/>
+ </changeSet>
+
+ <changeSet author="fineract" id="4" context="mysql">
+ <sql>
+ ALTER TABLE m_portfolio_command_source MODIFY idempotency_key
VARCHAR(50) not NULL
+ </sql>
+ </changeSet>
+</databaseChangeLog>