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:
+24
-4
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.documentmanagement.service;
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -31,6 +32,7 @@ import org.apache.commons.lang3.Strings;
|
||||
import org.apache.fineract.infrastructure.contentstore.service.ContentStoreService;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.adapter.EntitySignatureIdAdapter;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentCreateRequest;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentCreateResponse;
|
||||
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentDeleteRequest;
|
||||
@@ -59,6 +61,7 @@ public class DocumentWritePlatformServiceImpl implements DocumentWritePlatformSe
|
||||
private final ContentStoreService storeService;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final FineractProperties properties;
|
||||
private final List<EntitySignatureIdAdapter> signatureIdAdapters;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -74,13 +77,30 @@ public class DocumentWritePlatformServiceImpl implements DocumentWritePlatformSe
|
||||
|
||||
path = storeService.upload(path, request.getStream(), request.getType());
|
||||
|
||||
final var doc = new Document().setParentEntityType(request.getEntityType()).setParentEntityId(request.getEntityId())
|
||||
.setName(Optional.ofNullable(request.getName()).orElse(request.getFileName())).setFileName(request.getFileName())
|
||||
.setSize(request.getSize()).setType(request.getType()).setDescription(request.getDescription()).setLocation(path)
|
||||
.setStorageType(storeService.getType().getValue());
|
||||
final var docName = Optional.ofNullable(request.getName()).orElse(request.getFileName());
|
||||
|
||||
// Some document "slots" (e.g. a client's signature) are single-slot, mirroring
|
||||
// m_client.image_id: re-upload should replace the existing row in place rather than
|
||||
// leave the old one behind as an orphan whose ordering readers then disagree about.
|
||||
// Adapters recognize their own (entityType, name) convention and own the pointer.
|
||||
final var signatureAdapter = signatureIdAdapters.stream()
|
||||
.filter(adapter -> adapter.accept(request.getEntityType(), docName)).findFirst();
|
||||
|
||||
final var doc = signatureAdapter.flatMap(adapter -> adapter.get(request.getEntityId()))
|
||||
.flatMap(result -> documentRepository.findById(result.getId())).map(existing -> {
|
||||
// replacing an existing single-slot document: drop the old file, reuse the row
|
||||
storeService.delete(existing.getLocation());
|
||||
return existing;
|
||||
}).orElseGet(Document::new);
|
||||
|
||||
doc.setParentEntityType(request.getEntityType()).setParentEntityId(request.getEntityId()).setName(docName)
|
||||
.setFileName(request.getFileName()).setSize(request.getSize()).setType(request.getType())
|
||||
.setDescription(request.getDescription()).setLocation(path).setStorageType(storeService.getType().getValue());
|
||||
|
||||
documentRepository.save(doc);
|
||||
|
||||
signatureAdapter.ifPresent(adapter -> adapter.set(request.getEntityId(), doc.getId()));
|
||||
|
||||
businessEventNotifierService.notifyPostBusinessEvent(new DocumentCreatedBusinessEvent(documentMapper.map(doc)));
|
||||
|
||||
return DocumentCreateResponse.builder().resourceId(doc.getId()).resourceIdentifier(request.getEntityType()).build();
|
||||
|
||||
Reference in New Issue
Block a user