/** * 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 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 data = toMap(addrJson); Optional 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 addresses = addressRepository.findByClientId(clientId); Map 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 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 data = toMap(json); Optional 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 toResponseMap(ClientAddressIndia addr) { Map 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 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()) map.put(e.getKey(), prim.getAsInt()); else map.put(e.getKey(), prim.getAsString()); } }); return map; } }