feat: non-individual entity UI improvements — hide individual-only sections, fix legal form display, send extended fields to API
- 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>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
ab01111424
commit
b890d24bb7
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user