From 7c15fbb0c77a7376a4d9e569d8ba2ae3e903d9b4 Mon Sep 17 00:00:00 2001 From: Nitesh Yadav Date: Wed, 29 Jul 2026 11:34:18 +0530 Subject: [PATCH] fix(documentmanagement): close leaked file handles causing Windows re-upload failures; add entity KYC document CodeValues FileContentStoreService.upload() opened a FileOutputStream (write) and an InputStream (post-upload MIME check) without closing either. Windows keeps those handles open for the JVM's lifetime, so the next upsert-style delete-then-recreate of the same file (e.g. client signature/photo re-upload) failed with FileSystemException: "being used by another process". Wrapped both in try-with-resources. Also adds every distinct non-individual/constitution KYC document name (HUF, Private/Public Ltd, LLP, Partnership, Trust, Society, Proprietorship, Association, Govt/PSU, Cooperative) as a KYCIdProofType code value. resolveDocumentTypeId() on the frontend matches the picked document name against this list before creating a client_identifier; since these entity document names had no corresponding code value, every non-individual client's KYC document upload silently failed to persist. Co-Authored-By: Claude Sonnet 5 --- .../service/FileContentStoreService.java | 11 +-- .../db/changelog/tenant/changelog-tenant.xml | 1 + ...432_add_entity_kyc_document_type_codes.xml | 86 +++++++++++++++++++ 3 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 fineract-provider/src/main/resources/db/changelog/tenant/parts/0432_add_entity_kyc_document_type_codes.xml diff --git a/fineract-document/src/main/java/org/apache/fineract/infrastructure/contentstore/service/FileContentStoreService.java b/fineract-document/src/main/java/org/apache/fineract/infrastructure/contentstore/service/FileContentStoreService.java index 1f293764b..5fa86b242 100644 --- a/fineract-document/src/main/java/org/apache/fineract/infrastructure/contentstore/service/FileContentStoreService.java +++ b/fineract-document/src/main/java/org/apache/fineract/infrastructure/contentstore/service/FileContentStoreService.java @@ -95,23 +95,24 @@ public class FileContentStoreService implements ContentStoreService { final var target = Files.exists(getPath(safePath, false)) ? getPath(safePath, false) : getPath(safePath, true); - try (var in = is) { - IOUtils.copy(in, new FileOutputStream(target.toString())); + try (var in = is; var out = new FileOutputStream(target.toString())) { + IOUtils.copy(in, out); } catch (Exception e) { throw new ContentStoreException(e); } final var relativePath = getRelativePath(target); - try { - postUploadContentPolicy - .check(ContentPolicyContext.builder().path(path).inputStream(getInputStream(target)).mimeType(mimeType).build()); + try (var in = getInputStream(target)) { + postUploadContentPolicy.check(ContentPolicyContext.builder().path(path).inputStream(in).mimeType(mimeType).build()); } catch (ContentPolicyException e) { log.warn("Delete file because it didn't comply with the post-upload policy check: {} - {}", target, e.getMessage()); delete(relativePath.toString()); throw e; + } catch (IOException e) { + throw new ContentStoreException(e); } return relativePath.toString(); diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index f58a5d6d2..d8770b1c5 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -452,6 +452,7 @@ + + + + + + + INSERT INTO m_code_value (code_id, code_value, code_description, order_position, is_active, is_mandatory) + SELECT c.id, v.code_value, v.code_value, + (SELECT COALESCE(MAX(cv.order_position), 0) FROM m_code_value cv WHERE cv.code_id = c.id) + + ROW_NUMBER() OVER (ORDER BY v.code_value), + true, false + FROM m_code c + CROSS JOIN (VALUES + ('Certificate of Incorporation / Registration Certificate'), + ('PAN Card of Entity'), + ('Memorandum & Articles of Association / Partnership Deed / Trust Deed'), + ('Board Resolution / Authorization Letter'), + ('KYC of Authorized Signatory / Power of Attorney Holder'), + ('GST Registration Certificate'), + ('PAN Card of HUF'), + ('Declaration by Karta (with name, address & HUF member details)'), + ('KYC of Karta (OVDs + PAN + Photo)'), + ('Proof of Address of HUF'), + ('Certificate of Incorporation'), + ('Memorandum & Articles of Association'), + ('PAN of Company'), + ('Board Resolution (authorizing signatories)'), + ('KYC of Authorized Signatories'), + ('LLP Agreement'), + ('PAN of LLP'), + ('Designated Partners Resolution'), + ('KYC of Designated Partners / Authorized Signatories'), + ('Registration Certificate'), + ('Partnership Deed'), + ('PAN of Firm'), + ('Trust Deed'), + ('PAN of Trust'), + ('KYC of Trustees / Authorized Signatories'), + ('PAN of Society'), + ('Proof of Business Existence (GST Certificate / Shop License)'), + ('PAN of Proprietor'), + ('Proprietor''s KYC (OVDs + PAN + Photo)'), + ('PAN'), + ('Resolution authorizing signatories'), + ('Government Notification / Order'), + ('PAN (if applicable)'), + ('Authorized Signatory KYC') + ) AS v(code_value) + WHERE c.code_name = 'KYCIdProofType' + AND NOT EXISTS ( + SELECT 1 FROM m_code_value cv2 WHERE cv2.code_id = c.id AND cv2.code_value = v.code_value + ); + + + +