Files
cbsnexora/backend-schema/ClientAddressIndiaApiResource.java
T
AdityaandClaude Opus 4.6 b890d24bb7 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>
2026-04-04 15:10:51 +05:30

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;
}
}