Add CIF number, Occupation Category & Occupation fields to Client module

- Added mandatory unique CIF number (auto-generated as CIF+padded ID)
- Added Occupation Category dropdown (6 categories: Salaried, Business, Professional, Agriculture, Student, Others)
- Added Occupation dropdown (54 occupations mapped to categories)
- Both stored in m_code/m_code_value tables (same pattern as Gender)
- Visible in client create/update API and personal data view
- Includes Liquibase migrations 0227 & 0228
- Added Postman collection for User Management APIs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-03-20 18:51:26 +05:30
co-authored by Claude Opus 4.6
parent ba5365d4af
commit 90c21d40c1
12 changed files with 1116 additions and 75 deletions
@@ -26,10 +26,11 @@ import org.apache.fineract.portfolio.client.api.ClientApiConstants;
public class ClientApiCollectionConstants extends ClientApiConstants {
protected static final Set<String> CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(familyMembers, address,
localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, mobileNoParamName,
localeParamName, dateFormatParamName, groupIdParamName, accountNoParamName, cifNumberParamName, externalIdParamName, mobileNoParamName,
emailAddressParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName,
activeParamName, activationDateParamName, staffIdParamName, submittedOnDateParamName, savingsProductIdParamName,
dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
occupationCategoryIdParamName, occupationIdParamName,
clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName, datatables, isStaffParamName, kycParamName));
protected static final Set<String> CLIENT_NON_PERSON_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
@@ -41,8 +42,9 @@ public class ClientApiCollectionConstants extends ClientApiConstants {
middlenameParamName,
lastnameParamName, fullnameParamName, activeParamName, activationDateParamName, staffIdParamName, savingsProductIdParamName,
dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName, submittedOnDateParamName,
clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName, isStaffParamName));
dateOfBirthParamName, genderIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
occupationCategoryIdParamName, occupationIdParamName,
submittedOnDateParamName, clientNonPersonDetailsParamName, displaynameParamName, legalFormIdParamName, isStaffParamName));
protected static final Set<String> CLIENT_NON_PERSON_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(
Arrays.asList(localeParamName, dateFormatParamName, incorpNumberParamName, remarksParamName, incorpValidityTillParamName,
@@ -52,6 +52,10 @@ public interface ClientMapper {
@Mapping(target = "savingsAccountId", source = "savingsAccountId")
@Mapping(target = "clientType", source = "source", qualifiedByName = "clientTypeCode")
@Mapping(target = "clientClassification", source = "source", qualifiedByName = "clientClassificationCode")
@Mapping(target = "occupationCategory", source = "source", qualifiedByName = "occupationCategoryCode")
@Mapping(target = "occupation", source = "source", qualifiedByName = "occupationCode")
@Mapping(target = "occupationCategoryOptions", ignore = true)
@Mapping(target = "occupationOptions", ignore = true)
@Mapping(target = "legalForm", source = "source", qualifiedByName = "clientLegalFormEnum")
@Mapping(target = "isStaff", source = "source", qualifiedByName = "clientIsStaff")
@Mapping(target = "imagePresent", ignore = true)
@@ -100,6 +104,24 @@ public interface ClientMapper {
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("occupationCategoryCode")
default CodeValueData occupationCategoryCode(Client client) {
final CodeValue code = client.getOccupationCategory();
if (code == null) {
return null;
}
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("occupationCode")
default CodeValueData occupationCode(Client client) {
final CodeValue code = client.getOccupation();
if (code == null) {
return null;
}
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("clientSubStatusCode")
default CodeValueData clientSubStatusCode(Client client) {
final CodeValue code = client.getSubStatus();
@@ -296,7 +296,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append(
"c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum,c.sub_status as subStatus, ");
"c.id as id, c.account_no as accountNo, c.cif_number as cifNumber, c.external_id as externalId, c.status_enum as statusEnum,c.sub_status as subStatus, ");
sqlBuilder.append(
"cvSubStatus.code_value as subStatusValue,cvSubStatus.code_description as subStatusDesc,c.office_id as officeId, o.name as officeName, ");
sqlBuilder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, ");
@@ -313,6 +313,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("c.client_classification_cv_id as classificationId, ");
sqlBuilder.append("cvclassification.code_value as classificationValue, ");
sqlBuilder.append("c.legal_form_enum as legalFormEnum, ");
sqlBuilder.append("c.occupation_category_cv_id as occupationCategoryId, ");
sqlBuilder.append("cvOccupationCategory.code_value as occupationCategoryValue, ");
sqlBuilder.append("c.occupation_cv_id as occupationId, ");
sqlBuilder.append("cvOccupation.code_value as occupationValue, ");
sqlBuilder.append("c.activation_date as activationDate, c.image_id as imageId, ");
sqlBuilder.append("c.staff_id as staffId, s.display_name as staffName,");
sqlBuilder.append("c.default_savings_product as savingsProductId, sp.name as savingsProductName, ");
@@ -355,6 +359,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
sqlBuilder.append("left join m_code_value cvclienttype on cvclienttype.id = c.client_type_cv_id ");
sqlBuilder.append("left join m_code_value cvclassification on cvclassification.id = c.client_classification_cv_id ");
sqlBuilder.append("left join m_code_value cvSubStatus on cvSubStatus.id = c.sub_status ");
sqlBuilder.append("left join m_code_value cvOccupationCategory on cvOccupationCategory.id = c.occupation_category_cv_id ");
sqlBuilder.append("left join m_code_value cvOccupation on cvOccupation.id = c.occupation_cv_id ");
sqlBuilder.append("left join m_code_value cvConstitution on cvConstitution.id = cnp.constitution_cv_id ");
sqlBuilder.append("left join m_code_value cvMainBusinessLine on cvMainBusinessLine.id = cnp.main_business_line_cv_id ");
@@ -369,6 +375,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public ClientData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final String accountNo = rs.getString("accountNo");
final String cifNumber = rs.getString("cifNumber");
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
final EnumOptionData status = ClientEnumerations.status(statusEnum);
@@ -438,6 +445,14 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
legalForm = ClientEnumerations.legalForm(legalFormEnum);
}
final Long occupationCategoryId = JdbcSupport.getLong(rs, "occupationCategoryId");
final String occupationCategoryValue = rs.getString("occupationCategoryValue");
final CodeValueData occupationCategory = CodeValueData.instance(occupationCategoryId, occupationCategoryValue);
final Long occupationId = JdbcSupport.getLong(rs, "occupationId");
final String occupationValue = rs.getString("occupationValue");
final CodeValueData occupation = CodeValueData.instance(occupationId, occupationValue);
final Long constitutionId = JdbcSupport.getLong(rs, "constitutionId");
final String constitutionValue = rs.getString("constitutionValue");
final CodeValueData constitution = CodeValueData.instance(constitutionId, constitutionValue);
@@ -455,10 +470,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
submittedByLastname, activationDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate,
closedByUsername, closedByFirstname, closedByLastname);
return ClientData.instance(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id,
firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender,
activationDate, imageId, staffId, staffName, timeline, savingsProductId, savingsProductName, savingsAccountId,
clienttype, classification, legalForm, clientNonPerson, isStaff);
return ClientData.instance(accountNo, cifNumber, status, subStatus, officeId, officeName, transferToOfficeId,
transferToOfficeName, id, firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress,
dateOfBirth, gender, activationDate, imageId, staffId, staffName, timeline, savingsProductId, savingsProductName,
savingsAccountId, clienttype, classification, occupationCategory, occupation, legalForm, clientNonPerson, isStaff);
}
}
@@ -577,7 +592,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions = null;
final List<EnumOptionData> clientLegalFormOptions = null;
return ClientData.template(null, null, null, null, narrations, null, null, clientTypeOptions, clientClassificationOptions,
clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions, null, null, null, null);
null, null, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions, null, null,
null, null);
}
@Override
@@ -609,7 +625,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final StringBuilder builder = new StringBuilder(400);
builder.append(
"c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum,c.sub_status as subStatus, ");
"c.id as id, c.account_no as accountNo, c.cif_number as cifNumber, c.external_id as externalId, c.status_enum as statusEnum,c.sub_status as subStatus, ");
builder.append(
"cvSubStatus.code_value as subStatusValue,cvSubStatus.code_description as subStatusDesc,c.office_id as officeId, o.name as officeName, ");
builder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, ");
@@ -626,6 +642,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
builder.append("c.client_classification_cv_id as classificationId, ");
builder.append("cvclassification.code_value as classificationValue, ");
builder.append("c.legal_form_enum as legalFormEnum, ");
builder.append("c.occupation_category_cv_id as occupationCategoryId, ");
builder.append("cvOccupationCategory.code_value as occupationCategoryValue, ");
builder.append("c.occupation_cv_id as occupationId, ");
builder.append("cvOccupation.code_value as occupationValue, ");
builder.append("c.submittedon_date as submittedOnDate, ");
builder.append("sbu.username as submittedByUsername, ");
@@ -667,6 +687,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
builder.append("left join m_code_value cvclienttype on cvclienttype.id = c.client_type_cv_id ");
builder.append("left join m_code_value cvclassification on cvclassification.id = c.client_classification_cv_id ");
builder.append("left join m_code_value cvSubStatus on cvSubStatus.id = c.sub_status ");
builder.append("left join m_code_value cvOccupationCategory on cvOccupationCategory.id = c.occupation_category_cv_id ");
builder.append("left join m_code_value cvOccupation on cvOccupation.id = c.occupation_cv_id ");
builder.append("left join m_code_value cvConstitution on cvConstitution.id = cnp.constitution_cv_id ");
builder.append("left join m_code_value cvMainBusinessLine on cvMainBusinessLine.id = cnp.main_business_line_cv_id ");
@@ -681,6 +703,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public ClientData mapRow(final ResultSet rs, final int rowNum) throws SQLException {
final String accountNo = rs.getString("accountNo");
final String cifNumber = rs.getString("cifNumber");
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
final EnumOptionData status = ClientEnumerations.status(statusEnum);
@@ -749,6 +772,14 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
legalForm = ClientEnumerations.legalForm(legalFormEnum);
}
final Long occupationCategoryId = JdbcSupport.getLong(rs, "occupationCategoryId");
final String occupationCategoryValue = rs.getString("occupationCategoryValue");
final CodeValueData occupationCategory = CodeValueData.instance(occupationCategoryId, occupationCategoryValue);
final Long occupationId = JdbcSupport.getLong(rs, "occupationId");
final String occupationValue = rs.getString("occupationValue");
final CodeValueData occupation = CodeValueData.instance(occupationId, occupationValue);
final Long constitutionId = JdbcSupport.getLong(rs, "constitutionId");
final String constitutionValue = rs.getString("constitutionValue");
final CodeValueData constitution = CodeValueData.instance(constitutionId, constitutionValue);
@@ -766,10 +797,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
submittedByLastname, activationDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate,
closedByUsername, closedByFirstname, closedByLastname);
return ClientData.instance(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id,
firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender,
activationDate, imageId, staffId, staffName, timeline, savingsProductId, savingsProductName, savingsAccountId,
clienttype, classification, legalForm, clientNonPerson, isStaff);
return ClientData.instance(accountNo, cifNumber, status, subStatus, officeId, officeName, transferToOfficeId,
transferToOfficeName, id, firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress,
dateOfBirth, gender, activationDate, imageId, staffId, staffName, timeline, savingsProductId, savingsProductName,
savingsAccountId, clienttype, classification, occupationCategory, occupation, legalForm, clientNonPerson, isStaff);
}
}
@@ -105,6 +105,12 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead
final List<CodeValueData> clientClassificationOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_CLASSIFICATION));
final List<CodeValueData> occupationCategoryOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.OCCUPATION_CATEGORY));
final List<CodeValueData> occupationOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.OCCUPATION));
final List<CodeValueData> clientNonPersonConstitutionOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION));
@@ -117,9 +123,9 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead
EntityTables.CLIENT.getName(), null);
return ClientData.template(defaultOfficeId, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), offices, staffOptions, null,
genderOptions, savingsProductDatas, clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions,
clientNonPersonMainBusinessLineOptions, clientLegalFormOptions, familyMemberOptions,
new ArrayList<AddressData>(Arrays.asList(address)), isAddressEnabled, datatableTemplates);
genderOptions, savingsProductDatas, clientTypeOptions, clientClassificationOptions, occupationCategoryOptions,
occupationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions, clientLegalFormOptions,
familyMemberOptions, new ArrayList<AddressData>(Arrays.asList(address)), isAddressEnabled, datatableTemplates);
}
private Long defaultToUsersOfficeIfNull(final Long officeId) {
@@ -171,6 +171,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final String accountNo = command.stringValueOfParameterNamed("accountNo");
throw new PlatformDataIntegrityException("error.msg.client.duplicate.accountNo",
"Client with accountNo `" + accountNo + "` already exists", "accountNo", accountNo);
} else if (realCause.getMessage().contains("cif_number_UNIQUE") || realCause.getMessage().contains("cif_number")) {
final String cifNumber = command.stringValueOfParameterNamed("cifNumber");
throw new PlatformDataIntegrityException("error.msg.client.duplicate.cifNumber",
"Client with cifNumber `" + cifNumber + "` already exists", "cifNumber", cifNumber);
} else if (realCause.getMessage().contains("mobile_no")) {
final String mobileNo = command.stringValueOfParameterNamed("mobileNo");
throw new PlatformDataIntegrityException("error.msg.client.duplicate.mobileNo",
@@ -230,6 +234,20 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.CLIENT_CLASSIFICATION, clientClassificationId);
}
CodeValue occupationCategory = null;
final Long occupationCategoryId = command.longValueOfParameterNamed(ClientApiConstants.occupationCategoryIdParamName);
if (occupationCategoryId != null) {
occupationCategory = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.OCCUPATION_CATEGORY, occupationCategoryId);
}
CodeValue occupation = null;
final Long occupationId = command.longValueOfParameterNamed(ClientApiConstants.occupationIdParamName);
if (occupationId != null) {
occupation = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.OCCUPATION, occupationId);
}
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
if (savingsProductId != null) {
this.savingsProductRepository.findById(savingsProductId)
@@ -250,6 +268,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
}
final String accountNo = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName);
final String cifNumber = command.stringValueOfParameterNamed(ClientApiConstants.cifNumberParamName);
final String mobileNo = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName);
final String emailAddress = command.stringValueOfParameterNamed(ClientApiConstants.emailAddressParamName);
final String firstname = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName);
@@ -284,10 +303,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
final ExternalId externalId = externalIdFactory.createFromCommand(command, ClientApiConstants.externalIdParamName);
final Client newClient = Client.instance(currentUser, status, clientOffice, clientParentGroup, accountNo, firstname, middlename,
lastname, fullname, activationDate, officeJoiningDate, externalId, mobileNo, emailAddress, staff, submittedOnDate,
savingsProductId, savingsAccountId, dataOfBirth, gender, clientType, clientClassification, legalForm.getValue(),
isStaff);
final Client newClient = Client.instance(currentUser, status, clientOffice, clientParentGroup, accountNo, cifNumber, firstname,
middlename, lastname, fullname, activationDate, officeJoiningDate, externalId, mobileNo, emailAddress, staff,
submittedOnDate, savingsProductId, savingsAccountId, dataOfBirth, gender, clientType, clientClassification,
occupationCategory, occupation, legalForm.getValue(), isStaff);
// Account Number generation
this.clientRepository.saveAndFlush(newClient);
@@ -297,6 +316,13 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
this.clientRepository.saveAndFlush(newClient);
}
// CIF Number generation - auto-generate with CIF prefix if not provided
if (StringUtils.isBlank(cifNumber)) {
final String generatedCif = "CIF" + StringUtils.leftPad(newClient.getId().toString(), 10, '0');
newClient.updateCifNumber(generatedCif);
this.clientRepository.saveAndFlush(newClient);
}
boolean rollbackTransaction = false;
if (newClient.isActive()) {
validateParentGroupRulesBeforeClientActivation(newClient);
@@ -508,6 +534,17 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
changes.put(ClientApiConstants.clientClassificationIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.occupationCategoryIdParamName,
clientForUpdate.occupationCategoryId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.occupationCategoryIdParamName);
changes.put(ClientApiConstants.occupationCategoryIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.occupationIdParamName, clientForUpdate.occupationId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.occupationIdParamName);
changes.put(ClientApiConstants.occupationIdParamName, newValue);
}
if (command.isChangeInIntegerParameterNamed(ClientApiConstants.legalFormIdParamName, clientForUpdate.getLegalForm())) {
final Integer newValue = command.integerValueOfParameterNamed(ClientApiConstants.legalFormIdParamName);
if (newValue != null) {
@@ -625,6 +662,26 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
clientForUpdate.updateClientClassification(newCodeVal);
}
if (changes.containsKey(ClientApiConstants.occupationCategoryIdParamName)) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.occupationCategoryIdParamName);
CodeValue newCodeVal = null;
if (newValue != null) {
newCodeVal = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.OCCUPATION_CATEGORY, newValue);
}
clientForUpdate.updateOccupationCategory(newCodeVal);
}
if (changes.containsKey(ClientApiConstants.occupationIdParamName)) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.occupationIdParamName);
CodeValue newCodeVal = null;
if (newValue != null) {
newCodeVal = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.OCCUPATION, newValue);
}
clientForUpdate.updateOccupation(newCodeVal);
}
if (!changes.isEmpty()) {
this.clientRepository.saveAndFlush(clientForUpdate);
}
@@ -245,4 +245,6 @@
<include file="parts/0224_add_mobile_lookup_log.xml" relativeToChangelogFile="true"/>
<include file="parts/0225_add_current_account_support.xml" relativeToChangelogFile="true"/>
<include file="parts/0226_add_cfcfrms_tables.xml" relativeToChangelogFile="true"/>
<include file="parts/0227_add_client_cif_number.xml" relativeToChangelogFile="true"/>
<include file="parts/0228_add_occupation_fields.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,58 @@
<?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.13.xsd">
<changeSet author="fineract" id="0227-1">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client" columnName="cif_number"/></not>
</preConditions>
<addColumn tableName="m_client">
<column name="cif_number" type="VARCHAR(20)">
<constraints nullable="true" />
</column>
</addColumn>
</changeSet>
<changeSet author="fineract" id="0227-2">
<preConditions onFail="MARK_RAN">
<columnExists tableName="m_client" columnName="cif_number"/>
</preConditions>
<sql>UPDATE m_client SET cif_number = CONCAT('CIF', LPAD(CAST(id AS VARCHAR), 10, '0')) WHERE cif_number IS NULL</sql>
</changeSet>
<changeSet author="fineract" id="0227-3">
<preConditions onFail="MARK_RAN">
<columnExists tableName="m_client" columnName="cif_number"/>
</preConditions>
<addNotNullConstraint tableName="m_client" columnName="cif_number" columnDataType="VARCHAR(20)" />
</changeSet>
<changeSet author="fineract" id="0227-4">
<preConditions onFail="MARK_RAN">
<not><indexExists indexName="cif_number_UNIQUE"/></not>
</preConditions>
<addUniqueConstraint tableName="m_client" columnNames="cif_number" constraintName="cif_number_UNIQUE" />
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,167 @@
<?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.13.xsd">
<!-- ==================== Add OccupationCategory code ==================== -->
<changeSet author="fineract" id="0228-1">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_code WHERE code_name = 'OccupationCategory'</sqlCheck>
</preConditions>
<insert tableName="m_code">
<column name="code_name" value="OccupationCategory"/>
<column name="is_system_defined" valueBoolean="true"/>
</insert>
</changeSet>
<changeSet author="fineract" id="0228-2">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_code_value WHERE code_id = (SELECT id FROM m_code WHERE code_name = 'OccupationCategory')</sqlCheck>
</preConditions>
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT id, val, pos, true, false FROM m_code
CROSS JOIN (VALUES
('Salaried / Service', 1),
('Business / Self Employed', 2),
('Professional', 3),
('Agriculture', 4),
('Student / Non-Earning', 5),
('Others', 6)
) AS t(val, pos)
WHERE code_name = 'OccupationCategory';
</sql>
</changeSet>
<!-- ==================== Add Occupation code ==================== -->
<changeSet author="fineract" id="0228-3">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_code WHERE code_name = 'Occupation'</sqlCheck>
</preConditions>
<insert tableName="m_code">
<column name="code_name" value="Occupation"/>
<column name="is_system_defined" valueBoolean="true"/>
</insert>
</changeSet>
<changeSet author="fineract" id="0228-4">
<preConditions onFail="MARK_RAN">
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_code_value WHERE code_id = (SELECT id FROM m_code WHERE code_name = 'Occupation')</sqlCheck>
</preConditions>
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT id, val, pos, true, false FROM m_code
CROSS JOIN (VALUES
('Government Employee', 1),
('Public Sector Undertaking (PSU) Employee', 2),
('Private Sector Employee', 3),
('Defence / Armed Forces Personnel', 4),
('Police / Paramilitary', 5),
('Teacher / Professor', 6),
('Doctor (Salaried)', 7),
('Engineer (Salaried)', 8),
('Bank Employee', 9),
('Railway Employee', 10),
('Business Owner / Proprietor', 11),
('Trader / Merchant', 12),
('Manufacturer', 13),
('Contractor', 14),
('Real Estate / Property Dealer', 15),
('Retailer', 16),
('Wholesaler', 17),
('Importer / Exporter', 18),
('Commission Agent', 19),
('Transport / Logistics Owner', 20),
('Doctor (Private Practice)', 21),
('Lawyer / Advocate', 22),
('Chartered Accountant', 23),
('Company Secretary', 24),
('Architect', 25),
('Consultant', 26),
('Engineer (Self Employed)', 27),
('IT Professional / Freelancer', 28),
('Financial Advisor', 29),
('Auditor', 30),
('Farmer (Own Land)', 31),
('Tenant Farmer', 32),
('Agricultural Labourer', 33),
('Horticulture / Floriculture', 34),
('Dairy / Animal Husbandry', 35),
('Fisherman', 36),
('Poultry Farmer', 37),
('Agri Allied Activities', 38),
('Student', 39),
('Housewife / Homemaker', 40),
('Dependent / Minor', 41),
('Unemployed', 42),
('Retired (Pension)', 43),
('Retired (Non-Pension)', 44),
('NRI (Non-Resident Indian)', 45),
('PIO / OCI', 46),
('Politician / Elected Representative', 47),
('Religious / Trust Worker', 48),
('NGO / Social Worker', 49),
('Artisan / Craftsman', 50),
('Labourer / Daily Wage', 51),
('Domestic Worker', 52),
('Driver / Operator', 53),
('Others', 54)
) AS t(val, pos)
WHERE code_name = 'Occupation';
</sql>
</changeSet>
<!-- ==================== Add columns to m_client table ==================== -->
<changeSet author="fineract" id="0228-5">
<preConditions onFail="MARK_RAN">
<not><columnExists tableName="m_client" columnName="occupation_category_cv_id"/></not>
</preConditions>
<addColumn tableName="m_client">
<column name="occupation_category_cv_id" type="BIGINT">
<constraints nullable="true" />
</column>
<column name="occupation_cv_id" type="BIGINT">
<constraints nullable="true" />
</column>
</addColumn>
</changeSet>
<changeSet author="fineract" id="0228-6">
<preConditions onFail="MARK_RAN">
<not><foreignKeyConstraintExists foreignKeyName="FK_m_client_occupation_category_cv_id"/></not>
</preConditions>
<addForeignKeyConstraint baseTableName="m_client" baseColumnNames="occupation_category_cv_id"
referencedTableName="m_code_value" referencedColumnNames="id"
constraintName="FK_m_client_occupation_category_cv_id" />
</changeSet>
<changeSet author="fineract" id="0228-7">
<preConditions onFail="MARK_RAN">
<not><foreignKeyConstraintExists foreignKeyName="FK_m_client_occupation_cv_id"/></not>
</preConditions>
<addForeignKeyConstraint baseTableName="m_client" baseColumnNames="occupation_cv_id"
referencedTableName="m_code_value" referencedColumnNames="id"
constraintName="FK_m_client_occupation_cv_id" />
</changeSet>
</databaseChangeLog>