- 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>
220 lines
8.3 KiB
Java
220 lines
8.3 KiB
Java
/**
|
|
* CBS Nexora — India Address REST Controller
|
|
* Package: org.apache.fineract.portfolio.client.api
|
|
*
|
|
* Endpoints:
|
|
* POST /clients/{clientId}/india-address — Save all 4 address types
|
|
* GET /clients/{clientId}/india-address — Get all addresses
|
|
* GET /clients/{clientId}/india-address/{type} — Get specific type
|
|
* PUT /clients/{clientId}/india-address/{type} — Update specific type
|
|
* DELETE /clients/{clientId}/india-address — Delete all addresses
|
|
*/
|
|
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.JsonArray;
|
|
import com.google.gson.JsonElement;
|
|
import com.google.gson.JsonObject;
|
|
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Path("/v1/clients/{clientId}/india-address")
|
|
@Component
|
|
@Tag(name = "Client India Address", description = "India-specific multi-type address management")
|
|
@RequiredArgsConstructor
|
|
public class ClientAddressIndiaApiResource {
|
|
|
|
private final ClientRepositoryWrapper clientRepository;
|
|
private final ClientAddressIndiaRepository addressRepository;
|
|
private final FromJsonHelper fromJsonHelper;
|
|
|
|
/**
|
|
* POST /clients/{clientId}/india-address
|
|
* Body: { "permanent": {...}, "current": {...}, "office": {...}, "correspondence": {...} }
|
|
*/
|
|
@POST
|
|
@Consumes(MediaType.APPLICATION_JSON)
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Transactional
|
|
@Operation(summary = "Save all address types", description = "Create or update Permanent, Current, Office, and Correspondence addresses")
|
|
public Response saveAllAddresses(
|
|
@PathParam("clientId") Long clientId,
|
|
String jsonBody) {
|
|
|
|
final Client client = clientRepository.findOneWithNotFoundDetection(clientId);
|
|
final JsonObject json = fromJsonHelper.parse(jsonBody).getAsJsonObject();
|
|
|
|
List<Long> savedIds = new ArrayList<>();
|
|
|
|
for (ClientAddressIndia.AddressType type : ClientAddressIndia.AddressType.values()) {
|
|
String key = type.name().toLowerCase();
|
|
if (json.has(key) && json.get(key).isJsonObject()) {
|
|
JsonObject addrJson = json.getAsJsonObject(key);
|
|
Map<String, Object> data = toMap(addrJson);
|
|
|
|
Optional<ClientAddressIndia> existing = addressRepository.findByClientIdAndAddressType(clientId, type);
|
|
ClientAddressIndia addr;
|
|
|
|
if (existing.isPresent()) {
|
|
addr = existing.get();
|
|
addr.update(data);
|
|
} else {
|
|
addr = ClientAddressIndia.create(client, type);
|
|
addr.update(data);
|
|
}
|
|
|
|
addressRepository.saveAndFlush(addr);
|
|
savedIds.add(addr.getId());
|
|
}
|
|
}
|
|
|
|
return Response.ok(Map.of(
|
|
"clientId", clientId,
|
|
"savedAddressIds", savedIds
|
|
)).build();
|
|
}
|
|
|
|
/**
|
|
* GET /clients/{clientId}/india-address
|
|
*/
|
|
@GET
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Operation(summary = "Get all addresses", description = "Retrieve all 4 address types for a client")
|
|
public Response getAllAddresses(@PathParam("clientId") Long clientId) {
|
|
clientRepository.findOneWithNotFoundDetection(clientId);
|
|
List<ClientAddressIndia> addresses = addressRepository.findByClientId(clientId);
|
|
|
|
Map<String, Object> result = new HashMap<>();
|
|
result.put("clientId", clientId);
|
|
|
|
for (ClientAddressIndia addr : addresses) {
|
|
result.put(addr.getAddressType().name().toLowerCase(), toResponseMap(addr));
|
|
}
|
|
|
|
return Response.ok(result).build();
|
|
}
|
|
|
|
/**
|
|
* GET /clients/{clientId}/india-address/{type}
|
|
*/
|
|
@GET
|
|
@Path("/{type}")
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Operation(summary = "Get specific address type")
|
|
public Response getAddress(
|
|
@PathParam("clientId") Long clientId,
|
|
@PathParam("type") String type) {
|
|
|
|
clientRepository.findOneWithNotFoundDetection(clientId);
|
|
ClientAddressIndia.AddressType addrType = ClientAddressIndia.AddressType.valueOf(type.toUpperCase());
|
|
Optional<ClientAddressIndia> addr = addressRepository.findByClientIdAndAddressType(clientId, addrType);
|
|
|
|
if (addr.isEmpty()) {
|
|
return Response.status(Response.Status.NOT_FOUND)
|
|
.entity(Map.of("error", "No " + type + " address found for client " + clientId))
|
|
.build();
|
|
}
|
|
|
|
return Response.ok(toResponseMap(addr.get())).build();
|
|
}
|
|
|
|
/**
|
|
* PUT /clients/{clientId}/india-address/{type}
|
|
*/
|
|
@PUT
|
|
@Path("/{type}")
|
|
@Consumes(MediaType.APPLICATION_JSON)
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Transactional
|
|
@Operation(summary = "Update specific address type")
|
|
public Response updateAddress(
|
|
@PathParam("clientId") Long clientId,
|
|
@PathParam("type") String type,
|
|
String jsonBody) {
|
|
|
|
final Client client = clientRepository.findOneWithNotFoundDetection(clientId);
|
|
ClientAddressIndia.AddressType addrType = ClientAddressIndia.AddressType.valueOf(type.toUpperCase());
|
|
final JsonObject json = fromJsonHelper.parse(jsonBody).getAsJsonObject();
|
|
final Map<String, Object> data = toMap(json);
|
|
|
|
Optional<ClientAddressIndia> existing = addressRepository.findByClientIdAndAddressType(clientId, addrType);
|
|
ClientAddressIndia addr;
|
|
|
|
if (existing.isPresent()) {
|
|
addr = existing.get();
|
|
addr.update(data);
|
|
} else {
|
|
addr = ClientAddressIndia.create(client, addrType);
|
|
addr.update(data);
|
|
}
|
|
|
|
addressRepository.saveAndFlush(addr);
|
|
|
|
return Response.ok(Map.of(
|
|
"resourceId", addr.getId(),
|
|
"clientId", clientId,
|
|
"addressType", type.toUpperCase()
|
|
)).build();
|
|
}
|
|
|
|
/**
|
|
* DELETE /clients/{clientId}/india-address
|
|
*/
|
|
@DELETE
|
|
@Produces(MediaType.APPLICATION_JSON)
|
|
@Transactional
|
|
@Operation(summary = "Delete all addresses")
|
|
public Response deleteAllAddresses(@PathParam("clientId") Long clientId) {
|
|
clientRepository.findOneWithNotFoundDetection(clientId);
|
|
addressRepository.deleteByClientId(clientId);
|
|
return Response.ok(Map.of("clientId", clientId, "deleted", true)).build();
|
|
}
|
|
|
|
private Map<String, Object> toResponseMap(ClientAddressIndia addr) {
|
|
Map<String, Object> map = new HashMap<>();
|
|
map.put("id", addr.getId());
|
|
map.put("addressType", addr.getAddressType().name());
|
|
map.put("addressLine1", addr.getAddressLine1());
|
|
map.put("addressLine2", addr.getAddressLine2());
|
|
map.put("pinCode", addr.getPinCode());
|
|
map.put("locality", addr.getLocality());
|
|
map.put("city", addr.getCity());
|
|
map.put("district", addr.getDistrict());
|
|
map.put("state", addr.getState());
|
|
map.put("country", addr.getCountry());
|
|
map.put("landmark", addr.getLandmark());
|
|
map.put("proofType", addr.getProofType());
|
|
map.put("residenceType", addr.getResidenceType());
|
|
map.put("sameAsPermanent", addr.getSameAsPermanent());
|
|
map.put("orgName", addr.getOrgName());
|
|
map.put("employmentType", addr.getEmploymentType());
|
|
map.put("commMode", addr.getCommMode());
|
|
return map;
|
|
}
|
|
|
|
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()) map.put(e.getKey(), prim.getAsInt());
|
|
else map.put(e.getKey(), prim.getAsString());
|
|
}
|
|
});
|
|
return map;
|
|
}
|
|
}
|