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
@@ -0,0 +1,607 @@
{
"info": {
"_postman_id": "user-mgmt-collection",
"name": "Fineract - User Management",
"description": "Fineract User Management APIs - Login, Create, Update, Change Password, Delete Users",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"auth": {
"type": "basic",
"basic": [
{
"key": "username",
"value": "{{username}}",
"type": "string"
},
{
"key": "password",
"value": "{{password}}",
"type": "string"
}
]
},
"variable": [
{
"key": "baseUrl",
"value": "https://localhost:8443/fineract-provider/api"
},
{
"key": "username",
"value": "mifos"
},
{
"key": "password",
"value": "password"
},
{
"key": "tenantId",
"value": "default"
},
{
"key": "userId",
"value": "1"
}
],
"item": [
{
"name": "Authentication",
"item": [
{
"name": "Login (Self-Service)",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"mifos\",\n \"password\": \"password\"\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/self/authentication?returnClientList=true",
"host": ["{{baseUrl}}"],
"path": ["v1", "self", "authentication"],
"query": [
{
"key": "returnClientList",
"value": "true"
}
]
},
"description": "Authenticates a user and returns auth token. Use this for self-service users."
}
},
{
"name": "Login (Basic Auth Test)",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/users/1",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "1"]
},
"description": "Test basic auth by fetching user details. If credentials are correct, you'll get a 200 response."
}
}
]
},
{
"name": "Users",
"item": [
{
"name": "Get All Users",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/users",
"host": ["{{baseUrl}}"],
"path": ["v1", "users"]
}
}
},
{
"name": "Get User by ID",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/users/{{userId}}",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "{{userId}}"]
}
}
},
{
"name": "Get User Template",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/users/template",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "template"]
},
"description": "Returns template data (available offices, roles) needed to create a new user."
}
},
{
"name": "Create User",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"newuser\",\n \"firstname\": \"New\",\n \"lastname\": \"User\",\n \"email\": \"newuser@example.com\",\n \"officeId\": 1,\n \"roles\": [1],\n \"sendPasswordToEmail\": false,\n \"password\": \"Password@123\",\n \"repeatPassword\": \"Password@123\",\n \"isSelfServiceUser\": false,\n \"passwordNeverExpires\": true\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/users",
"host": ["{{baseUrl}}"],
"path": ["v1", "users"]
}
}
},
{
"name": "Update User (Change Username)",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"updatedUsername\"\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/users/{{userId}}",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "{{userId}}"]
}
}
},
{
"name": "Update User (Change Password via PUT)",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"password\": \"NewPassword@123\",\n \"repeatPassword\": \"NewPassword@123\"\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/users/{{userId}}",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "{{userId}}"]
}
}
},
{
"name": "Change Password (Dedicated Endpoint)",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"password\": \"NewPassword@123\",\n \"repeatPassword\": \"NewPassword@123\"\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/users/{{userId}}/pwd",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "{{userId}}", "pwd"]
},
"description": "Dedicated password change endpoint. Must provide both password and repeatPassword."
}
},
{
"name": "Update User (Full Update)",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"updatedUser\",\n \"firstname\": \"Updated\",\n \"lastname\": \"User\",\n \"email\": \"updated@example.com\",\n \"officeId\": 1,\n \"roles\": [1],\n \"password\": \"NewPassword@123\",\n \"repeatPassword\": \"NewPassword@123\",\n \"passwordNeverExpires\": true\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/users/{{userId}}",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "{{userId}}"]
}
}
},
{
"name": "Delete User",
"request": {
"method": "DELETE",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/users/{{userId}}",
"host": ["{{baseUrl}}"],
"path": ["v1", "users", "{{userId}}"]
}
}
}
]
},
{
"name": "Roles",
"item": [
{
"name": "Get All Roles",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/roles",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles"]
}
}
},
{
"name": "Get Role by ID",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/roles/1",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1"]
}
}
},
{
"name": "Get Role Permissions",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/roles/1/permissions",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1", "permissions"]
}
}
},
{
"name": "Create Role",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"New Role\",\n \"description\": \"A new custom role\"\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/roles",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles"]
}
}
},
{
"name": "Update Role",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Updated Role\",\n \"description\": \"Updated description\"\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/roles/1",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1"]
}
}
},
{
"name": "Update Role Permissions",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"permissions\": {\n \"READ_USER\": true,\n \"CREATE_USER\": true,\n \"UPDATE_USER\": true\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/roles/1/permissions",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1", "permissions"]
}
}
},
{
"name": "Enable Role",
"request": {
"method": "POST",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/roles/1?command=enable",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1"],
"query": [
{
"key": "command",
"value": "enable"
}
]
}
}
},
{
"name": "Disable Role",
"request": {
"method": "POST",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/roles/1?command=disable",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1"],
"query": [
{
"key": "command",
"value": "disable"
}
]
}
}
},
{
"name": "Delete Role",
"request": {
"method": "DELETE",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/roles/1",
"host": ["{{baseUrl}}"],
"path": ["v1", "roles", "1"]
}
}
}
]
},
{
"name": "Password Preferences",
"item": [
{
"name": "Get Password Preferences",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/passwordpreferences",
"host": ["{{baseUrl}}"],
"path": ["v1", "passwordpreferences"]
}
}
},
{
"name": "Get Password Preferences Template",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/passwordpreferences/template",
"host": ["{{baseUrl}}"],
"path": ["v1", "passwordpreferences", "template"]
}
}
},
{
"name": "Update Password Preferences",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"validationPolicyId\": 2\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/passwordpreferences",
"host": ["{{baseUrl}}"],
"path": ["v1", "passwordpreferences"]
}
}
}
]
},
{
"name": "Permissions",
"item": [
{
"name": "Get All Permissions",
"request": {
"method": "GET",
"header": [
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"url": {
"raw": "{{baseUrl}}/v1/permissions",
"host": ["{{baseUrl}}"],
"path": ["v1", "permissions"]
}
}
},
{
"name": "Update Permissions (Maker-Checker)",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
},
{
"key": "fineract-platform-tenantid",
"value": "{{tenantId}}"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"permissions\": {\n \"CREATE_USER_MAKER\": true,\n \"CREATE_USER_CHECKER\": true\n }\n}"
},
"url": {
"raw": "{{baseUrl}}/v1/permissions",
"host": ["{{baseUrl}}"],
"path": ["v1", "permissions"]
}
}
}
]
}
]
}
@@ -61,6 +61,9 @@ public class ClientApiConstants {
public static final String CLIENT_TYPE = "ClientType";
public static final String CLIENT_CLASSIFICATION = "ClientClassification";
public static final String OCCUPATION_CATEGORY = "OccupationCategory";
public static final String OCCUPATION = "Occupation";
public static final String CLIENT_NON_PERSON_CONSTITUTION = "Constitution";
public static final String CLIENT_NON_PERSON_MAIN_BUSINESS_LINE = "Main Business Line";
@@ -78,6 +81,7 @@ public class ClientApiConstants {
public static final String idParamName = "id";
public static final String groupIdParamName = "groupId";
public static final String accountNoParamName = "accountNo";
public static final String cifNumberParamName = "cifNumber";
public static final String externalIdParamName = "externalId";
public static final String mobileNoParamName = "mobileNo";
public static final String emailAddressParamName = "emailAddress";
@@ -112,6 +116,10 @@ public class ClientApiConstants {
public static final String clientTypeParamName = "clientType";
public static final String clientClassificationIdParamName = "clientClassificationId";
public static final String clientClassificationParamName = "clientClassification";
public static final String occupationCategoryIdParamName = "occupationCategoryId";
public static final String occupationCategoryParamName = "occupationCategory";
public static final String occupationIdParamName = "occupationId";
public static final String occupationParamName = "occupation";
public static final String legalFormIdParamName = "legalFormId";
public static final String legalFormParamName = "legalForm";
// request parameters for payment details
@@ -193,11 +201,12 @@ public class ClientApiConstants {
* parameters to match those of request parameters.
*/
protected static final Set<String> CLIENT_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, accountNoParamName,
externalIdParamName, statusParamName, activeParamName, activationDateParamName, firstnameParamName, middlenameParamName,
cifNumberParamName, externalIdParamName, statusParamName, activeParamName, activationDateParamName, firstnameParamName, middlenameParamName,
lastnameParamName, fullnameParamName, displayNameParamName, mobileNoParamName, emailAddressParamName, officeIdParamName,
officeNameParamName, transferToOfficeIdParamName, transferToOfficeNameParamName, hierarchyParamName, imageIdParamName,
imagePresentParamName, staffIdParamName, staffNameParamName, timelineParamName, groupsParamName, officeOptionsParamName,
staffOptionsParamName, dateOfBirthParamName, genderParamName, clientTypeParamName, clientClassificationParamName,
occupationCategoryParamName, occupationParamName,
legalFormParamName, clientNonPersonDetailsParamName, isStaffParamName, legalFormParamName));
protected static final Set<String> CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(chargeIdParamName,
@@ -51,6 +51,7 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private Long id;
private String accountNo;
private String cifNumber;
private ExternalId externalId;
private EnumOptionData status;
@@ -70,6 +71,8 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private CodeValueData gender;
private CodeValueData clientType;
private CodeValueData clientClassification;
private CodeValueData occupationCategory;
private CodeValueData occupation;
private Boolean isStaff;
private Long officeId;
@@ -102,6 +105,8 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
private Collection<CodeValueData> genderOptions;
private Collection<CodeValueData> clientTypeOptions;
private Collection<CodeValueData> clientClassificationOptions;
private Collection<CodeValueData> occupationCategoryOptions;
private Collection<CodeValueData> occupationOptions;
private Collection<CodeValueData> clientNonPersonConstitutionOptions;
private Collection<CodeValueData> clientNonPersonMainBusinessLineOptions;
private List<EnumOptionData> clientLegalFormOptions;
@@ -281,6 +286,7 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
final Collection<StaffData> staffOptions, final Collection<CodeValueData> narrations,
final Collection<CodeValueData> genderOptions, final Collection<SavingsProductData> savingProductOptions,
final Collection<CodeValueData> clientTypeOptions, final Collection<CodeValueData> clientClassificationOptions,
final Collection<CodeValueData> occupationCategoryOptions, final Collection<CodeValueData> occupationOptions,
final Collection<CodeValueData> clientNonPersonConstitutionOptions,
final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions, final List<EnumOptionData> clientLegalFormOptions,
final ClientFamilyMembersData familyMemberOptions, final Collection<AddressData> address, final Boolean isAddressEnabled,
@@ -317,64 +323,83 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
final Boolean isStaff = false;
final ClientNonPersonData clientNonPersonDetails = null;
final Set<ClientCollateralManagementData> clientCollateralManagements = null;
return new ClientData(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender, joinedDate, imageId,
staffId, staffName, officeOptions, groups, staffOptions, narrations, genderOptions, timeline, savingProductOptions,
ClientData data = new ClientData(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id,
firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender, joinedDate,
imageId, staffId, staffName, officeOptions, groups, staffOptions, narrations, genderOptions, timeline, savingProductOptions,
savingsProductId, savingsProductName, savingsAccountId, savingAccountOptions, clientType, clientClassification,
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions,
clientNonPersonDetails, clientLegalFormOptions, familyMemberOptions, legalForm, address, isAddressEnabled, datatables,
isStaff, clientCollateralManagements);
data.occupationCategoryOptions = occupationCategoryOptions;
data.occupationOptions = occupationOptions;
return data;
}
public static ClientData templateOnTop(final ClientData clientData, final ClientData templateData) {
final Set<ClientCollateralManagementData> clientCollateralManagements = null;
return new ClientData(clientData.accountNo, clientData.status, clientData.subStatus, clientData.officeId, clientData.officeName,
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.emailAddress, clientData.dateOfBirth, clientData.gender, clientData.activationDate, clientData.imageId,
clientData.staffId, clientData.staffName, templateData.officeOptions, clientData.groups, templateData.staffOptions,
templateData.narrations, templateData.genderOptions, clientData.timeline, templateData.savingProductOptions,
clientData.savingsProductId, clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions,
clientData.clientType, clientData.clientClassification, templateData.clientTypeOptions,
ClientData data = new ClientData(clientData.accountNo, clientData.status, clientData.subStatus, clientData.officeId,
clientData.officeName, clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname,
clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId,
clientData.mobileNo, clientData.emailAddress, clientData.dateOfBirth, clientData.gender, clientData.activationDate,
clientData.imageId, clientData.staffId, clientData.staffName, templateData.officeOptions, clientData.groups,
templateData.staffOptions, templateData.narrations, templateData.genderOptions, clientData.timeline,
templateData.savingProductOptions, clientData.savingsProductId, clientData.savingsProductName, clientData.savingsAccountId,
clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification, templateData.clientTypeOptions,
templateData.clientClassificationOptions, templateData.clientNonPersonConstitutionOptions,
templateData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, templateData.clientLegalFormOptions,
templateData.familyMemberOptions, clientData.legalForm, clientData.address, clientData.isAddressEnabled, null,
clientData.isStaff, clientCollateralManagements);
data.cifNumber = clientData.cifNumber;
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
data.occupationCategoryOptions = templateData.occupationCategoryOptions;
data.occupationOptions = templateData.occupationOptions;
return data;
}
public static ClientData templateWithSavingAccountOptions(final ClientData clientData,
final Collection<SavingsAccountData> savingAccountOptions) {
final Set<ClientCollateralManagementData> clientCollateralManagements = null;
return new ClientData(clientData.accountNo, clientData.status, clientData.subStatus, clientData.officeId, clientData.officeName,
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.emailAddress, clientData.dateOfBirth, clientData.gender, clientData.activationDate, clientData.imageId,
clientData.staffId, clientData.staffName, clientData.officeOptions, clientData.groups, clientData.staffOptions,
clientData.narrations, clientData.genderOptions, clientData.timeline, clientData.savingProductOptions,
clientData.savingsProductId, clientData.savingsProductName, clientData.savingsAccountId, savingAccountOptions,
clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions,
ClientData data = new ClientData(clientData.accountNo, clientData.status, clientData.subStatus, clientData.officeId,
clientData.officeName, clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname,
clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId,
clientData.mobileNo, clientData.emailAddress, clientData.dateOfBirth, clientData.gender, clientData.activationDate,
clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions, clientData.groups,
clientData.staffOptions, clientData.narrations, clientData.genderOptions, clientData.timeline,
clientData.savingProductOptions, clientData.savingsProductId, clientData.savingsProductName, clientData.savingsAccountId,
savingAccountOptions, clientData.clientType, clientData.clientClassification, clientData.clientTypeOptions,
clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions,
clientData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, clientData.clientLegalFormOptions,
clientData.familyMemberOptions, clientData.legalForm, clientData.address, clientData.isAddressEnabled, null,
clientData.isStaff, clientCollateralManagements);
data.cifNumber = clientData.cifNumber;
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
data.occupationCategoryOptions = clientData.occupationCategoryOptions;
data.occupationOptions = clientData.occupationOptions;
return data;
}
public static ClientData setParentGroups(final ClientData clientData, final Collection<GroupGeneralData> parentGroups,
final Set<ClientCollateralManagementData> clientCollateralManagements) {
return new ClientData(clientData.accountNo, clientData.status, clientData.subStatus, clientData.officeId, clientData.officeName,
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
clientData.emailAddress, clientData.dateOfBirth, clientData.gender, clientData.activationDate, clientData.imageId,
clientData.staffId, clientData.staffName, clientData.officeOptions, parentGroups, clientData.staffOptions, null, null,
clientData.timeline, clientData.savingProductOptions, clientData.savingsProductId, clientData.savingsProductName,
clientData.savingsAccountId, clientData.savingAccountOptions, clientData.clientType, clientData.clientClassification,
clientData.clientTypeOptions, clientData.clientClassificationOptions, clientData.clientNonPersonConstitutionOptions,
clientData.clientNonPersonMainBusinessLineOptions, clientData.clientNonPersonDetails, clientData.clientLegalFormOptions,
clientData.familyMemberOptions, clientData.legalForm, clientData.address, clientData.isAddressEnabled, null,
clientData.isStaff, clientCollateralManagements);
ClientData data = new ClientData(clientData.accountNo, clientData.status, clientData.subStatus, clientData.officeId,
clientData.officeName, clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname,
clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId,
clientData.mobileNo, clientData.emailAddress, clientData.dateOfBirth, clientData.gender, clientData.activationDate,
clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions, parentGroups,
clientData.staffOptions, null, null, clientData.timeline, clientData.savingProductOptions, clientData.savingsProductId,
clientData.savingsProductName, clientData.savingsAccountId, clientData.savingAccountOptions, clientData.clientType,
clientData.clientClassification, clientData.clientTypeOptions, clientData.clientClassificationOptions,
clientData.clientNonPersonConstitutionOptions, clientData.clientNonPersonMainBusinessLineOptions,
clientData.clientNonPersonDetails, clientData.clientLegalFormOptions, clientData.familyMemberOptions, clientData.legalForm,
clientData.address, clientData.isAddressEnabled, null, clientData.isStaff, clientCollateralManagements);
data.cifNumber = clientData.cifNumber;
data.occupationCategory = clientData.occupationCategory;
data.occupation = clientData.occupation;
return data;
}
@@ -484,14 +509,15 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
return lookup(id, displayName, officeId, officeName);
}
public static ClientData instance(final String accountNo, final EnumOptionData status, final CodeValueData subStatus,
final Long officeId, final String officeName, final Long transferToOfficeId, final String transferToOfficeName, final Long id,
final String firstname, final String middlename, final String lastname, final String fullname, final String displayName,
final ExternalId externalId, final String mobileNo, final String emailAddress, final LocalDate dateOfBirth,
final CodeValueData gender, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
final ClientTimelineData timeline, final Long savingsProductId, final String savingsProductName, final Long savingsAccountId,
final CodeValueData clientType, final CodeValueData clientClassification, final EnumOptionData legalForm,
final ClientNonPersonData clientNonPerson, final Boolean isStaff) {
public static ClientData instance(final String accountNo, final String cifNumber, final EnumOptionData status,
final CodeValueData subStatus, final Long officeId, final String officeName, final Long transferToOfficeId,
final String transferToOfficeName, final Long id, final String firstname, final String middlename, final String lastname,
final String fullname, final String displayName, final ExternalId externalId, final String mobileNo,
final String emailAddress, final LocalDate dateOfBirth, final CodeValueData gender, final LocalDate activationDate,
final Long imageId, final Long staffId, final String staffName, final ClientTimelineData timeline,
final Long savingsProductId, final String savingsProductName, final Long savingsAccountId, final CodeValueData clientType,
final CodeValueData clientClassification, final CodeValueData occupationCategory, final CodeValueData occupation,
final EnumOptionData legalForm, final ClientNonPersonData clientNonPerson, final Boolean isStaff) {
final Collection<OfficeData> allowedOffices = null;
final Collection<GroupGeneralData> groups = null;
@@ -505,12 +531,16 @@ public final class ClientData implements Comparable<ClientData>, Serializable {
final Collection<CodeValueData> clientNonPersonMainBusinessLineOptions = null;
final List<EnumOptionData> clientLegalFormOptions = null;
final ClientFamilyMembersData familyMemberOptions = null;
return new ClientData(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender, activationDate,
imageId, staffId, staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline,
ClientData data = new ClientData(accountNo, status, subStatus, officeId, officeName, transferToOfficeId, transferToOfficeName, id,
firstname, middlename, lastname, fullname, displayName, externalId, mobileNo, emailAddress, dateOfBirth, gender,
activationDate, imageId, staffId, staffName, allowedOffices, groups, staffOptions, closureReasons, genderOptions, timeline,
savingProductOptions, savingsProductId, savingsProductName, savingsAccountId, null, clientType, clientClassification,
clientTypeOptions, clientClassificationOptions, clientNonPersonConstitutionOptions, clientNonPersonMainBusinessLineOptions,
clientNonPerson, clientLegalFormOptions, familyMemberOptions, legalForm, null, null, null, isStaff, null);
data.cifNumber = cifNumber;
data.occupationCategory = occupationCategory;
data.occupation = occupation;
return data;
}
@@ -56,12 +56,16 @@ import org.apache.fineract.useradministration.domain.AppUser;
@Getter
@Setter
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE"), //
@UniqueConstraint(columnNames = { "cif_number" }, name = "cif_number_UNIQUE"), //
@UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") })
public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@Column(name = "account_no", length = 20, unique = true, nullable = false)
private String accountNumber;
@Column(name = "cif_number", length = 20, unique = true, nullable = false)
private String cifNumber;
@ManyToOne
@JoinColumn(name = "office_id", nullable = false)
private Office office;
@@ -189,6 +193,14 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
@JoinColumn(name = "client_classification_cv_id")
private CodeValue clientClassification;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "occupation_category_cv_id")
private CodeValue occupationCategory;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "occupation_cv_id")
private CodeValue occupation;
@Column(name = "legal_form_enum")
private Integer legalForm;
@@ -206,24 +218,26 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
protected Set<ClientIdentifier> identifiers = new HashSet<>();
public static Client instance(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup,
final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname,
final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId, final String mobileNo,
final String emailAddress, final Staff staff, final LocalDate submittedOnDate, final Long savingsProductId,
final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender, final CodeValue clientType,
final CodeValue clientClassification, final Integer legalForm, final Boolean isStaff) {
return new Client(currentUser, status, office, clientParentGroup, accountNo, firstname, middlename, lastname, fullname,
final String accountNo, final String cifNumber, final String firstname, final String middlename, final String lastname,
final String fullname, final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId,
final String mobileNo, final String emailAddress, final Staff staff, final LocalDate submittedOnDate,
final Long savingsProductId, final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender,
final CodeValue clientType, final CodeValue clientClassification, final CodeValue occupationCategory,
final CodeValue occupation, final Integer legalForm, final Boolean isStaff) {
return new Client(currentUser, status, office, clientParentGroup, accountNo, cifNumber, firstname, middlename, lastname, fullname,
activationDate, officeJoiningDate, externalId, mobileNo, emailAddress, staff, submittedOnDate, savingsProductId,
savingsAccountId, dateOfBirth, gender, clientType, clientClassification, legalForm, isStaff);
savingsAccountId, dateOfBirth, gender, clientType, clientClassification, occupationCategory, occupation, legalForm, isStaff);
}
protected Client() {}
private Client(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup,
final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname,
final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId, final String mobileNo,
final String emailAddress, final Staff staff, final LocalDate submittedOnDate, final Long savingsProductId,
final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender, final CodeValue clientType,
final CodeValue clientClassification, final Integer legalForm, final Boolean isStaff) {
final String accountNo, final String cifNumber, final String firstname, final String middlename, final String lastname,
final String fullname, final LocalDate activationDate, final LocalDate officeJoiningDate, final ExternalId externalId,
final String mobileNo, final String emailAddress, final Staff staff, final LocalDate submittedOnDate,
final Long savingsProductId, final Long savingsAccountId, final LocalDate dateOfBirth, final CodeValue gender,
final CodeValue clientType, final CodeValue clientClassification, final CodeValue occupationCategory,
final CodeValue occupation, final Integer legalForm, final Boolean isStaff) {
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
@@ -231,6 +245,12 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.accountNumber = accountNo;
}
if (StringUtils.isBlank(cifNumber)) {
this.cifNumber = new RandomPasswordGenerator(19).generate();
} else {
this.cifNumber = cifNumber;
}
this.submittedOnDate = submittedOnDate;
this.status = status.getValue();
@@ -285,6 +305,8 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.clientType = clientType;
this.clientClassification = clientClassification;
this.occupationCategory = occupationCategory;
this.occupation = occupation;
this.setLegalForm(legalForm);
deriveDisplayName();
@@ -324,6 +346,10 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.accountNumber = accountIdentifier;
}
public void updateCifNumber(final String cifNumber) {
this.cifNumber = cifNumber;
}
public void activate(final AppUser currentUser, final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
if (isActive()) {
@@ -646,6 +672,30 @@ public class Client extends AbstractAuditableWithUTCDateTimeCustom<Long> {
this.clientClassification = clientClassification;
}
public Long occupationCategoryId() {
Long occupationCategoryId = null;
if (this.occupationCategory != null) {
occupationCategoryId = this.occupationCategory.getId();
}
return occupationCategoryId;
}
public void updateOccupationCategory(CodeValue occupationCategory) {
this.occupationCategory = occupationCategory;
}
public Long occupationId() {
Long occupationId = null;
if (this.occupation != null) {
occupationId = this.occupation.getId();
}
return occupationId;
}
public void updateOccupation(CodeValue occupation) {
this.occupation = occupation;
}
public void updateGender(CodeValue gender) {
this.gender = gender;
}
@@ -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>