/** * CBS Nexora — Entity KYC REST Controller * Package: org.apache.fineract.portfolio.client.api * * Endpoints: * POST /clients/{clientId}/entity-kyc — Create or update entity KYC + MSME * GET /clients/{clientId}/entity-kyc — Retrieve entity KYC data * DELETE /clients/{clientId}/entity-kyc — Delete entity KYC data */ package org.apache.fineract.portfolio.client.api; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.portfolio.client.domain.*; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.google.gson.JsonObject; import java.util.HashMap; import java.util.Map; import java.util.Optional; @Path("/v1/clients/{clientId}/entity-kyc") @Component @Tag(name = "Client Entity KYC", description = "Non-Individual client MSME & KYC management") @RequiredArgsConstructor public class ClientEntityKycApiResource { private final ClientRepositoryWrapper clientRepository; private final ClientEntityKycRepository entityKycRepository; private final FromJsonHelper fromJsonHelper; @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @Transactional @Operation(summary = "Create or Update Entity KYC", description = "Save MSME details, entity KYC document, signatory KYC, authorization document, and risk assessment") public Response saveEntityKyc( @PathParam("clientId") Long clientId, String jsonBody) { final Client client = clientRepository.findOneWithNotFoundDetection(clientId); final JsonObject json = fromJsonHelper.parse(jsonBody).getAsJsonObject(); final Map data = toMap(json); Optional existing = entityKycRepository.findByClientId(clientId); ClientEntityKyc entityKyc; if (existing.isPresent()) { entityKyc = existing.get(); entityKyc.update(data); } else { String constitutionType = json.has("constitutionType") ? json.get("constitutionType").getAsString() : null; entityKyc = ClientEntityKyc.create(client, constitutionType); entityKyc.update(data); } entityKycRepository.saveAndFlush(entityKyc); return Response.ok(Map.of( "resourceId", entityKyc.getId(), "clientId", clientId )).build(); } @GET @Produces(MediaType.APPLICATION_JSON) @Operation(summary = "Retrieve Entity KYC", description = "Get MSME, signatory, authorization, and risk data for a non-individual client") public Response getEntityKyc(@PathParam("clientId") Long clientId) { clientRepository.findOneWithNotFoundDetection(clientId); Optional entityKyc = entityKycRepository.findByClientId(clientId); if (entityKyc.isEmpty()) { return Response.status(Response.Status.NOT_FOUND) .entity(Map.of("error", "No entity KYC found for client " + clientId)) .build(); } ClientEntityKyc kyc = entityKyc.get(); Map result = new HashMap<>(); result.put("id", kyc.getId()); result.put("clientId", clientId); result.put("constitutionType", kyc.getConstitutionType()); result.put("isMsme", kyc.getIsMsme()); result.put("udyamNumber", kyc.getUdyamNumber()); result.put("enterpriseName", kyc.getEnterpriseName()); result.put("businessSector", kyc.getBusinessSector()); result.put("msmeTurnover", kyc.getMsmeTurnover()); result.put("msmeInvestment", kyc.getMsmeInvestment()); result.put("msmeType", kyc.getMsmeType()); result.put("entityKycDocType", kyc.getEntityKycDocType()); result.put("entityKycDocNumber", kyc.getEntityKycDocNumber()); result.put("entityKycDocIssueDate", kyc.getEntityKycDocIssueDate()); result.put("entityKycDocExpiryDate", kyc.getEntityKycDocExpiryDate()); result.put("signatoryName", kyc.getSignatoryName()); result.put("signatoryDesignation", kyc.getSignatoryDesignation()); result.put("signatoryPan", kyc.getSignatoryPan()); result.put("signatoryAadhaarMasked", kyc.getSignatoryAadhaarMasked()); result.put("authorizationDocType", kyc.getAuthorizationDocType()); result.put("authorizationDocNumber", kyc.getAuthorizationDocNumber()); result.put("authorizationDate", kyc.getAuthorizationDate()); result.put("entityRiskCategory", kyc.getEntityRiskCategory()); result.put("entityRemarks", kyc.getEntityRemarks()); return Response.ok(result).build(); } @DELETE @Produces(MediaType.APPLICATION_JSON) @Transactional @Operation(summary = "Delete Entity KYC") public Response deleteEntityKyc(@PathParam("clientId") Long clientId) { clientRepository.findOneWithNotFoundDetection(clientId); entityKycRepository.deleteByClientId(clientId); return Response.ok(Map.of("clientId", clientId, "deleted", true)).build(); } private Map toMap(JsonObject json) { Map map = new HashMap<>(); json.entrySet().forEach(e -> { if (e.getValue().isJsonNull()) { map.put(e.getKey(), null); } else if (e.getValue().isJsonPrimitive()) { var prim = e.getValue().getAsJsonPrimitive(); if (prim.isBoolean()) map.put(e.getKey(), prim.getAsBoolean()); else if (prim.isNumber()) { if (prim.getAsString().contains(".")) map.put(e.getKey(), prim.getAsBigDecimal()); else map.put(e.getKey(), prim.getAsInt()); } else map.put(e.getKey(), prim.getAsString()); } }); return map; } }