- Hide Family Members tab/section for non-individual entities in client view, create flow, and preview - Hide Financial & Classification section for non-individual entities in personal data and preview - Fix legal form column in clients list — fetch legalForm from client API for correct display - Add person/business icon before client name in list rows - Remove unsupportedNpd filter — send authorizedSignatory, additionalInfo, dateOfRegistration to API - Add registration number format hint (mat-hint) based on constitution type - Add spacing between verification row and constitution type dropdowns - Reduce table cell padding and prevent action buttons from being clipped - Add missing MPL-2.0 license headers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
141 lines
6.0 KiB
Java
141 lines
6.0 KiB
Java
/**
|
|
* 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<String, Object> data = toMap(json);
|
|
|
|
Optional<ClientEntityKyc> 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<ClientEntityKyc> 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<String, Object> 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<String, Object> toMap(JsonObject json) {
|
|
Map<String, Object> 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;
|
|
}
|
|
}
|