nominee facility added code update

This commit is contained in:
Nitesh Yadav
2026-05-15 12:59:57 +05:30
parent 167079c2d7
commit 7e0fe99ea6
16 changed files with 42533 additions and 29760 deletions
+3 -2
View File
@@ -36,7 +36,8 @@
"Bash(curl -sk -X POST \"https://localhost:8443/fineract-provider/api/v1/authentication?username=mifos&password=password\" -H 'Fineract-Platform-TenantId: default' -H 'Content-Type: application/json')",
"Bash(curl -sk \"https://localhost:8443/fineract-provider/api/v1/clients?limit=5\" -H \"Fineract-Platform-TenantId: default\" -u \"mifos:password\")",
"Bash(curl -sk -X POST \"https://localhost:8443/fineract-provider/api/v1/authentication\" -H \"Fineract-Platform-TenantId: default\" -H \"Content-Type: application/json\" -d '{\"\"username\"\":\"\"mifos\"\",\"\"password\"\":\"\"password\"\"}')",
"Bash(curl -sk \"https://localhost:8443/fineract-provider/api/v1/clients?limit=5\" -H \"Fineract-Platform-TenantId: default\" -H \"Authorization: Basic bWlmb3M6cGFzc3dvcmQ=\")"
"Bash(curl -sk \"https://localhost:8443/fineract-provider/api/v1/clients?limit=5\" -H \"Fineract-Platform-TenantId: default\" -H \"Authorization: Basic bWlmb3M6cGFzc3dvcmQ=\")",
"Bash(git add *)"
],
"additionalDirectories": [
"c:\\Users\\adity\\Music\\CBS\\cfcfrms-bank-api"
@@ -55,4 +56,4 @@
}
]
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -18,6 +18,7 @@
*/
package org.apache.fineract.portfolio.client.service;
import com.google.gson.JsonElement;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
@@ -28,4 +29,11 @@ public interface ClientNomineeWritePlatformService {
CommandProcessingResult updateNominee(Long clientId, Long nomineeId, JsonCommand command);
CommandProcessingResult deleteNominee(Long clientId, Long nomineeId);
/**
* Saves nominee from a JSON element already extracted from the account creation payload.
* Called internally during account creation (SB/CB/FD/RD) so nominee is persisted
* in the same transaction without a separate API call.
*/
void saveNomineeIfPresent(Long clientId, String accountNo, String accountType, JsonElement nomineeJson);
}
@@ -18,10 +18,13 @@
*/
package org.apache.fineract.portfolio.client.service;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -43,6 +46,7 @@ import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@Slf4j
public class ClientNomineeWritePlatformServiceImpl implements ClientNomineeWritePlatformService {
private static final String RELATIONSHIP_CODE = "RELATIONSHIP";
@@ -301,4 +305,59 @@ public class ClientNomineeWritePlatformServiceImpl implements ClientNomineeWrite
"percentageShare", total);
}
}
@Override
public void saveNomineeIfPresent(final Long clientId, final String accountNo, final String accountType, final JsonElement nomineeJson) {
if (nomineeJson == null || nomineeJson.isJsonNull() || !nomineeJson.isJsonObject()) return;
final JsonObject n = nomineeJson.getAsJsonObject();
if (!n.has("nomineeClientId") || n.get("nomineeClientId").isJsonNull()) return;
try {
final Client client = clientRepository.findOneWithNotFoundDetection(clientId);
final Long nomineeClientId = n.get("nomineeClientId").getAsLong();
if (nomineeClientId.equals(clientId)) return; // self-nomination guard
final Client nomineeClient = clientRepository.findOneWithNotFoundDetection(nomineeClientId);
final BigDecimal share = n.has("percentageShare") && !n.get("percentageShare").isJsonNull()
? n.get("percentageShare").getAsBigDecimal() : BigDecimal.ZERO;
validatePercentageShareForAccount(accountNo, accountType, null, share);
final ClientNominee nominee = new ClientNominee();
nominee.setClient(client);
nominee.setNomineeClient(nomineeClient);
nominee.setPercentageShare(share);
nominee.setIsActive(true);
nominee.setAccountNo(accountNo);
nominee.setAccountType(accountType);
nominee.setNomineeIdentifier(generateNomineeIdentifier(accountNo, accountType));
if (n.has("relationshipId") && !n.get("relationshipId").isJsonNull()) {
final Long relationshipId = n.get("relationshipId").getAsLong();
final CodeValue relationship = codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
RELATIONSHIP_CODE, relationshipId);
nominee.setRelationship(relationship);
}
final boolean isMinor = n.has("nomineeIsMinor") && !n.get("nomineeIsMinor").isJsonNull()
&& n.get("nomineeIsMinor").getAsBoolean();
nominee.setNomineeIsMinor(isMinor);
if (isMinor && n.has("guardianClientId") && !n.get("guardianClientId").isJsonNull()) {
final Long guardianClientId = n.get("guardianClientId").getAsLong();
final Client guardian = clientRepository.findOneWithNotFoundDetection(guardianClientId);
nominee.setGuardianClient(guardian);
}
if (n.has("remarks") && !n.get("remarks").isJsonNull()) {
nominee.setRemarks(n.get("remarks").getAsString());
}
nomineeRepository.saveAndFlush(nominee);
} catch (Exception e) {
log.warn("Failed to save nominee during account creation for clientId={}, accountNo={}: {}", clientId, accountNo, e.getMessage());
}
}
}
@@ -34,6 +34,7 @@ import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.client.service.ClientNomineeWritePlatformService;
import org.apache.fineract.portfolio.currentaccount.domain.CurrentAccount;
import org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountFacilityConfig;
import org.apache.fineract.portfolio.currentaccount.domain.CurrentAccountJointHolder;
@@ -59,6 +60,7 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
private final ClientRepositoryWrapper clientRepository;
private final OfficeRepositoryWrapper officeRepository;
private final CurrentAccountNumberGenerator accountNumberGenerator;
private final ClientNomineeWritePlatformService clientNomineeWritePlatformService;
@Override
@Transactional
@@ -156,6 +158,11 @@ public class CurrentAccountWritePlatformServiceImpl implements CurrentAccountWri
final String accountNo = accountNumberGenerator.generate(account);
account.updateAccountNo(accountNo);
// Save nominee if provided in payload (same transaction)
if (json.has("nominee") && !json.get("nominee").isJsonNull()) {
clientNomineeWritePlatformService.saveNomineeIfPresent(clientId, accountNo, "CB", json.get("nominee"));
}
// Facility config — UI sends "accountFacilityConfig", internal uses "facilityConfig"
JsonObject fcJson = json.getAsJsonObject("accountFacilityConfig");
if (fcJson == null) fcJson = json.getAsJsonObject("facilityConfig");
@@ -69,6 +69,7 @@ import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
import org.apache.fineract.portfolio.client.service.ClientNomineeWritePlatformService;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.domain.GroupRepository;
@@ -123,6 +124,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
private final BusinessEventNotifierService businessEventNotifierService;
private final SavingsAccountAssembler savingsAccountAssembler;
private final ClientNomineeWritePlatformService clientNomineeWritePlatformService;
/*
* Guaranteed to throw an exception no matter what the data integrity issue is.
@@ -196,6 +198,13 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
this.accountAssociationsRepository.save(accountAssociations);
}
// Save nominee if provided in payload (same transaction)
if (command.parameterExists("nominee")) {
clientNomineeWritePlatformService.saveNomineeIfPresent(
account.clientId(), account.getAccountNumber(), "FD",
command.parsedJson().getAsJsonObject().get("nominee"));
}
final Long savingsId = account.getId();
businessEventNotifierService.notifyPostBusinessEvent(new FixedDepositAccountCreateBusinessEvent(account));
@@ -258,6 +267,14 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
financialYearBeginningMonth);
account.validateApplicableInterestRate();
savingAccountRepository.save(account);
// Save nominee if provided in payload (same transaction)
if (command.parameterExists("nominee")) {
clientNomineeWritePlatformService.saveNomineeIfPresent(
account.clientId(), account.getAccountNumber(), "RD",
command.parsedJson().getAsJsonObject().get("nominee"));
}
businessEventNotifierService.notifyPostBusinessEvent(new RecurringDepositAccountCreateBusinessEvent(account));
return new CommandProcessingResultBuilder() //
@@ -62,6 +62,7 @@ import org.apache.fineract.portfolio.account.service.AccountNumberGenerator;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
import org.apache.fineract.portfolio.client.service.ClientNomineeWritePlatformService;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.domain.GroupRepository;
import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper;
@@ -113,6 +114,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
private final GSIMRepositoy gsimRepository;
private final GroupRepositoryWrapper groupRepositoryWrapper;
private final GroupSavingsIndividualMonitoringWritePlatformService gsimWritePlatformService;
private final ClientNomineeWritePlatformService clientNomineeWritePlatformService;
@Transactional
@Override
@@ -231,6 +233,13 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
}
}
// end of gsim
// Save nominee if provided in payload (same transaction)
if (command.parameterExists("nominee")) {
clientNomineeWritePlatformService.saveNomineeIfPresent(
account.clientId(), account.getAccountNumber(), "SB",
command.parsedJson().getAsJsonObject().get("nominee"));
}
final Long savingsId = account.getId();
if (command.parameterExists(SavingsApiConstants.datatables)) {
this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getValue(), EntityTables.SAVINGS.getName(),
@@ -55,6 +55,7 @@ import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
import org.apache.fineract.portfolio.charge.service.ChargeDropdownReadPlatformService;
import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.client.service.ClientNomineeWritePlatformService;
import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
import org.apache.fineract.portfolio.common.service.DropdownReadPlatformService;
import org.apache.fineract.portfolio.group.domain.GroupRepository;
@@ -289,13 +290,14 @@ public class SavingsConfiguration {
SavingsAccountChargeAssembler savingsAccountChargeAssembler, AccountAssociationsRepository accountAssociationsRepository,
FromJsonHelper fromJsonHelper, CalendarInstanceRepository calendarInstanceRepository,
ConfigurationDomainService configurationDomainService, AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
BusinessEventNotifierService businessEventNotifierService, SavingsAccountAssembler savingsAccountAssembler) {
BusinessEventNotifierService businessEventNotifierService, SavingsAccountAssembler savingsAccountAssembler,
ClientNomineeWritePlatformService clientNomineeWritePlatformService) {
return new DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl(context, savingAccountRepository,
fixedDepositAccountRepository, recurringDepositAccountRepository, depositAccountAssembler, depositAccountDataValidator,
accountNumberGenerator, clientRepository, groupRepository, savingsProductRepository, noteRepository, staffRepository,
savingsAccountApplicationTransitionApiJsonValidator, savingsAccountChargeAssembler, accountAssociationsRepository,
fromJsonHelper, calendarInstanceRepository, configurationDomainService, accountNumberFormatRepository,
businessEventNotifierService, savingsAccountAssembler);
businessEventNotifierService, savingsAccountAssembler, clientNomineeWritePlatformService);
}
@Bean
@@ -444,13 +446,14 @@ public class SavingsConfiguration {
SavingsAccountDomainService savingsAccountDomainService, SavingsAccountWritePlatformService savingsAccountWritePlatformService,
AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, BusinessEventNotifierService businessEventNotifierService,
EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, GSIMRepositoy gsimRepository,
GroupRepositoryWrapper groupRepositoryWrapper, GroupSavingsIndividualMonitoringWritePlatformService gsimWritePlatformService) {
GroupRepositoryWrapper groupRepositoryWrapper, GroupSavingsIndividualMonitoringWritePlatformService gsimWritePlatformService,
ClientNomineeWritePlatformService clientNomineeWritePlatformService) {
return new SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(context, savingAccountRepository, savingAccountAssembler,
savingsAccountDataValidator, accountNumberGenerator, clientRepository, groupRepository, savingsProductRepository,
noteRepository, staffRepository, savingsAccountApplicationTransitionApiJsonValidator, savingsAccountChargeAssembler,
commandProcessingService, savingsAccountDomainService, savingsAccountWritePlatformService, accountNumberFormatRepository,
businessEventNotifierService, entityDatatableChecksWritePlatformService, gsimRepository, groupRepositoryWrapper,
gsimWritePlatformService);
gsimWritePlatformService, clientNomineeWritePlatformService);
}
@Bean
@@ -18,9 +18,12 @@
<changeSet id="0278b_add_is_mandatory_to_savings_joint_holder" author="system">
<preConditions onFail="MARK_RAN">
<not>
<columnExists tableName="m_savings_account_joint_holders" columnName="is_mandatory"/>
</not>
<and>
<tableExists tableName="m_savings_account_joint_holders"/>
<not>
<columnExists tableName="m_savings_account_joint_holders" columnName="is_mandatory"/>
</not>
</and>
</preConditions>
<addColumn tableName="m_savings_account_joint_holders">
<column name="is_mandatory" type="boolean" defaultValueBoolean="false">
@@ -34,7 +34,10 @@
<!-- 1. Tables that already have is_active — add is_deleted only -->
<changeSet id="0279a_is_deleted_client_address" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_address" columnName="is_deleted"/></not>
<and>
<tableExists tableName="m_client_address"/>
<not><columnExists tableName="m_client_address" columnName="is_deleted"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_address">
<column name="is_deleted" type="boolean" defaultValueBoolean="false">
@@ -45,7 +48,10 @@
<changeSet id="0279b_is_deleted_client_nominee" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_nominee" columnName="is_deleted"/></not>
<and>
<tableExists tableName="m_client_nominee"/>
<not><columnExists tableName="m_client_nominee" columnName="is_deleted"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_nominee">
<column name="is_deleted" type="boolean" defaultValueBoolean="false">
@@ -56,7 +62,10 @@
<changeSet id="0279c_is_deleted_client_charge" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_charge" columnName="is_deleted"/></not>
<and>
<tableExists tableName="m_client_charge"/>
<not><columnExists tableName="m_client_charge" columnName="is_deleted"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_charge">
<column name="is_deleted" type="boolean" defaultValueBoolean="false">
@@ -68,7 +77,10 @@
<!-- 2. Tables that have neither — add both -->
<changeSet id="0279d_flags_client_non_person" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_non_person" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_non_person"/>
<not><columnExists tableName="m_client_non_person" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_non_person">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -82,7 +94,10 @@
<changeSet id="0279e_flags_client_identifier" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_identifier" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_identifier"/>
<not><columnExists tableName="m_client_identifier" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_identifier">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -96,7 +111,10 @@
<changeSet id="0279f_flags_client_kyc" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_kyc" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_kyc"/>
<not><columnExists tableName="m_client_kyc" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_kyc">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -110,7 +128,10 @@
<changeSet id="0279g_flags_address" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_address" columnName="is_active"/></not>
<and>
<tableExists tableName="m_address"/>
<not><columnExists tableName="m_address" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_address">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -124,7 +145,10 @@
<changeSet id="0279h_flags_client_priority_sector" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_priority_sector" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_priority_sector"/>
<not><columnExists tableName="m_client_priority_sector" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_priority_sector">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -138,7 +162,10 @@
<changeSet id="0279i_flags_client_non_priority_sector" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_non_priority_sector" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_non_priority_sector"/>
<not><columnExists tableName="m_client_non_priority_sector" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_non_priority_sector">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -152,7 +179,10 @@
<changeSet id="0279j_flags_client_msme" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_msme" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_msme"/>
<not><columnExists tableName="m_client_msme" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_msme">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -166,7 +196,10 @@
<changeSet id="0279k_flags_client_mudra_borrower" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_mudra_borrower" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_mudra_borrower"/>
<not><columnExists tableName="m_client_mudra_borrower" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_mudra_borrower">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -180,7 +213,10 @@
<changeSet id="0279l_flags_client_startup_india" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_startup_india" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_startup_india"/>
<not><columnExists tableName="m_client_startup_india" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_startup_india">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -194,7 +230,10 @@
<changeSet id="0279m_flags_client_eou" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_eou" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_eou"/>
<not><columnExists tableName="m_client_eou" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_eou">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -208,7 +247,10 @@
<changeSet id="0279n_flags_client_charge_paid_by" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_charge_paid_by" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_charge_paid_by"/>
<not><columnExists tableName="m_client_charge_paid_by" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_charge_paid_by">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -222,7 +264,10 @@
<changeSet id="0279o_flags_client_collateral_management" author="fineract">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client_collateral_management" columnName="is_active"/></not>
<and>
<tableExists tableName="m_client_collateral_management"/>
<not><columnExists tableName="m_client_collateral_management" columnName="is_active"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_collateral_management">
<column name="is_active" type="boolean" defaultValueBoolean="true">
@@ -28,7 +28,12 @@
-->
<changeSet id="0280a_deletion_audit_family_members" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_family_members" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_family_members"/>
<not><columnExists tableName="m_family_members" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_family_members">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -37,7 +42,12 @@
</changeSet>
<changeSet id="0280b_deletion_audit_client_address" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_address" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_address"/>
<not><columnExists tableName="m_client_address" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_address">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -46,7 +56,12 @@
</changeSet>
<changeSet id="0280c_deletion_audit_client_nominee" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_nominee" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_nominee"/>
<not><columnExists tableName="m_client_nominee" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_nominee">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -55,7 +70,12 @@
</changeSet>
<changeSet id="0280d_deletion_audit_client_charge" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_charge" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_charge"/>
<not><columnExists tableName="m_client_charge" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_charge">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -64,7 +84,12 @@
</changeSet>
<changeSet id="0280e_deletion_audit_client_non_person" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_non_person" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_non_person"/>
<not><columnExists tableName="m_client_non_person" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_non_person">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -73,7 +98,12 @@
</changeSet>
<changeSet id="0280f_deletion_audit_client_identifier" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_identifier" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_identifier"/>
<not><columnExists tableName="m_client_identifier" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_identifier">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -82,7 +112,12 @@
</changeSet>
<changeSet id="0280g_deletion_audit_client_kyc" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_kyc" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_kyc"/>
<not><columnExists tableName="m_client_kyc" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_kyc">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -91,7 +126,12 @@
</changeSet>
<changeSet id="0280h_deletion_audit_address" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_address" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_address"/>
<not><columnExists tableName="m_address" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_address">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -100,7 +140,12 @@
</changeSet>
<changeSet id="0280i_deletion_audit_client_priority_sector" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_priority_sector" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_priority_sector"/>
<not><columnExists tableName="m_client_priority_sector" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_priority_sector">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -109,7 +154,12 @@
</changeSet>
<changeSet id="0280j_deletion_audit_client_non_priority_sector" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_non_priority_sector" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_non_priority_sector"/>
<not><columnExists tableName="m_client_non_priority_sector" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_non_priority_sector">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -118,7 +168,12 @@
</changeSet>
<changeSet id="0280k_deletion_audit_client_msme" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_msme" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_msme"/>
<not><columnExists tableName="m_client_msme" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_msme">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -127,7 +182,12 @@
</changeSet>
<changeSet id="0280l_deletion_audit_client_mudra_borrower" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_mudra_borrower" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_mudra_borrower"/>
<not><columnExists tableName="m_client_mudra_borrower" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_mudra_borrower">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -136,7 +196,12 @@
</changeSet>
<changeSet id="0280m_deletion_audit_client_startup_india" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_startup_india" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_startup_india"/>
<not><columnExists tableName="m_client_startup_india" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_startup_india">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -145,7 +210,12 @@
</changeSet>
<changeSet id="0280n_deletion_audit_client_eou" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_eou" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_eou"/>
<not><columnExists tableName="m_client_eou" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_eou">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -154,7 +224,12 @@
</changeSet>
<changeSet id="0280o_deletion_audit_client_charge_paid_by" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_charge_paid_by" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_charge_paid_by"/>
<not><columnExists tableName="m_client_charge_paid_by" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_charge_paid_by">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -163,7 +238,12 @@
</changeSet>
<changeSet id="0280p_deletion_audit_client_collateral_management" author="fineract">
<preConditions onFail="MARK_RAN"><not><columnExists tableName="m_client_collateral_management" columnName="deleted_at"/></not></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_collateral_management"/>
<not><columnExists tableName="m_client_collateral_management" columnName="deleted_at"/></not>
</and>
</preConditions>
<addColumn tableName="m_client_collateral_management">
<column name="deleted_by" type="bigint"/>
<column name="deleted_at" type="datetime"/>
@@ -38,63 +38,108 @@
<!-- =========================== Group A: rename =========================== -->
<changeSet id="0281a_rename_audit_client_nominee" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_nominee" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_nominee"/>
<columnExists tableName="m_client_nominee" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_nominee" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_nominee" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_nominee" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281b_rename_audit_client_identifier" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_identifier" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_identifier"/>
<columnExists tableName="m_client_identifier" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_identifier" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_identifier" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_identifier" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281c_rename_audit_client_kyc" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_kyc" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_kyc"/>
<columnExists tableName="m_client_kyc" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_kyc" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_kyc" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_kyc" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281d_rename_audit_client_priority_sector" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_priority_sector" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_priority_sector"/>
<columnExists tableName="m_client_priority_sector" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_priority_sector" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_priority_sector" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_priority_sector" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281e_rename_audit_client_non_priority_sector" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_non_priority_sector" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_non_priority_sector"/>
<columnExists tableName="m_client_non_priority_sector" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_non_priority_sector" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_non_priority_sector" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_non_priority_sector" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281f_rename_audit_client_msme" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_msme" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_msme"/>
<columnExists tableName="m_client_msme" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_msme" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_msme" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_msme" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281g_rename_audit_client_mudra_borrower" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_mudra_borrower" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_mudra_borrower"/>
<columnExists tableName="m_client_mudra_borrower" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_mudra_borrower" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_mudra_borrower" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_mudra_borrower" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281h_rename_audit_client_startup_india" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_startup_india" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_startup_india"/>
<columnExists tableName="m_client_startup_india" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_startup_india" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_startup_india" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_startup_india" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
</changeSet>
<changeSet id="0281i_rename_audit_client_eou" author="fineract">
<preConditions onFail="MARK_RAN"><columnExists tableName="m_client_eou" columnName="last_modified_by"/></preConditions>
<preConditions onFail="MARK_RAN">
<and>
<tableExists tableName="m_client_eou"/>
<columnExists tableName="m_client_eou" columnName="last_modified_by"/>
</and>
</preConditions>
<renameColumn tableName="m_client_eou" oldColumnName="last_modified_by" newColumnName="modified_by" columnDataType="bigint"/>
<renameColumn tableName="m_client_eou" oldColumnName="created_on_utc" newColumnName="created_at" columnDataType="datetime"/>
<renameColumn tableName="m_client_eou" oldColumnName="last_modified_on_utc" newColumnName="modified_on" columnDataType="datetime"/>
@@ -1,39 +1,24 @@
<?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
-->
<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">
<!--
Enforce uniqueness on m_appuser.email and m_appuser.mobile_no.
Username is already unique (constraint name 'username_org' from the upstream schema).
Email is NOT NULL in the entity; mobile_no IS nullable. Both PostgreSQL and MySQL allow
multiple NULLs in a UNIQUE constraint, so a plain UNIQUE works for mobile_no — multiple
users with no mobile remain valid.
Note: if your existing data already contains duplicate emails or mobiles, this migration
WILL fail. Dedupe first:
SELECT LOWER(email), COUNT(*) FROM m_appuser GROUP BY LOWER(email) HAVING COUNT(*) > 1;
SELECT mobile_no, COUNT(*) FROM m_appuser WHERE mobile_no IS NOT NULL GROUP BY mobile_no HAVING COUNT(*) > 1;
-->
<changeSet id="0295_add_unique_email_to_m_appuser" author="fineract">
<preConditions onFail="MARK_RAN">
<not>
<indexExists tableName="m_appuser" indexName="uq_m_appuser_email"/>
</not>
<sqlCheck expectedResult="0">
SELECT COUNT(*)
FROM (
SELECT LOWER(email)
FROM m_appuser
WHERE email IS NOT NULL
GROUP BY LOWER(email)
HAVING COUNT(*) &gt; 1
) t
</sqlCheck>
</preConditions>
<addUniqueConstraint tableName="m_appuser" columnNames="email"
constraintName="uq_m_appuser_email"/>
@@ -44,8 +29,17 @@
<not>
<indexExists tableName="m_appuser" indexName="uq_m_appuser_mobile_no"/>
</not>
<sqlCheck expectedResult="0">
SELECT COUNT(*)
FROM (
SELECT mobile_no
FROM m_appuser
WHERE mobile_no IS NOT NULL
GROUP BY mobile_no
HAVING COUNT(*) &gt; 1
) t
</sqlCheck>
</preConditions>
<!-- Drop the plain non-unique index added in 0283 first — the unique constraint replaces it. -->
<dropIndex tableName="m_appuser" indexName="idx_m_appuser_mobile_no"/>
<addUniqueConstraint tableName="m_appuser" columnNames="mobile_no"
constraintName="uq_m_appuser_mobile_no"/>