Add Education Level, Degree, Religion, Social Category & Income fields to Client module

- Migration 0256: EducationLevel & DegreeQualification codes with m_client FK columns
- Migration 0257: Religion & SocialCategory codes with m_client FK columns
- Migration 0258: agriculture_income & non_agriculture_income decimal columns on m_client
- Full API support: create, update, template options, and GET response for all new fields
- Postman collection for testing all new dropdowns

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aditya
2026-04-27 16:31:55 +05:30
co-authored by Claude Opus 4.6
parent b4429d04b0
commit 9fb43ad971
12 changed files with 941 additions and 5 deletions
@@ -76,6 +76,14 @@ public class ClientApiConstants {
public static final String MARITAL_STATUS = "MaritalStatus";
public static final String maritalStatusIdParamName = "maritalStatusId";
public static final String maritalStatusParamName = "maritalStatus";
public static final String EDUCATION_LEVEL = "EducationLevel";
public static final String educationLevelIdParamName = "educationLevelId";
public static final String DEGREE_QUALIFICATION = "DegreeQualification";
public static final String degreeQualificationIdParamName = "degreeQualificationId";
public static final String RELIGION = "Religion";
public static final String religionIdParamName = "religionId";
public static final String SOCIAL_CATEGORY = "SocialCategory";
public static final String socialCategoryIdParamName = "socialCategoryId";
public static final String CLIENT_TYPE_INDIVIDUAL = "Individual";
@@ -125,8 +133,14 @@ public class ClientApiConstants {
public static final String occupationCategoryParamName = "occupationCategory";
public static final String occupationIdParamName = "occupationId";
public static final String occupationParamName = "occupation";
public static final String educationLevelParamName = "educationLevel";
public static final String degreeQualificationParamName = "degreeQualification";
public static final String religionParamName = "religion";
public static final String socialCategoryParamName = "socialCategory";
public static final String monthlyIncomeParamName = "monthlyIncome";
public static final String annualTurnoverParamName = "annualTurnover";
public static final String agricultureIncomeParamName = "agricultureIncome";
public static final String nonAgricultureIncomeParamName = "nonAgricultureIncome";
public static final String ageYearsParamName = "ageYears";
public static final String ageMonthsParamName = "ageMonths";
public static final String ageDaysParamName = "ageDays";
@@ -232,8 +246,11 @@ public class ClientApiConstants {
officeNameParamName, transferToOfficeIdParamName, transferToOfficeNameParamName, hierarchyParamName, imageIdParamName,
imagePresentParamName, staffIdParamName, staffNameParamName, timelineParamName, groupsParamName, officeOptionsParamName,
staffOptionsParamName, dateOfBirthParamName, genderParamName, clientTypeParamName, clientClassificationParamName,
salutationParamName, occupationCategoryParamName, occupationParamName, maritalStatusParamName, monthlyIncomeParamName,
annualTurnoverParamName, ageYearsParamName, ageMonthsParamName, ageDaysParamName,
salutationParamName, occupationCategoryParamName, occupationParamName, maritalStatusParamName,
educationLevelParamName, degreeQualificationParamName,
religionParamName, socialCategoryParamName, monthlyIncomeParamName,
annualTurnoverParamName, agricultureIncomeParamName, nonAgricultureIncomeParamName,
ageYearsParamName, ageMonthsParamName, ageDaysParamName,
nationalityIdParamName, isMinorParamName, guardianClientIdParamName, guardianClientDisplayNameParamName, guardianRelationParamName,
dipVerifiedParamName, dipLookupLogIdParamName, dipTimestampParamName,
alternateMobileNoParamName, alternateDipVerifiedParamName, alternateDipLookupLogIdParamName, alternateDipTimestampParamName,
@@ -77,8 +77,14 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private CodeValueData occupationCategory;
private CodeValueData occupation;
private CodeValueData maritalStatus;
private CodeValueData educationLevel;
private CodeValueData degreeQualification;
private CodeValueData religion;
private CodeValueData socialCategory;
private BigDecimal monthlyIncome;
private BigDecimal annualTurnover;
private BigDecimal agricultureIncome;
private BigDecimal nonAgricultureIncome;
private Integer ageYears;
private Integer ageMonths;
private Integer ageDays;
@@ -130,6 +136,10 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private Collection<CodeValueData> clientClassificationOptions;
private Collection<CodeValueData> occupationCategoryOptions;
private Collection<CodeValueData> occupationOptions;
private Collection<CodeValueData> educationLevelOptions;
private Collection<CodeValueData> degreeQualificationOptions;
private Collection<CodeValueData> religionOptions;
private Collection<CodeValueData> socialCategoryOptions;
private Collection<CodeValueData> clientNonPersonConstitutionOptions;
private Collection<CodeValueData> clientNonPersonMainBusinessLineOptions;
private List<EnumOptionData> clientLegalFormOptions;
@@ -357,6 +367,10 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
data.salutationOptions = salutationOptions;
data.occupationCategoryOptions = occupationCategoryOptions;
data.occupationOptions = occupationOptions;
data.educationLevelOptions = null;
data.degreeQualificationOptions = null;
data.religionOptions = null;
data.socialCategoryOptions = null;
return data;
}
@@ -382,9 +396,19 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
data.occupation = clientData.occupation;
data.occupationCategoryOptions = templateData.occupationCategoryOptions;
data.occupationOptions = templateData.occupationOptions;
data.educationLevelOptions = templateData.educationLevelOptions;
data.degreeQualificationOptions = templateData.degreeQualificationOptions;
data.religionOptions = templateData.religionOptions;
data.socialCategoryOptions = templateData.socialCategoryOptions;
data.maritalStatus = clientData.maritalStatus;
data.educationLevel = clientData.educationLevel;
data.degreeQualification = clientData.degreeQualification;
data.religion = clientData.religion;
data.socialCategory = clientData.socialCategory;
data.monthlyIncome = clientData.monthlyIncome;
data.annualTurnover = clientData.annualTurnover;
data.agricultureIncome = clientData.agricultureIncome;
data.nonAgricultureIncome = clientData.nonAgricultureIncome;
data.ageYears = clientData.ageYears;
data.ageMonths = clientData.ageMonths;
data.ageDays = clientData.ageDays;
@@ -428,9 +452,19 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
data.occupation = clientData.occupation;
data.occupationCategoryOptions = clientData.occupationCategoryOptions;
data.occupationOptions = clientData.occupationOptions;
data.educationLevelOptions = clientData.educationLevelOptions;
data.degreeQualificationOptions = clientData.degreeQualificationOptions;
data.religionOptions = clientData.religionOptions;
data.socialCategoryOptions = clientData.socialCategoryOptions;
data.maritalStatus = clientData.maritalStatus;
data.educationLevel = clientData.educationLevel;
data.degreeQualification = clientData.degreeQualification;
data.religion = clientData.religion;
data.socialCategory = clientData.socialCategory;
data.monthlyIncome = clientData.monthlyIncome;
data.annualTurnover = clientData.annualTurnover;
data.agricultureIncome = clientData.agricultureIncome;
data.nonAgricultureIncome = clientData.nonAgricultureIncome;
data.ageYears = clientData.ageYears;
data.ageMonths = clientData.ageMonths;
data.ageDays = clientData.ageDays;
@@ -470,8 +504,14 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
data.maritalStatus = clientData.maritalStatus;
data.educationLevel = clientData.educationLevel;
data.degreeQualification = clientData.degreeQualification;
data.religion = clientData.religion;
data.socialCategory = clientData.socialCategory;
data.monthlyIncome = clientData.monthlyIncome;
data.annualTurnover = clientData.annualTurnover;
data.agricultureIncome = clientData.agricultureIncome;
data.nonAgricultureIncome = clientData.nonAgricultureIncome;
data.ageYears = clientData.ageYears;
data.ageMonths = clientData.ageMonths;
data.ageDays = clientData.ageDays;
@@ -212,12 +212,34 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@JoinColumn(name = "marital_status_cv_id")
private CodeValue maritalStatus;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "education_level_cv_id")
private CodeValue educationLevel;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "degree_qualification_cv_id")
private CodeValue degreeQualification;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "religion_cv_id")
private CodeValue religion;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "social_category_cv_id")
private CodeValue socialCategory;
@Column(name = "monthly_income")
private java.math.BigDecimal monthlyIncome;
@Column(name = "annual_turnover")
private java.math.BigDecimal annualTurnover;
@Column(name = "agriculture_income")
private java.math.BigDecimal agricultureIncome;
@Column(name = "non_agriculture_income")
private java.math.BigDecimal nonAgricultureIncome;
@Column(name = "nationality", length = 100)
private String nationality;
@@ -782,6 +804,38 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.maritalStatus = maritalStatus;
}
public Long educationLevelId() {
return this.educationLevel != null ? this.educationLevel.getId() : null;
}
public void updateEducationLevel(CodeValue educationLevel) {
this.educationLevel = educationLevel;
}
public Long degreeQualificationId() {
return this.degreeQualification != null ? this.degreeQualification.getId() : null;
}
public void updateDegreeQualification(CodeValue degreeQualification) {
this.degreeQualification = degreeQualification;
}
public Long religionId() {
return this.religion != null ? this.religion.getId() : null;
}
public void updateReligion(CodeValue religion) {
this.religion = religion;
}
public Long socialCategoryId() {
return this.socialCategory != null ? this.socialCategory.getId() : null;
}
public void updateSocialCategory(CodeValue socialCategory) {
this.socialCategory = socialCategory;
}
public void updateGender(CodeValue gender) {
this.gender = gender;
}
@@ -30,7 +30,10 @@ public class ClientApiCollectionConstants extends ClientApiConstants {
alternateMobileNoParamName, emailAddressParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName,
activeParamName, activationDateParamName, staffIdParamName, submittedOnDateParamName, savingsProductIdParamName,
dateOfBirthParamName, genderIdParamName, salutationIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
occupationCategoryIdParamName, occupationIdParamName, maritalStatusIdParamName, monthlyIncomeParamName, annualTurnoverParamName,
occupationCategoryIdParamName, occupationIdParamName, maritalStatusIdParamName,
educationLevelIdParamName, degreeQualificationIdParamName,
religionIdParamName, socialCategoryIdParamName, monthlyIncomeParamName, annualTurnoverParamName,
agricultureIncomeParamName, nonAgricultureIncomeParamName,
ageYearsParamName, ageMonthsParamName, ageDaysParamName,
nationalityIdParamName, isMinorParamName, guardianClientIdParamName, guardianRelationParamName,
dipVerifiedParamName, dipLookupLogIdParamName, dipTimestampParamName,
@@ -49,7 +52,10 @@ public class ClientApiCollectionConstants extends ClientApiConstants {
lastnameParamName, fullnameParamName, activeParamName, activationDateParamName, staffIdParamName, savingsProductIdParamName,
dateOfBirthParamName, genderIdParamName, salutationIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
occupationCategoryIdParamName, occupationIdParamName, maritalStatusIdParamName, monthlyIncomeParamName, annualTurnoverParamName,
occupationCategoryIdParamName, occupationIdParamName, maritalStatusIdParamName,
educationLevelIdParamName, degreeQualificationIdParamName,
religionIdParamName, socialCategoryIdParamName, monthlyIncomeParamName, annualTurnoverParamName,
agricultureIncomeParamName, nonAgricultureIncomeParamName,
ageYearsParamName, ageMonthsParamName, ageDaysParamName,
nationalityIdParamName, isMinorParamName, guardianClientIdParamName, guardianRelationParamName,
dipVerifiedParamName, dipLookupLogIdParamName, dipTimestampParamName,
@@ -61,8 +61,16 @@ public interface ClientMapper {
@Mapping(target = "occupationCategory", source = "source", qualifiedByName = "occupationCategoryCode")
@Mapping(target = "occupation", source = "source", qualifiedByName = "occupationCode")
@Mapping(target = "maritalStatus", source = "source", qualifiedByName = "maritalStatusCode")
@Mapping(target = "educationLevel", source = "source", qualifiedByName = "educationLevelCode")
@Mapping(target = "degreeQualification", source = "source", qualifiedByName = "degreeQualificationCode")
@Mapping(target = "religion", source = "source", qualifiedByName = "religionCode")
@Mapping(target = "socialCategory", source = "source", qualifiedByName = "socialCategoryCode")
@Mapping(target = "occupationCategoryOptions", ignore = true)
@Mapping(target = "occupationOptions", ignore = true)
@Mapping(target = "educationLevelOptions", ignore = true)
@Mapping(target = "degreeQualificationOptions", ignore = true)
@Mapping(target = "religionOptions", ignore = true)
@Mapping(target = "socialCategoryOptions", ignore = true)
@Mapping(target = "legalForm", source = "source", qualifiedByName = "clientLegalFormEnum")
@Mapping(target = "isStaff", source = "source", qualifiedByName = "clientIsStaff")
@Mapping(target = "ageYears", ignore = true)
@@ -152,6 +160,42 @@ public interface ClientMapper {
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("educationLevelCode")
default CodeValueData educationLevelCode(Client client) {
final CodeValue code = client.getEducationLevel();
if (code == null) {
return null;
}
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("degreeQualificationCode")
default CodeValueData degreeQualificationCode(Client client) {
final CodeValue code = client.getDegreeQualification();
if (code == null) {
return null;
}
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("religionCode")
default CodeValueData religionCode(Client client) {
final CodeValue code = client.getReligion();
if (code == null) {
return null;
}
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("socialCategoryCode")
default CodeValueData socialCategoryCode(Client client) {
final CodeValue code = client.getSocialCategory();
if (code == null) {
return null;
}
return CodeValueData.instance(code.getId(), code.getLabel());
}
@Named("clientSubStatusCode")
default CodeValueData clientSubStatusCode(Client client) {
final CodeValue code = client.getSubStatus();
@@ -114,6 +114,18 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead
final List<CodeValueData> occupationOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.OCCUPATION));
final List<CodeValueData> educationLevelOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.EDUCATION_LEVEL));
final List<CodeValueData> degreeQualificationOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.DEGREE_QUALIFICATION));
final List<CodeValueData> religionOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.RELIGION));
final List<CodeValueData> socialCategoryOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.SOCIAL_CATEGORY));
final List<CodeValueData> clientNonPersonConstitutionOptions = new ArrayList<>(
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION));
@@ -125,11 +137,16 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead
final List<DatatableData> datatableTemplates = this.entityDatatableChecksReadService.retrieveTemplates(StatusEnum.CREATE.getValue(),
EntityTables.CLIENT.getName(), null);
return ClientData.template(defaultOfficeId, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), offices, staffOptions, null,
ClientData templateData = ClientData.template(defaultOfficeId, LocalDate.now(DateUtils.getDateTimeZoneOfTenant()), offices, staffOptions, null,
genderOptions, salutationOptions, savingsProductDatas, clientTypeOptions, clientClassificationOptions,
occupationCategoryOptions, occupationOptions, clientNonPersonConstitutionOptions,
clientNonPersonMainBusinessLineOptions, clientLegalFormOptions, familyMemberOptions,
new ArrayList<AddressData>(Arrays.asList(address)), isAddressEnabled, datatableTemplates);
templateData.setEducationLevelOptions(educationLevelOptions);
templateData.setDegreeQualificationOptions(degreeQualificationOptions);
templateData.setReligionOptions(religionOptions);
templateData.setSocialCategoryOptions(socialCategoryOptions);
return templateData;
}
private Long defaultToUsersOfficeIfNull(final Long officeId) {
@@ -264,6 +264,34 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.MARITAL_STATUS, maritalStatusId);
}
CodeValue educationLevel = null;
final Long educationLevelId = command.longValueOfParameterNamed(ClientApiConstants.educationLevelIdParamName);
if (educationLevelId != null) {
educationLevel = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.EDUCATION_LEVEL, educationLevelId);
}
CodeValue degreeQualification = null;
final Long degreeQualificationId = command.longValueOfParameterNamed(ClientApiConstants.degreeQualificationIdParamName);
if (degreeQualificationId != null) {
degreeQualification = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.DEGREE_QUALIFICATION, degreeQualificationId);
}
CodeValue religion = null;
final Long religionId = command.longValueOfParameterNamed(ClientApiConstants.religionIdParamName);
if (religionId != null) {
religion = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.RELIGION, religionId);
}
CodeValue socialCategory = null;
final Long socialCategoryId = command.longValueOfParameterNamed(ClientApiConstants.socialCategoryIdParamName);
if (socialCategoryId != null) {
socialCategory = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.SOCIAL_CATEGORY, socialCategoryId);
}
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
if (savingsProductId != null) {
this.savingsProductRepository.findById(savingsProductId)
@@ -335,10 +363,36 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
newClient.setAnnualTurnover(annualTurnover);
}
final java.math.BigDecimal agricultureIncome = command.bigDecimalValueOfParameterNamed(ClientApiConstants.agricultureIncomeParamName);
if (agricultureIncome != null) {
newClient.setAgricultureIncome(agricultureIncome);
}
final java.math.BigDecimal nonAgricultureIncome = command.bigDecimalValueOfParameterNamed(ClientApiConstants.nonAgricultureIncomeParamName);
if (nonAgricultureIncome != null) {
newClient.setNonAgricultureIncome(nonAgricultureIncome);
}
if (maritalStatus != null) {
newClient.setMaritalStatus(maritalStatus);
}
if (educationLevel != null) {
newClient.setEducationLevel(educationLevel);
}
if (degreeQualification != null) {
newClient.setDegreeQualification(degreeQualification);
}
if (religion != null) {
newClient.setReligion(religion);
}
if (socialCategory != null) {
newClient.setSocialCategory(socialCategory);
}
final String nationality = command.stringValueOfParameterNamed(ClientApiConstants.nationalityIdParamName);
if (nationality != null) {
newClient.setNationality(nationality);
@@ -688,6 +742,30 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
changes.put(ClientApiConstants.maritalStatusIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.educationLevelIdParamName,
clientForUpdate.educationLevelId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.educationLevelIdParamName);
changes.put(ClientApiConstants.educationLevelIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.degreeQualificationIdParamName,
clientForUpdate.degreeQualificationId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.degreeQualificationIdParamName);
changes.put(ClientApiConstants.degreeQualificationIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.religionIdParamName,
clientForUpdate.religionId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.religionIdParamName);
changes.put(ClientApiConstants.religionIdParamName, newValue);
}
if (command.isChangeInLongParameterNamed(ClientApiConstants.socialCategoryIdParamName,
clientForUpdate.socialCategoryId())) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.socialCategoryIdParamName);
changes.put(ClientApiConstants.socialCategoryIdParamName, newValue);
}
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.monthlyIncomeParamName, clientForUpdate.getMonthlyIncome())) {
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.monthlyIncomeParamName);
changes.put(ClientApiConstants.monthlyIncomeParamName, newValue);
@@ -700,6 +778,18 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
clientForUpdate.setAnnualTurnover(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.agricultureIncomeParamName, clientForUpdate.getAgricultureIncome())) {
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.agricultureIncomeParamName);
changes.put(ClientApiConstants.agricultureIncomeParamName, newValue);
clientForUpdate.setAgricultureIncome(newValue);
}
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.nonAgricultureIncomeParamName, clientForUpdate.getNonAgricultureIncome())) {
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.nonAgricultureIncomeParamName);
changes.put(ClientApiConstants.nonAgricultureIncomeParamName, newValue);
clientForUpdate.setNonAgricultureIncome(newValue);
}
if (command.isChangeInStringParameterNamed(ClientApiConstants.nationalityIdParamName, clientForUpdate.getNationality())) {
final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.nationalityIdParamName);
changes.put(ClientApiConstants.nationalityIdParamName, newValue);
@@ -938,6 +1028,46 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
clientForUpdate.updateMaritalStatus(newCodeVal);
}
if (changes.containsKey(ClientApiConstants.educationLevelIdParamName)) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.educationLevelIdParamName);
CodeValue newCodeVal = null;
if (newValue != null) {
newCodeVal = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.EDUCATION_LEVEL, newValue);
}
clientForUpdate.updateEducationLevel(newCodeVal);
}
if (changes.containsKey(ClientApiConstants.degreeQualificationIdParamName)) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.degreeQualificationIdParamName);
CodeValue newCodeVal = null;
if (newValue != null) {
newCodeVal = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.DEGREE_QUALIFICATION, newValue);
}
clientForUpdate.updateDegreeQualification(newCodeVal);
}
if (changes.containsKey(ClientApiConstants.religionIdParamName)) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.religionIdParamName);
CodeValue newCodeVal = null;
if (newValue != null) {
newCodeVal = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.RELIGION, newValue);
}
clientForUpdate.updateReligion(newCodeVal);
}
if (changes.containsKey(ClientApiConstants.socialCategoryIdParamName)) {
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.socialCategoryIdParamName);
CodeValue newCodeVal = null;
if (newValue != null) {
newCodeVal = this.codeValueRepository
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.SOCIAL_CATEGORY, newValue);
}
clientForUpdate.updateSocialCategory(newCodeVal);
}
if (!changes.isEmpty()) {
this.clientRepository.saveAndFlush(clientForUpdate);
}
@@ -274,4 +274,7 @@
<include file="parts/0253_add_ckyc_batch_table.xml" relativeToChangelogFile="true"/>
<include file="parts/0254_fix_ckyc_batch_audit_columns.xml" relativeToChangelogFile="true"/>
<include file="parts/0255_add_ckyc_batch_id_to_client_kyc.xml" relativeToChangelogFile="true"/>
<include file="parts/0256_add_education_level_degree_codes.xml" relativeToChangelogFile="true"/>
<include file="parts/0257_add_religion_social_category_codes.xml" relativeToChangelogFile="true"/>
<include file="parts/0258_add_agriculture_non_agriculture_income.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,139 @@
<?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.3.xsd">
<!-- ==================== EducationLevel code ==================== -->
<changeSet id="0256_01_insert_education_level_code" author="fineract">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'EducationLevel', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'EducationLevel');
</sql>
</changeSet>
<changeSet id="0256_02_insert_education_level_values" author="fineract">
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c
CROSS JOIN (
VALUES
('School', 1),
('Undergraduate', 2),
('Postgraduate', 3),
('Doctorate / Professional', 4)
) AS v(code_value, order_position)
WHERE c.code_name = 'EducationLevel'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
<!-- ==================== DegreeQualification code ==================== -->
<changeSet id="0256_03_insert_degree_qualification_code" author="fineract">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'DegreeQualification', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'DegreeQualification');
</sql>
</changeSet>
<changeSet id="0256_04_insert_degree_qualification_values" author="fineract">
<sql>
INSERT INTO m_code_value (code_id, code_value, code_description, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.code_description, v.order_position, true, false
FROM m_code c
CROSS JOIN (
VALUES
('Below 10th', 'School', 1),
('10th / SSC / Matriculation', 'School', 2),
('12th / HSC / Intermediate', 'School', 3),
('Diploma', 'School', 4),
('ITI', 'School', 5),
('B.A. (Bachelor of Arts)', 'Undergraduate', 6),
('B.Sc. (Bachelor of Science)', 'Undergraduate', 7),
('B.Com. (Bachelor of Commerce)', 'Undergraduate', 8),
('BBA (Business Administration)', 'Undergraduate', 9),
('BCA (Computer Applications)', 'Undergraduate', 10),
('B.Tech / B.E. (Engineering)', 'Undergraduate', 11),
('B.Ed. (Education)', 'Undergraduate', 12),
('LLB (Laws)', 'Undergraduate', 13),
('MBBS', 'Undergraduate', 14),
('BDS', 'Undergraduate', 15),
('BAMS', 'Undergraduate', 16),
('BHMS', 'Undergraduate', 17),
('B.Pharm', 'Undergraduate', 18),
('B.Arch', 'Undergraduate', 19),
('BFA (Fine Arts)', 'Undergraduate', 20),
('BHM (Hotel Management)', 'Undergraduate', 21),
('B.Sc. Nursing', 'Undergraduate', 22),
('Other UG', 'Undergraduate', 23),
('M.A. (Master of Arts)', 'Postgraduate', 24),
('M.Sc. (Master of Science)', 'Postgraduate', 25),
('M.Com. (Master of Commerce)', 'Postgraduate', 26),
('MBA (Business Administration)', 'Postgraduate', 27),
('MCA (Computer Applications)', 'Postgraduate', 28),
('M.Tech / M.E. (Engineering)', 'Postgraduate', 29),
('M.Ed. (Education)', 'Postgraduate', 30),
('LLM (Laws)', 'Postgraduate', 31),
('MD (Medicine)', 'Postgraduate', 32),
('MS (Surgery)', 'Postgraduate', 33),
('MDS', 'Postgraduate', 34),
('M.Pharm', 'Postgraduate', 35),
('M.Arch', 'Postgraduate', 36),
('MFA (Fine Arts)', 'Postgraduate', 37),
('MSW (Social Work)', 'Postgraduate', 38),
('Other PG', 'Postgraduate', 39),
('Ph.D. (Doctor of Philosophy)', 'Doctorate / Professional', 40),
('D.Litt.', 'Doctorate / Professional', 41),
('D.Sc.', 'Doctorate / Professional', 42),
('CA (Chartered Accountant)', 'Doctorate / Professional', 43),
('CS (Company Secretary)', 'Doctorate / Professional', 44),
('CMA (Cost &amp; Mgmt Accountant)', 'Doctorate / Professional', 45),
('CFA', 'Doctorate / Professional', 46),
('Other Professional', 'Doctorate / Professional', 47)
) AS v(code_value, code_description, order_position)
WHERE c.code_name = 'DegreeQualification'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
<!-- ==================== Add columns to m_client ==================== -->
<changeSet id="0256_05_add_education_columns_to_client" author="fineract">
<addColumn tableName="m_client">
<column name="education_level_cv_id" type="BIGINT"/>
<column name="degree_qualification_cv_id" type="BIGINT"/>
</addColumn>
<addForeignKeyConstraint baseTableName="m_client" baseColumnNames="education_level_cv_id"
constraintName="fk_client_education_level_cv"
referencedTableName="m_code_value" referencedColumnNames="id"/>
<addForeignKeyConstraint baseTableName="m_client" baseColumnNames="degree_qualification_cv_id"
constraintName="fk_client_degree_qualification_cv"
referencedTableName="m_code_value" referencedColumnNames="id"/>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,99 @@
<?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.3.xsd">
<!-- ==================== Religion code ==================== -->
<changeSet id="0257_01_insert_religion_code" author="fineract">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'Religion', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'Religion');
</sql>
</changeSet>
<changeSet id="0257_02_insert_religion_values" author="fineract">
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c
CROSS JOIN (
VALUES
('Hindu', 1),
('Muslim', 2),
('Sikh', 3),
('Christian', 4),
('Jain', 5),
('Buddhist', 6),
('Others', 7)
) AS v(code_value, order_position)
WHERE c.code_name = 'Religion'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
<!-- ==================== SocialCategory code ==================== -->
<changeSet id="0257_03_insert_social_category_code" author="fineract">
<sql>
INSERT INTO m_code (code_name, is_system_defined)
SELECT 'SocialCategory', false
WHERE NOT EXISTS (SELECT 1 FROM m_code WHERE code_name = 'SocialCategory');
</sql>
</changeSet>
<changeSet id="0257_04_insert_social_category_values" author="fineract">
<sql>
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
SELECT c.id, v.code_value, v.order_position, true, false
FROM m_code c
CROSS JOIN (
VALUES
('General', 1),
('OBC', 2),
('SC', 3),
('ST', 4)
) AS v(code_value, order_position)
WHERE c.code_name = 'SocialCategory'
AND NOT EXISTS (
SELECT 1 FROM m_code_value cv
WHERE cv.code_id = c.id AND cv.code_value = v.code_value
);
</sql>
</changeSet>
<!-- ==================== Add columns to m_client ==================== -->
<changeSet id="0257_05_add_religion_social_category_columns_to_client" author="fineract">
<addColumn tableName="m_client">
<column name="religion_cv_id" type="BIGINT"/>
<column name="social_category_cv_id" type="BIGINT"/>
</addColumn>
<addForeignKeyConstraint baseTableName="m_client" baseColumnNames="religion_cv_id"
constraintName="fk_client_religion_cv"
referencedTableName="m_code_value" referencedColumnNames="id"/>
<addForeignKeyConstraint baseTableName="m_client" baseColumnNames="social_category_cv_id"
constraintName="fk_client_social_category_cv"
referencedTableName="m_code_value" referencedColumnNames="id"/>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,31 @@
<?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.3.xsd">
<changeSet id="0258_01_add_agriculture_non_agriculture_income" author="fineract">
<addColumn tableName="m_client">
<column name="agriculture_income" type="DECIMAL(19,6)"/>
<column name="non_agriculture_income" type="DECIMAL(19,6)"/>
</addColumn>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,356 @@
{
"info": {
"name": "Education, Religion & Social Category",
"description": "Postman collection for Education Level, Degree/Qualification, Religion and Social Category dropdowns in Client registration.\n\nWorkflow:\n1. Get all codes to find code IDs\n2. Get code values for each to populate dropdowns\n3. Create/Update client with all dropdown IDs",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"variable": [
{
"key": "base_url",
"value": "https://localhost:8443/fineract-provider/api/v1"
},
{
"key": "tenant_id",
"value": "default"
},
{
"key": "username",
"value": "mifos"
},
{
"key": "password",
"value": "password"
}
],
"auth": {
"type": "basic",
"basic": [
{ "key": "username", "value": "{{username}}" },
{ "key": "password", "value": "{{password}}" }
]
},
"item": [
{
"name": "1. Get All Codes",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/codes",
"host": ["{{base_url}}"],
"path": ["codes"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"var codeMap = {",
" 'EducationLevel': 'education_level_code_id',",
" 'DegreeQualification': 'degree_qualification_code_id',",
" 'Religion': 'religion_code_id',",
" 'SocialCategory': 'social_category_code_id'",
"};",
"jsonData.forEach(function(code) {",
" if (codeMap[code.name]) {",
" pm.collectionVariables.set(codeMap[code.name], code.id);",
" console.log(code.name + ' code id: ' + code.id);",
" }",
"});",
"Object.keys(codeMap).forEach(function(name) {",
" pm.test(name + ' code exists', function () {",
" pm.expect(pm.collectionVariables.get(codeMap[name])).to.not.be.undefined;",
" });",
"});"
],
"type": "text/javascript"
}
}
]
},
{
"name": "2. Get Education Level Code Values",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/codes/{{education_level_code_id}}/codevalues",
"host": ["{{base_url}}"],
"path": ["codes", "{{education_level_code_id}}", "codevalues"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"pm.test('Education Level values returned', function () {",
" pm.expect(jsonData.length).to.be.greaterThan(0);",
"});",
"console.log('Education Level options:');",
"jsonData.forEach(function(v) {",
" console.log(' id=' + v.id + ' name=' + v.name);",
"});",
"if (jsonData.length > 0) {",
" pm.collectionVariables.set('sample_education_level_id', jsonData[0].id);",
"}"
],
"type": "text/javascript"
}
}
]
},
{
"name": "3. Get Degree Qualification Code Values",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/codes/{{degree_qualification_code_id}}/codevalues",
"host": ["{{base_url}}"],
"path": ["codes", "{{degree_qualification_code_id}}", "codevalues"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"pm.test('Degree Qualification values returned', function () {",
" pm.expect(jsonData.length).to.be.greaterThan(0);",
"});",
"console.log('Degree/Qualification options:');",
"jsonData.forEach(function(v) {",
" console.log(' id=' + v.id + ' name=' + v.name + ' description=' + v.description);",
"});",
"if (jsonData.length > 0) {",
" pm.collectionVariables.set('sample_degree_qualification_id', jsonData[0].id);",
"}"
],
"type": "text/javascript"
}
}
]
},
{
"name": "4. Get Religion Code Values",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/codes/{{religion_code_id}}/codevalues",
"host": ["{{base_url}}"],
"path": ["codes", "{{religion_code_id}}", "codevalues"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"pm.test('Religion values returned', function () {",
" pm.expect(jsonData.length).to.be.greaterThan(0);",
"});",
"console.log('Religion options:');",
"jsonData.forEach(function(v) {",
" console.log(' id=' + v.id + ' name=' + v.name);",
"});",
"if (jsonData.length > 0) {",
" pm.collectionVariables.set('sample_religion_id', jsonData[0].id);",
"}"
],
"type": "text/javascript"
}
}
]
},
{
"name": "5. Get Social Category Code Values",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/codes/{{social_category_code_id}}/codevalues",
"host": ["{{base_url}}"],
"path": ["codes", "{{social_category_code_id}}", "codevalues"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"pm.test('Social Category values returned', function () {",
" pm.expect(jsonData.length).to.be.greaterThan(0);",
"});",
"console.log('Social Category options:');",
"jsonData.forEach(function(v) {",
" console.log(' id=' + v.id + ' name=' + v.name);",
"});",
"if (jsonData.length > 0) {",
" pm.collectionVariables.set('sample_social_category_id', jsonData[0].id);",
"}"
],
"type": "text/javascript"
}
}
]
},
{
"name": "6. Get Client Template (with all dropdown options)",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/clients/template",
"host": ["{{base_url}}"],
"path": ["clients", "template"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"['educationLevelOptions', 'degreeQualificationOptions', 'religionOptions', 'socialCategoryOptions'].forEach(function(opt) {",
" pm.test(opt + ' present in template', function () {",
" pm.expect(jsonData).to.have.property(opt);",
" });",
" console.log(opt + ':', JSON.stringify(jsonData[opt]));",
"});"
],
"type": "text/javascript"
}
}
]
},
{
"name": "7. Create Client with all dropdown fields",
"request": {
"method": "POST",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "{\n \"officeId\": 1,\n \"firstname\": \"Dropdown\",\n \"lastname\": \"Test Client\",\n \"active\": true,\n \"activationDate\": \"20 April 2026\",\n \"dateFormat\": \"dd MMMM yyyy\",\n \"locale\": \"en\",\n \"legalFormId\": 1,\n \"educationLevelId\": {{sample_education_level_id}},\n \"degreeQualificationId\": {{sample_degree_qualification_id}},\n \"religionId\": {{sample_religion_id}},\n \"socialCategoryId\": {{sample_social_category_id}}\n}"
},
"url": {
"raw": "{{base_url}}/clients",
"host": ["{{base_url}}"],
"path": ["clients"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"pm.test('Client created successfully', function () {",
" pm.expect(pm.response.code).to.equal(200);",
" pm.expect(jsonData.clientId).to.not.be.undefined;",
"});",
"if (jsonData.clientId) {",
" pm.collectionVariables.set('created_client_id', jsonData.clientId);",
" console.log('Created client id: ' + jsonData.clientId);",
"}"
],
"type": "text/javascript"
}
}
]
},
{
"name": "8. Get Client (verify all dropdown fields)",
"request": {
"method": "GET",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"url": {
"raw": "{{base_url}}/clients/{{created_client_id}}",
"host": ["{{base_url}}"],
"path": ["clients", "{{created_client_id}}"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"var jsonData = pm.response.json();",
"['educationLevel', 'degreeQualification', 'religion', 'socialCategory'].forEach(function(field) {",
" pm.test(field + ' present in response', function () {",
" pm.expect(jsonData).to.have.property(field);",
" pm.expect(jsonData[field]).to.not.be.null;",
" });",
" console.log(field + ':', JSON.stringify(jsonData[field]));",
"});"
],
"type": "text/javascript"
}
}
]
},
{
"name": "9. Update Client dropdown fields",
"request": {
"method": "PUT",
"header": [
{ "key": "Fineract-Platform-TenantId", "value": "{{tenant_id}}" },
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "{\n \"educationLevelId\": {{sample_education_level_id}},\n \"degreeQualificationId\": {{sample_degree_qualification_id}},\n \"religionId\": {{sample_religion_id}},\n \"socialCategoryId\": {{sample_social_category_id}}\n}"
},
"url": {
"raw": "{{base_url}}/clients/{{created_client_id}}",
"host": ["{{base_url}}"],
"path": ["clients", "{{created_client_id}}"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('Client updated successfully', function () {",
" pm.expect(pm.response.code).to.equal(200);",
"});"
],
"type": "text/javascript"
}
}
]
}
]
}