fix(clients): stale signature bug, CKYC fixes, monthly turnover/annual income, senior citizen/PWD classification
- Add m_client.signature_id (single-slot pointer, mirrors image_id) plus ClientSignatureIdAdapter/EntitySignatureIdAdapter so re-uploading a signature updates the existing m_document row in place instead of leaving duplicate rows behind that readers picked inconsistently. - Fix CkycBatchBuilderServiceImpl address-proof classification to read the client identifier's actual m_code (KYCAddressProofType vs KYCIdProofType) instead of a hardcoded string set that disagreed with the CKYC tab and silently dropped Aadhaar-as-address-proof identifiers. - Organize the CKYC ZIP into per-artefact-type folders (PHOTO/SIGNATURE/ID_PROOF/ADDRESS_PROOF). - Fix CkycBatchBuilderServiceImpl.createBatch() using the daily batch sequence number as the ZIP document's parent_entity_id instead of the real m_ckyc_batch.id, which 404'd on download whenever the two diverged (i.e. almost always). - Add monthlyTurnover and annualIncome fields alongside the existing annualTurnover/monthlyIncome. - Add isSeniorCitizen, isPwd, and pwdCategory (proper m_code_value-backed PwdCategory code, not a free-text column) to m_client, following the same pattern as occupation/religion/marital status. - Add Diploma as its own Education Level (with diploma-specific DegreeQualification values) and Graduate as a level distinct from Undergraduate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+56
-35
@@ -32,7 +32,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -61,16 +60,22 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
||||
private static final DateTimeFormatter ZIP_NAME_TS_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
/**
|
||||
* Names of code values (from {@code KYCAddressProofType}) that unambiguously indicate an
|
||||
* address proof. Aadhaar / Passport / DL / Voter ID can be both ID and address proof — we
|
||||
* default them to ID (PI) unless the UI tags them explicitly.
|
||||
* Code (m_code.code_name) under which an identifier's document type must be classified for it
|
||||
* to count as an address proof. Matches the same m_code_value config that
|
||||
* KycProofTypesApiResource (GET /kyc/proof-types) reads to populate the CKYC tab's
|
||||
* "Address Proof Document" card — e.g. Aadhaar Card is seeded as a document type under BOTH
|
||||
* KYCIdProofType and KYCAddressProofType (two separate m_client_identifier rows), so trusting
|
||||
* the code a given identifier was actually tagged under is the only way this can agree with
|
||||
* what the CKYC tab already shows as "available".
|
||||
*/
|
||||
private static final Set<String> ADDRESS_PROOF_ONLY = Set.of(
|
||||
"UTILITY BILLS", "UTILITY BILL", "ELECTRICITY BILL", "WATER BILL", "GAS BILL", "INTERNET BILL",
|
||||
"BANK ACCOUNT STATEMENT / PASSBOOK", "BANK STATEMENT", "POSTPAID MOBILE BILL",
|
||||
"REGISTERED RENT AGREEMENT", "RENT AGREEMENT", "PROPERTY TAX RECEIPT",
|
||||
"EMPLOYER LETTER (FOR SALARIED EMPLOYEES)", "EMPLOYER LETTER",
|
||||
"PENSION PAYMENT ORDERS (FOR RETIREES)", "PENSION PAYMENT ORDER");
|
||||
private static final String ADDRESS_PROOF_CODE_NAME = "KYCAddressProofType";
|
||||
|
||||
// Top-level ZIP folders — one per artefact type, so every client's file of a given type lands
|
||||
// in the same folder instead of all 4 types being interleaved flat at the ZIP root.
|
||||
private static final String PHOTO_FOLDER = "PHOTO/";
|
||||
private static final String SIGNATURE_FOLDER = "SIGNATURE/";
|
||||
private static final String ID_PROOF_FOLDER = "ID_PROOF/";
|
||||
private static final String ADDRESS_PROOF_FOLDER = "ADDRESS_PROOF/";
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DocumentReadPlatformService documentReadPlatformService;
|
||||
@@ -111,13 +116,30 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
||||
final byte[] zipBytes = zipBytesOut.toByteArray();
|
||||
final String checksum = "sha256:" + sha256Hex(zipBytes);
|
||||
|
||||
// Persist the ZIP as an m_document row (parent_entity_type='ckyc_batch', parent_entity_id=seq)
|
||||
// Persistence happens BEFORE we know m_ckyc_batch.id, so we use the synthetic seq as a
|
||||
// temporary parent_entity_id. The real FK is via m_ckyc_batch.document_id after save.
|
||||
// Persist the batch registry row FIRST (without documentId) so we have its real,
|
||||
// DB-generated id before creating the ZIP's m_document row. The document's
|
||||
// parent_entity_id must be the actual m_ckyc_batch.id — using the daily `seq` here
|
||||
// (as a stand-in for an id that doesn't exist yet) was wrong: seq resets every day
|
||||
// while m_ckyc_batch.id is a global auto-increment, so GET
|
||||
// /ckyc_batch/{id}/documents/{documentId}/attachment (which matches on the REAL batch
|
||||
// id) 404'd for any batch whose seq didn't coincidentally equal its DB id.
|
||||
final CkycBatch batch = new CkycBatch();
|
||||
batch.setBatchId(batchId);
|
||||
batch.setFilename(filename);
|
||||
batch.setChecksumSha256(checksum);
|
||||
batch.setRecordCount(includedCount);
|
||||
batch.setSizeBytes((long) zipBytes.length);
|
||||
batch.setCreatedOnDate(today);
|
||||
batch.setUploadedToCersai(false);
|
||||
batch.setManifestJson(new Gson().toJson(manifest));
|
||||
|
||||
final CkycBatch saved = ckycBatchRepository.saveAndFlush(batch);
|
||||
|
||||
// Now persist the ZIP as an m_document row keyed to the batch's real id.
|
||||
final var docResponse = documentWritePlatformService.createDocument(
|
||||
DocumentCreateRequest.builder()
|
||||
.entityType("ckyc_batch")
|
||||
.entityId((long) seq)
|
||||
.entityId(saved.getId())
|
||||
.name(batchId)
|
||||
.fileName(filename)
|
||||
.description(StringUtils.defaultIfEmpty(remarks, "CERSAI CKYC batch ZIP"))
|
||||
@@ -126,19 +148,8 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
||||
.stream(new ByteArrayInputStream(zipBytes))
|
||||
.build());
|
||||
|
||||
// Persist the batch registry row
|
||||
final CkycBatch batch = new CkycBatch();
|
||||
batch.setBatchId(batchId);
|
||||
batch.setFilename(filename);
|
||||
batch.setChecksumSha256(checksum);
|
||||
batch.setRecordCount(includedCount);
|
||||
batch.setSizeBytes((long) zipBytes.length);
|
||||
batch.setDocumentId(docResponse.getResourceId() != null ? docResponse.getResourceId().longValue() : null);
|
||||
batch.setCreatedOnDate(today);
|
||||
batch.setUploadedToCersai(false);
|
||||
batch.setManifestJson(new Gson().toJson(manifest));
|
||||
|
||||
final CkycBatch saved = ckycBatchRepository.saveAndFlush(batch);
|
||||
saved.setDocumentId(docResponse.getResourceId() != null ? docResponse.getResourceId().longValue() : null);
|
||||
ckycBatchRepository.saveAndFlush(saved);
|
||||
|
||||
log.info("CKYC batch created: id={}, batchId={}, filename={}, recordCount={}/{}, bytes={}",
|
||||
saved.getId(), batchId, filename, includedCount, clientIds.size(), zipBytes.length);
|
||||
@@ -184,32 +195,40 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
||||
entry.setCifNumber(cifNumber);
|
||||
entry.setDisplayName(displayName);
|
||||
|
||||
// Photo — packaged as "<CIF>-PI-PHOTO.<ext>" using m_client.image_id → m_image
|
||||
// Photo — packaged as "PHOTO/<CIF>-PI-PHOTO.<ext>" using m_client.image_id → m_image.
|
||||
// Every artefact type gets its own top-level ZIP folder, so a batch of N clients produces
|
||||
// one PHOTO/ folder containing all N client photos (and likewise for the other 3 types),
|
||||
// rather than every client's files interleaved flat at the ZIP root.
|
||||
final Map<String, Object> photo = new LinkedHashMap<>();
|
||||
photo.put("present", imageId != null);
|
||||
entry.setPhoto(photo);
|
||||
if (imageId != null && cifNumber != null) {
|
||||
packageClientImage(zip, clientId, cifNumber + "-PI-PHOTO", photo);
|
||||
packageClientImage(zip, clientId, PHOTO_FOLDER + cifNumber + "-PI-PHOTO", photo);
|
||||
}
|
||||
|
||||
// Signature — packaged as "<CIF>-PI-SIGNATURE.<ext>"
|
||||
// Signature — packaged as "SIGNATURE/<CIF>-PI-SIGNATURE.<ext>"
|
||||
final Long signatureDocId = findSignatureDocId(clientId);
|
||||
final Map<String, Object> signature = new LinkedHashMap<>();
|
||||
signature.put("present", signatureDocId != null);
|
||||
entry.setSignature(signature);
|
||||
if (signatureDocId != null && cifNumber != null) {
|
||||
packageFile(zip, "clients", clientId, signatureDocId,
|
||||
cifNumber + "-PI-SIGNATURE", signature);
|
||||
SIGNATURE_FOLDER + cifNumber + "-PI-SIGNATURE", signature);
|
||||
}
|
||||
|
||||
// ID proof + Address proof: iterate m_client_identifier, classify by code value name.
|
||||
// ID proof + Address proof: iterate m_client_identifier, classify by the m_code the
|
||||
// identifier's document type actually belongs to (KYCIdProofType vs KYCAddressProofType) —
|
||||
// the same source of truth KycProofTypesApiResource uses for the CKYC tab, so a document
|
||||
// the client sees as "Address Proof: Available" is never silently dropped here.
|
||||
// For each identifier, find the attached m_document (one-to-one, latest wins).
|
||||
// NOTE: the `active` column in m_client_identifier stores the status code (200 = active)
|
||||
// not a 1/0 boolean — so we filter on `status = 200` (ClientIdentifierStatus.ACTIVE).
|
||||
final List<Map<String, Object>> identifiers = jdbcTemplate.queryForList(
|
||||
"select ci.id as identifierId, ci.document_key as docKey, cv.code_value as codeValue "
|
||||
"select ci.id as identifierId, ci.document_key as docKey, cv.code_value as codeValue, "
|
||||
+ " c.code_name as codeName "
|
||||
+ " from m_client_identifier ci "
|
||||
+ " join m_code_value cv on cv.id = ci.document_type_id "
|
||||
+ " join m_code c on c.id = cv.code_id "
|
||||
+ " where ci.client_id = ? and (ci.status = 200 or ci.status is null)",
|
||||
clientId);
|
||||
|
||||
@@ -221,8 +240,9 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
||||
for (final Map<String, Object> idRow : identifiers) {
|
||||
final Long identifierId = ((Number) idRow.get("identifierId")).longValue();
|
||||
final String codeValue = (String) idRow.get("codeValue");
|
||||
final String codeName = (String) idRow.get("codeName");
|
||||
final String docKey = (String) idRow.get("docKey");
|
||||
final boolean isAddress = ADDRESS_PROOF_ONLY.contains(codeValue == null ? "" : codeValue.toUpperCase(Locale.ROOT));
|
||||
final boolean isAddress = ADDRESS_PROOF_CODE_NAME.equalsIgnoreCase(codeName);
|
||||
final String role = isAddress ? "PA" : "PI";
|
||||
|
||||
final Long attachedDocId = findLatestDocForIdentifier(identifierId);
|
||||
@@ -242,8 +262,9 @@ public class CkycBatchBuilderServiceImpl implements CkycBatchBuilderService {
|
||||
bucket.put("key", docKey);
|
||||
|
||||
if (cifNumber != null) {
|
||||
final String folder = isAddress ? ADDRESS_PROOF_FOLDER : ID_PROOF_FOLDER;
|
||||
packageFile(zip, "client_identifiers", identifierId, attachedDocId,
|
||||
cifNumber + "-" + role + "-" + shortCode, bucket);
|
||||
folder + cifNumber + "-" + role + "-" + shortCode, bucket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -32,8 +32,9 @@ public class ClientApiCollectionConstants extends ClientApiConstants {
|
||||
dateOfBirthParamName, genderIdParamName, salutationIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
|
||||
occupationCategoryIdParamName, occupationIdParamName, maritalStatusIdParamName,
|
||||
educationLevelIdParamName, degreeQualificationIdParamName,
|
||||
religionIdParamName, socialCategoryIdParamName, monthlyIncomeParamName, annualTurnoverParamName,
|
||||
agricultureIncomeParamName, nonAgricultureIncomeParamName,
|
||||
religionIdParamName, socialCategoryIdParamName, monthlyIncomeParamName, annualIncomeParamName, annualTurnoverParamName,
|
||||
monthlyTurnoverParamName, agricultureIncomeParamName, nonAgricultureIncomeParamName,
|
||||
isSeniorCitizenParamName, isPwdParamName, pwdCategoryIdParamName,
|
||||
ageYearsParamName, ageMonthsParamName, ageDaysParamName,
|
||||
nationalityIdParamName, isMinorParamName, guardianClientIdParamName, guardianRelationParamName,
|
||||
dipVerifiedParamName, dipLookupLogIdParamName, dipTimestampParamName,
|
||||
@@ -55,8 +56,9 @@ public class ClientApiCollectionConstants extends ClientApiConstants {
|
||||
dateOfBirthParamName, genderIdParamName, salutationIdParamName, clientTypeIdParamName, clientClassificationIdParamName,
|
||||
occupationCategoryIdParamName, occupationIdParamName, maritalStatusIdParamName,
|
||||
educationLevelIdParamName, degreeQualificationIdParamName,
|
||||
religionIdParamName, socialCategoryIdParamName, monthlyIncomeParamName, annualTurnoverParamName,
|
||||
agricultureIncomeParamName, nonAgricultureIncomeParamName,
|
||||
religionIdParamName, socialCategoryIdParamName, monthlyIncomeParamName, annualIncomeParamName, annualTurnoverParamName,
|
||||
monthlyTurnoverParamName, agricultureIncomeParamName, nonAgricultureIncomeParamName,
|
||||
isSeniorCitizenParamName, isPwdParamName, pwdCategoryIdParamName,
|
||||
ageYearsParamName, ageMonthsParamName, ageDaysParamName,
|
||||
nationalityIdParamName, isMinorParamName, guardianClientIdParamName, guardianRelationParamName,
|
||||
dipVerifiedParamName, dipLookupLogIdParamName, dipTimestampParamName,
|
||||
|
||||
+11
@@ -65,12 +65,14 @@ public interface ClientMapper {
|
||||
@Mapping(target = "degreeQualification", source = "source", qualifiedByName = "degreeQualificationCode")
|
||||
@Mapping(target = "religion", source = "source", qualifiedByName = "religionCode")
|
||||
@Mapping(target = "socialCategory", source = "source", qualifiedByName = "socialCategoryCode")
|
||||
@Mapping(target = "pwdCategory", source = "source", qualifiedByName = "pwdCategoryCode")
|
||||
@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 = "pwdCategoryOptions", ignore = true)
|
||||
@Mapping(target = "legalForm", source = "source", qualifiedByName = "clientLegalFormEnum")
|
||||
@Mapping(target = "isStaff", source = "source", qualifiedByName = "clientIsStaff")
|
||||
@Mapping(target = "ageYears", ignore = true)
|
||||
@@ -196,6 +198,15 @@ public interface ClientMapper {
|
||||
return CodeValueData.instance(code.getId(), code.getLabel());
|
||||
}
|
||||
|
||||
@Named("pwdCategoryCode")
|
||||
default CodeValueData pwdCategoryCode(Client client) {
|
||||
final CodeValue code = client.getPwdCategory();
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
return CodeValueData.instance(code.getId(), code.getLabel());
|
||||
}
|
||||
|
||||
@Named("clientSubStatusCode")
|
||||
default CodeValueData clientSubStatusCode(Client client) {
|
||||
final CodeValue code = client.getSubStatus();
|
||||
|
||||
+38
@@ -321,7 +321,13 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
sqlBuilder.append("c.occupation_cv_id as occupationId, ");
|
||||
sqlBuilder.append("cvOccupation.code_value as occupationValue, ");
|
||||
sqlBuilder.append("c.monthly_income as monthlyIncome, ");
|
||||
sqlBuilder.append("c.annual_income as annualIncome, ");
|
||||
sqlBuilder.append("c.annual_turnover as annualTurnover, ");
|
||||
sqlBuilder.append("c.monthly_turnover as monthlyTurnover, ");
|
||||
sqlBuilder.append("c.is_senior_citizen as isSeniorCitizen, ");
|
||||
sqlBuilder.append("c.is_pwd as isPwd, ");
|
||||
sqlBuilder.append("c.pwd_category_cv_id as pwdCategoryId, ");
|
||||
sqlBuilder.append("cvPwdCategory.code_value as pwdCategoryValue, ");
|
||||
sqlBuilder.append("c.nationality as nationality, ");
|
||||
sqlBuilder.append("c.is_minor as isMinor, ");
|
||||
sqlBuilder.append("c.guardian_client_id as guardianClientId, ");
|
||||
@@ -383,6 +389,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
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 cvPwdCategory on cvPwdCategory.id = c.pwd_category_cv_id ");
|
||||
sqlBuilder.append("left join m_code_value cvOccupation on cvOccupation.id = c.occupation_cv_id ");
|
||||
sqlBuilder.append("left join m_client gc on gc.id = c.guardian_client_id ");
|
||||
sqlBuilder.append("left join m_code_value cvConstitution on cvConstitution.id = cnp.constitution_cv_id ");
|
||||
@@ -482,7 +489,14 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
final CodeValueData occupation = CodeValueData.instance(occupationId, occupationValue);
|
||||
|
||||
final BigDecimal monthlyIncome1 = rs.getBigDecimal("monthlyIncome");
|
||||
final BigDecimal annualIncome1 = rs.getBigDecimal("annualIncome");
|
||||
final BigDecimal annualTurnover1 = rs.getBigDecimal("annualTurnover");
|
||||
final BigDecimal monthlyTurnover1 = rs.getBigDecimal("monthlyTurnover");
|
||||
final Boolean isSeniorCitizen1 = rs.getBoolean("isSeniorCitizen");
|
||||
final Boolean isPwd1 = rs.getBoolean("isPwd");
|
||||
final Long pwdCategoryId1 = JdbcSupport.getLong(rs, "pwdCategoryId");
|
||||
final String pwdCategoryValue1 = rs.getString("pwdCategoryValue");
|
||||
final CodeValueData pwdCategory1 = CodeValueData.instance(pwdCategoryId1, pwdCategoryValue1);
|
||||
|
||||
Integer ageYears1 = null;
|
||||
Integer ageMonths1 = null;
|
||||
@@ -520,7 +534,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
savingsProductName, savingsAccountId, clienttype, classification, occupationCategory, occupation, legalForm,
|
||||
clientNonPerson, isStaff);
|
||||
clientData.setMonthlyIncome(monthlyIncome1);
|
||||
clientData.setAnnualIncome(annualIncome1);
|
||||
clientData.setAnnualTurnover(annualTurnover1);
|
||||
clientData.setMonthlyTurnover(monthlyTurnover1);
|
||||
clientData.setIsSeniorCitizen(isSeniorCitizen1);
|
||||
clientData.setIsPwd(isPwd1);
|
||||
clientData.setPwdCategory(pwdCategory1);
|
||||
clientData.setAgeYears(ageYears1);
|
||||
clientData.setAgeMonths(ageMonths1);
|
||||
clientData.setAgeDays(ageDays1);
|
||||
@@ -714,7 +733,13 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
builder.append("c.occupation_cv_id as occupationId, ");
|
||||
builder.append("cvOccupation.code_value as occupationValue, ");
|
||||
builder.append("c.monthly_income as monthlyIncome, ");
|
||||
builder.append("c.annual_income as annualIncome, ");
|
||||
builder.append("c.annual_turnover as annualTurnover, ");
|
||||
builder.append("c.monthly_turnover as monthlyTurnover, ");
|
||||
builder.append("c.is_senior_citizen as isSeniorCitizen, ");
|
||||
builder.append("c.is_pwd as isPwd, ");
|
||||
builder.append("c.pwd_category_cv_id as pwdCategoryId, ");
|
||||
builder.append("cvPwdCategory.code_value as pwdCategoryValue, ");
|
||||
builder.append("c.nationality as nationality, ");
|
||||
builder.append("c.is_minor as isMinor, ");
|
||||
builder.append("c.guardian_client_id as guardianClientId, ");
|
||||
@@ -775,6 +800,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
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 cvPwdCategory on cvPwdCategory.id = c.pwd_category_cv_id ");
|
||||
builder.append("left join m_code_value cvOccupation on cvOccupation.id = c.occupation_cv_id ");
|
||||
builder.append("left join m_client gc on gc.id = c.guardian_client_id ");
|
||||
builder.append("left join m_code_value cvConstitution on cvConstitution.id = cnp.constitution_cv_id ");
|
||||
@@ -873,7 +899,14 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
final CodeValueData occupation = CodeValueData.instance(occupationId, occupationValue);
|
||||
|
||||
final BigDecimal monthlyIncome = rs.getBigDecimal("monthlyIncome");
|
||||
final BigDecimal annualIncome = rs.getBigDecimal("annualIncome");
|
||||
final BigDecimal annualTurnover = rs.getBigDecimal("annualTurnover");
|
||||
final BigDecimal monthlyTurnover = rs.getBigDecimal("monthlyTurnover");
|
||||
final Boolean isSeniorCitizen = rs.getBoolean("isSeniorCitizen");
|
||||
final Boolean isPwd = rs.getBoolean("isPwd");
|
||||
final Long pwdCategoryId = JdbcSupport.getLong(rs, "pwdCategoryId");
|
||||
final String pwdCategoryValue = rs.getString("pwdCategoryValue");
|
||||
final CodeValueData pwdCategory = CodeValueData.instance(pwdCategoryId, pwdCategoryValue);
|
||||
|
||||
Integer ageYears = null;
|
||||
Integer ageMonths = null;
|
||||
@@ -911,7 +944,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
savingsProductName, savingsAccountId, clienttype, classification, occupationCategory, occupation, legalForm,
|
||||
clientNonPerson, isStaff);
|
||||
clientData.setMonthlyIncome(monthlyIncome);
|
||||
clientData.setAnnualIncome(annualIncome);
|
||||
clientData.setAnnualTurnover(annualTurnover);
|
||||
clientData.setMonthlyTurnover(monthlyTurnover);
|
||||
clientData.setIsSeniorCitizen(isSeniorCitizen);
|
||||
clientData.setIsPwd(isPwd);
|
||||
clientData.setPwdCategory(pwdCategory);
|
||||
clientData.setAgeYears(ageYears);
|
||||
clientData.setAgeMonths(ageMonths);
|
||||
clientData.setAgeDays(ageDays);
|
||||
|
||||
+4
@@ -126,6 +126,9 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead
|
||||
final List<CodeValueData> socialCategoryOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.SOCIAL_CATEGORY));
|
||||
|
||||
final List<CodeValueData> pwdCategoryOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.PWD_CATEGORY));
|
||||
|
||||
final List<CodeValueData> clientNonPersonConstitutionOptions = new ArrayList<>(
|
||||
this.codeValueReadPlatformService.retrieveCodeValuesByCode(ClientApiConstants.CLIENT_NON_PERSON_CONSTITUTION));
|
||||
|
||||
@@ -146,6 +149,7 @@ public class ClientTemplateReadPlatformServiceImpl implements ClientTemplateRead
|
||||
templateData.setDegreeQualificationOptions(degreeQualificationOptions);
|
||||
templateData.setReligionOptions(religionOptions);
|
||||
templateData.setSocialCategoryOptions(socialCategoryOptions);
|
||||
templateData.setPwdCategoryOptions(pwdCategoryOptions);
|
||||
return templateData;
|
||||
}
|
||||
|
||||
|
||||
+62
@@ -395,6 +395,13 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.SOCIAL_CATEGORY, socialCategoryId);
|
||||
}
|
||||
|
||||
CodeValue pwdCategory = null;
|
||||
final Long pwdCategoryId = command.longValueOfParameterNamed(ClientApiConstants.pwdCategoryIdParamName);
|
||||
if (pwdCategoryId != null) {
|
||||
pwdCategory = this.codeValueRepository
|
||||
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.PWD_CATEGORY, pwdCategoryId);
|
||||
}
|
||||
|
||||
final Long savingsProductId = command.longValueOfParameterNamed(ClientApiConstants.savingsProductIdParamName);
|
||||
if (savingsProductId != null) {
|
||||
this.savingsProductRepository.findById(savingsProductId)
|
||||
@@ -481,11 +488,31 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
newClient.setMonthlyIncome(monthlyIncome);
|
||||
}
|
||||
|
||||
final java.math.BigDecimal annualIncome = command.bigDecimalValueOfParameterNamed(ClientApiConstants.annualIncomeParamName);
|
||||
if (annualIncome != null) {
|
||||
newClient.setAnnualIncome(annualIncome);
|
||||
}
|
||||
|
||||
final java.math.BigDecimal annualTurnover = command.bigDecimalValueOfParameterNamed(ClientApiConstants.annualTurnoverParamName);
|
||||
if (annualTurnover != null) {
|
||||
newClient.setAnnualTurnover(annualTurnover);
|
||||
}
|
||||
|
||||
final java.math.BigDecimal monthlyTurnover = command.bigDecimalValueOfParameterNamed(ClientApiConstants.monthlyTurnoverParamName);
|
||||
if (monthlyTurnover != null) {
|
||||
newClient.setMonthlyTurnover(monthlyTurnover);
|
||||
}
|
||||
|
||||
final Boolean isSeniorCitizen = command.booleanObjectValueOfParameterNamed(ClientApiConstants.isSeniorCitizenParamName);
|
||||
newClient.setIsSeniorCitizen(Boolean.TRUE.equals(isSeniorCitizen));
|
||||
|
||||
final Boolean isPwd = command.booleanObjectValueOfParameterNamed(ClientApiConstants.isPwdParamName);
|
||||
newClient.setIsPwd(Boolean.TRUE.equals(isPwd));
|
||||
|
||||
if (pwdCategory != null) {
|
||||
newClient.updatePwdCategory(pwdCategory);
|
||||
}
|
||||
|
||||
final java.math.BigDecimal agricultureIncome = command.bigDecimalValueOfParameterNamed(ClientApiConstants.agricultureIncomeParamName);
|
||||
if (agricultureIncome != null) {
|
||||
newClient.setAgricultureIncome(agricultureIncome);
|
||||
@@ -964,12 +991,47 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
clientForUpdate.setMonthlyIncome(newValue);
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.annualIncomeParamName, clientForUpdate.getAnnualIncome())) {
|
||||
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.annualIncomeParamName);
|
||||
changes.put(ClientApiConstants.annualIncomeParamName, newValue);
|
||||
clientForUpdate.setAnnualIncome(newValue);
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.annualTurnoverParamName, clientForUpdate.getAnnualTurnover())) {
|
||||
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.annualTurnoverParamName);
|
||||
changes.put(ClientApiConstants.annualTurnoverParamName, newValue);
|
||||
clientForUpdate.setAnnualTurnover(newValue);
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.monthlyTurnoverParamName, clientForUpdate.getMonthlyTurnover())) {
|
||||
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.monthlyTurnoverParamName);
|
||||
changes.put(ClientApiConstants.monthlyTurnoverParamName, newValue);
|
||||
clientForUpdate.setMonthlyTurnover(newValue);
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(ClientApiConstants.isSeniorCitizenParamName, clientForUpdate.getIsSeniorCitizen())) {
|
||||
final Boolean newValue = command.booleanObjectValueOfParameterNamed(ClientApiConstants.isSeniorCitizenParamName);
|
||||
changes.put(ClientApiConstants.isSeniorCitizenParamName, newValue);
|
||||
clientForUpdate.setIsSeniorCitizen(Boolean.TRUE.equals(newValue));
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(ClientApiConstants.isPwdParamName, clientForUpdate.getIsPwd())) {
|
||||
final Boolean newValue = command.booleanObjectValueOfParameterNamed(ClientApiConstants.isPwdParamName);
|
||||
changes.put(ClientApiConstants.isPwdParamName, newValue);
|
||||
clientForUpdate.setIsPwd(Boolean.TRUE.equals(newValue));
|
||||
}
|
||||
|
||||
if (command.isChangeInLongParameterNamed(ClientApiConstants.pwdCategoryIdParamName, clientForUpdate.pwdCategoryId())) {
|
||||
final Long newValue = command.longValueOfParameterNamed(ClientApiConstants.pwdCategoryIdParamName);
|
||||
changes.put(ClientApiConstants.pwdCategoryIdParamName, newValue);
|
||||
CodeValue newCodeVal = null;
|
||||
if (newValue != null) {
|
||||
newCodeVal = this.codeValueRepository
|
||||
.findOneByCodeNameAndIdWithNotFoundDetection(ClientApiConstants.PWD_CATEGORY, newValue);
|
||||
}
|
||||
clientForUpdate.updatePwdCategory(newCodeVal);
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamed(ClientApiConstants.agricultureIncomeParamName, clientForUpdate.getAgricultureIncome())) {
|
||||
final java.math.BigDecimal newValue = command.bigDecimalValueOfParameterNamed(ClientApiConstants.agricultureIncomeParamName);
|
||||
changes.put(ClientApiConstants.agricultureIncomeParamName, newValue);
|
||||
|
||||
@@ -441,6 +441,12 @@
|
||||
<include file="parts/0418_add_user_agreement_permissions.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0419_revert_first_login_gate_column_and_config.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0420_add_missing_clientkyc_action_permissions.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0421_add_signature_id_to_client.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0422_add_monthly_turnover_to_client.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0423_add_annual_income_to_client.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0424_add_senior_citizen_pwd_to_client.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0425_add_diploma_degree_qualification.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0426_add_graduate_education_level.xml" relativeToChangelogFile="true"/>
|
||||
<!-- NOTE: the numbers below (0341-0359) re-use prefixes already used above by the chequebook/CTS
|
||||
clearing catchup migrations — these come from a long-diverged branch (uate) that assigned its own
|
||||
sequence independently. Liquibase tracks changesets by filename + id + author, not by the numeric
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<?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">
|
||||
|
||||
<!--
|
||||
m_client.image_id is a single-slot pointer into m_image: every photo upload overwrites the
|
||||
same row, so every reader always sees the latest photo. The client signature had no
|
||||
equivalent — every upload/re-crop created a brand-new m_document row named
|
||||
'clientSignature' and never touched the previous one. Readers that don't explicitly
|
||||
`order by id desc` (CKYC Documents tab, view-signature dialog, delete-signature dialog)
|
||||
picked the FIRST matching row from an unordered query, i.e. the oldest signature, even
|
||||
after the client re-cropped it — while CkycBatchBuilderServiceImpl (which does order by id
|
||||
desc) correctly zipped up the latest one. This adds a signature_id pointer mirroring
|
||||
image_id so signature storage becomes single-slot too, and backfills it from the latest
|
||||
existing 'clientSignature' document per client so it starts out consistent with what the
|
||||
CKYC ZIP builder already considered "current".
|
||||
-->
|
||||
<changeSet author="CBS" id="0421-1-add-signature-id-to-client">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="signature_id" type="BIGINT">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="CBS" id="0421-2-add-signature-id-index">
|
||||
<createIndex indexName="FK_m_client_m_document_signature" tableName="m_client">
|
||||
<column name="signature_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="CBS" id="0421-3-add-signature-id-fk">
|
||||
<addForeignKeyConstraint baseColumnNames="signature_id" baseTableName="m_client"
|
||||
constraintName="FK_m_client_m_document_signature" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="SET NULL" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_document" validate="true"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="CBS" id="0421-4-backfill-signature-id">
|
||||
<sql>
|
||||
UPDATE m_client c
|
||||
SET signature_id = (
|
||||
SELECT MAX(d.id) FROM m_document d
|
||||
WHERE d.parent_entity_type = 'clients' AND d.parent_entity_id = c.id AND d.name = 'clientSignature'
|
||||
)
|
||||
WHERE EXISTS (
|
||||
SELECT 1 FROM m_document d
|
||||
WHERE d.parent_entity_type = 'clients' AND d.parent_entity_id = c.id AND d.name = 'clientSignature'
|
||||
)
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?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">
|
||||
|
||||
<!-- Mirrors 0238_add_annual_turnover.xml — "Annual Turnover (Last FY)" is now labelled
|
||||
"Yearly Turnover" in the client form, alongside this new "Monthly Turnover" field. -->
|
||||
<changeSet author="CBS" id="0422-1">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="monthly_turnover" type="DECIMAL(19,2)" defaultValue="null"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<?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">
|
||||
|
||||
<!-- Pairs with monthly_income the same way monthly_turnover pairs with annual_turnover
|
||||
(0422_add_monthly_turnover_to_client.xml) — "Annual Income" alongside "Monthly Income". -->
|
||||
<changeSet author="CBS" id="0423-1">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="annual_income" type="DECIMAL(19,2)" defaultValue="null"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
<?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">
|
||||
|
||||
<!-- Senior Citizen / Persons-with-Disability flags for RBI-mandated accessible-banking
|
||||
provisions (doorstep banking eligibility for senior citizens 70+ and differently-abled/
|
||||
infirm customers, per RBI's customer service circulars). isSeniorCitizen is auto-detected
|
||||
client-side from Date of Birth (not user-editable); PWD is a manual flag. -->
|
||||
<changeSet author="CBS" id="0424-1">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="is_senior_citizen" type="boolean" defaultValueBoolean="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="is_pwd" type="boolean" defaultValueBoolean="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<!-- pwd_category_cv_id follows the same m_code_value FK pattern as occupation_category_cv_id /
|
||||
marital_status_cv_id / religion_cv_id etc — a fixed free-text column would need a Java
|
||||
change every time a new disability category is needed; a code value lets an admin add,
|
||||
reorder, or deactivate categories from System -> Manage Codes with zero code changes. -->
|
||||
<changeSet author="CBS" id="0424-2">
|
||||
<addColumn tableName="m_client">
|
||||
<column name="pwd_category_cv_id" type="BIGINT">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="CBS" id="0424-3">
|
||||
<createIndex indexName="FK_m_client_pwd_category_cv_id" tableName="m_client">
|
||||
<column name="pwd_category_cv_id"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="CBS" id="0424-4">
|
||||
<addForeignKeyConstraint baseColumnNames="pwd_category_cv_id" baseTableName="m_client"
|
||||
constraintName="FK_m_client_pwd_category_cv_id" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_code_value" validate="true"/>
|
||||
</changeSet>
|
||||
|
||||
<!-- ==================== PwdCategory code ====================
|
||||
Categories per the Rights of Persons with Disabilities Act, 2016 (RPWD Act), the same
|
||||
classification referenced by RBI's accessible-banking circulars. -->
|
||||
<changeSet author="CBS" id="0424-5">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_code WHERE code_name = 'PwdCategory'</sqlCheck>
|
||||
</preConditions>
|
||||
<insert tableName="m_code">
|
||||
<column name="code_name" value="PwdCategory"/>
|
||||
<column name="is_system_defined" valueBoolean="true"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="CBS" id="0424-6">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">SELECT COUNT(*) FROM m_code_value WHERE code_id = (SELECT id FROM m_code WHERE code_name = 'PwdCategory')</sqlCheck>
|
||||
</preConditions>
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, code_description, order_position, is_active, is_mandatory)
|
||||
SELECT id, val, val, pos, true, false FROM m_code
|
||||
CROSS JOIN (VALUES
|
||||
('Blindness', 1),
|
||||
('Low Vision', 2),
|
||||
('Leprosy Cured Persons', 3),
|
||||
('Hearing Impairment (Deaf and Hard of Hearing)', 4),
|
||||
('Locomotor Disability', 5),
|
||||
('Dwarfism', 6),
|
||||
('Intellectual Disability', 7),
|
||||
('Mental Illness', 8),
|
||||
('Autism Spectrum Disorder', 9),
|
||||
('Cerebral Palsy', 10),
|
||||
('Muscular Dystrophy', 11),
|
||||
('Chronic Neurological Conditions', 12),
|
||||
('Specific Learning Disabilities', 13),
|
||||
('Multiple Sclerosis', 14),
|
||||
('Speech and Language Disability', 15),
|
||||
('Thalassemia', 16),
|
||||
('Hemophilia', 17),
|
||||
('Sickle Cell Disease', 18),
|
||||
('Multiple Disabilities', 19),
|
||||
('Acid Attack Victim', 20),
|
||||
('Parkinson''s Disease', 21)
|
||||
) AS t(val, pos)
|
||||
WHERE code_name = 'PwdCategory';
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
<?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">
|
||||
|
||||
<!-- "Diploma" becomes its own Education Level (alongside School / Undergraduate / Postgraduate
|
||||
/ Doctorate) rather than a single generic entry nested under either of those — polytechnic
|
||||
diploma holders are neither "School" nor "Undergraduate" in the strict sense. The
|
||||
"Degree / Qualification" dropdown then offers diploma-specific branches when this level
|
||||
is selected. -->
|
||||
<changeSet id="0425_01_insert_diploma_education_level" author="CBS">
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
|
||||
SELECT c.id, 'Diploma',
|
||||
(SELECT COALESCE(MAX(cv.order_position), 0) FROM m_code_value cv WHERE cv.code_id = c.id) + 1,
|
||||
true, false
|
||||
FROM m_code c
|
||||
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 = 'Diploma'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="0425_02_insert_diploma_degree_values" author="CBS">
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, code_description, order_position, is_active, is_mandatory)
|
||||
SELECT c.id, v.code_value, 'Diploma',
|
||||
(SELECT COALESCE(MAX(cv.order_position), 0) FROM m_code_value cv WHERE cv.code_id = c.id) + v.rn,
|
||||
true, false
|
||||
FROM m_code c
|
||||
CROSS JOIN (
|
||||
VALUES
|
||||
('Diploma in Mechanical Engineering', 1),
|
||||
('Diploma in Civil Engineering', 2),
|
||||
('Diploma in Electrical Engineering', 3),
|
||||
('Diploma in Electronics & Communication', 4),
|
||||
('Diploma in Computer Science / IT', 5),
|
||||
('Diploma in Automobile Engineering', 6),
|
||||
('ITI Certificate', 7),
|
||||
('Polytechnic Diploma (Other)', 8),
|
||||
('Other Diploma', 9)
|
||||
) AS v(code_value, rn)
|
||||
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 AND cv.code_description = 'Diploma'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
<!-- The original "Diploma" DegreeQualification row (0256_add_education_level_degree_codes.xml)
|
||||
was tagged under School — it's superseded by the standalone Diploma Education Level above,
|
||||
so deactivate rather than delete (existing client records referencing it must keep resolving). -->
|
||||
<changeSet id="0425_03_deactivate_school_diploma_degree_value" author="CBS">
|
||||
<sql>
|
||||
UPDATE m_code_value cv
|
||||
SET is_active = false
|
||||
WHERE cv.code_id = (SELECT id FROM m_code WHERE code_name = 'DegreeQualification')
|
||||
AND cv.code_value = 'Diploma'
|
||||
AND cv.code_description = 'School';
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
<?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">
|
||||
|
||||
<!-- "Undergraduate" means currently pursuing a bachelor's degree (not yet completed);
|
||||
"Graduate" means it has been completed. These are distinct statuses, so Graduate gets
|
||||
its own Education Level rather than being folded into Undergraduate.
|
||||
No frontend change needed for degree filtering: getEducationLevelCategory() in
|
||||
client-general-step.component.ts already matches any name containing "graduate"
|
||||
(Undergraduate OR Graduate) to the same 'undergraduate' bucket, so both levels correctly
|
||||
show the same specific-degree list (B.Tech, B.A., B.Sc., ..., Other UG). -->
|
||||
<changeSet id="0426_01_insert_graduate_education_level" author="CBS">
|
||||
<sql>
|
||||
INSERT INTO m_code_value (code_id, code_value, order_position, is_active, is_mandatory)
|
||||
SELECT c.id, 'Graduate',
|
||||
(SELECT COALESCE(MAX(cv.order_position), 0) FROM m_code_value cv WHERE cv.code_id = c.id) + 1,
|
||||
true, false
|
||||
FROM m_code c
|
||||
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 = 'Graduate'
|
||||
);
|
||||
</sql>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user