adamsaghy commented on code in PR #2783:
URL: https://github.com/apache/fineract/pull/2783#discussion_r1040850456
##########
fineract-provider/src/main/java/org/apache/fineract/portfolio/client/api/ClientsApiResource.java:
##########
@@ -415,25 +300,302 @@ public String
postClientTemplate(@QueryParam("legalFormType") final String legal
@GET
@Path("{clientId}/obligeedetails")
- @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Retrieve client obligee details", description =
"Retrieve client obligee details")
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.GetClientObligeeDetailsResponse.class))),
+ @ApiResponse(responseCode = "400", description = "Bad Request") })
public String retrieveObligeeDetails(@PathParam("clientId") final Long
clientId, @Context final UriInfo uriInfo) {
+ return retrieveClientObligeeDetails(clientId, null);
+ }
-
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
-
- final List<ObligeeData> ObligeeList =
guarantorReadPlatformService.retrieveObligeeDetails(clientId);
+ @GET
+ @Path("{clientId}/transferproposaldate")
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Retrieve client transfer template", description =
"Retrieve client transfer template")
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.GetClientTransferProposalDateResponse.class))),
+ @ApiResponse(responseCode = "400", description = "Bad Request") })
+ public String retrieveTransferTemplate(@PathParam("clientId") final Long
clientId, @Context final UriInfo uriInfo) {
+ return retrieveClientTransferTemplate(clientId, null);
+ }
- return toApiJsonSerializer.serialize(ObligeeList);
+ @GET
+ @Path("/external-id/{externalId}")
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Retrieve a Client by External Id", description =
"Example Requests:\n" + "\n" + "clients/123-456\n" + "\n" + "\n"
+ + "clients/123-456?template=true\n" + "\n" + "\n" +
"clients/123-456?fields=id,displayName,officeName")
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.GetClientsClientIdResponse.class))) })
+ public String retrieveOne(@PathParam("externalId") @Parameter(description
= "externalId") final String externalId,
+ @Context final UriInfo uriInfo,
+ @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly")
@Parameter(description = "staffInSelectedOfficeOnly") final boolean
staffInSelectedOfficeOnly) {
+ return retrieveClient(null, externalId, staffInSelectedOfficeOnly,
uriInfo);
}
@GET
- @Path("{clientId}/transferproposaldate")
+ @Path("/external-id/{externalId}/accounts")
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Retrieve client accounts overview", description =
"An example of how a loan portfolio summary can be provided. This is requested
in a specific use case of the community application.\n"
+ + "It is quite reasonable to add resources like this to simplify
User Interface development.\n" + "\n" + "Example Requests:\n "
+ + "\n" + "clients/123-456/accounts\n" + "\n" +
"clients/123-456/accounts?fields=loanAccounts,savingsAccounts")
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.GetClientsClientIdAccountsResponse.class))),
+ @ApiResponse(responseCode = "400", description = "Bad Request") })
+ public String retrieveAssociatedAccounts(@PathParam("externalId")
@Parameter(description = "externalId") final String externalId,
+ @Context final UriInfo uriInfo) {
+ return retrieveClientAccounts(null, externalId, uriInfo);
+ }
+
+ @PUT
+ @Path("/external-id/{externalId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
- public String retrieveTransferTemplate(@PathParam("clientId") final Long
clientId, @Context final UriInfo uriInfo) {
+ @Operation(summary = "Update a Client using the External Id", description
= "Note: You can update any of the basic attributes of a client (but not its
associations) using this API.\n"
+ + "\n"
+ + "Changing the relationship between a client and its office is
not supported through this API. An API specific to handling transfers of
clients between offices is available for the same.\n"
+ + "\n" + "The relationship between a client and a group must be
removed through the Groups API.")
+ @RequestBody(required = true, content = @Content(schema =
@Schema(implementation =
ClientsApiResourceSwagger.PutClientsClientIdRequest.class)))
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.PutClientsClientIdResponse.class))) })
+ public String update(@Parameter(description = "externalId")
@PathParam("externalId") final String externalId,
+ @Parameter(hidden = true) final String apiRequestBodyAsJson) {
+ return updateClient(null, externalId, apiRequestBodyAsJson);
+ }
+
+ @POST
+ @Path("/external-id/{externalId}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Activate a Client | Close a Client | Reject a Client
| Withdraw a Client | Reactivate a Client | UndoReject a Client | UndoWithdraw
a Client | Assign a Staff | Unassign a Staff | Update Default Savings Account |
Propose a Client Transfer | Withdraw a Client Transfer | Reject a Client
Transfer | Accept a Client Transfer | Propose and Accept a Client Transfer",
description = "Activate a Client:\n\n"
+ + "Clients can be created in a Pending state. This API exists to
enable client activation (for when a client becomes an approved member of the
financial Institution).\n"
+ + "\n" + "If the client happens to be already active this API will
result in an error.\n\n" + "Close a Client:\n\n"
+ + "Clients can be closed if they do not have any non-closed
loans/savingsAccount. This API exists to close a client .\n" + "\n"
+ + "If the client have any active loans/savingsAccount this API
will result in an error.\n\n" + "Reject a Client:\n\n"
+ + "Clients can be rejected when client is in pending for
activation status.\n" + "\n"
+ + "If the client is any other status, this API throws an
error.\n\n" + "Mandatory Fields: rejectionDate, rejectionReasonId\n\n"
+ + "Withdraw a Client:\n\n" + "Client applications can be withdrawn
when client is in a pending for activation status.\n" + "\n"
+ + "If the client is any other status, this API throws an
error.\n\n"
+ + "Mandatory Fields: withdrawalDate, withdrawalReasonId\n\n"
+ + "Reactivate a Client: Clients can be reactivated after they have
been closed.\n" + "\n"
+ + "Trying to reactivate a client in any other state throws an
error.\n\n" + "Mandatory Fields: reactivationDate\n\n"
+ + "UndoReject a Client:\n\n" + "Clients can be reactivated after
they have been rejected.\n" + "\n"
+ + "Trying to reactivate a client in any other state throws an
error.\n\n" + "Mandatory Fields: reopenedDate"
+ + "UndoWithdraw a Client:\n\n" + "Clients can be reactivated after
they have been withdrawn.\n" + "\n"
+ + "Trying to reactivate a client in any other state throws an
error.\n\n" + "Mandatory Fields: reopenedDate\n\n"
+ + "Assign a Staff:\n\n" + "Allows you to assign a Staff for
existed Client.\n" + "\n"
+ + "The selected Staff should belong to the same office (or an
officer higher up in the hierarchy) as the Client he manages.\n\n"
+ + "Unassign a Staff:\n\n" + "Allows you to unassign the Staff
assigned to a Client.\n\n" + "Update Default Savings Account:\n\n"
+ + "Allows you to modify or assign a default savings account for an
existing Client.\n" + "\n"
+ + "The selected savings account should be one among the existing
savings account for a particular customer.\n\n"
+ + "Propose a Client Transfer:\n\n" + "Allows you to propose the
transfer of a Client to a different Office.\n\n"
+ + "Withdraw a Client Transfer:\n\n" + "Allows you to withdraw the
proposed transfer of a Client to a different Office.\n" + "\n"
+ + "Withdrawal can happen only if the destination Branch (to which
the transfer was proposed) has not already accepted the transfer proposal\n\n"
+ + "Reject a Client Transfer:\n\n" + "Allows the Destination Branch
to reject the proposed Client Transfer.\n\n"
+ + "Accept a Client Transfer:\n\n" + "Allows the Destination Branch
to accept the proposed Client Transfer.\n" + "\n"
+ + "The destination branch may also choose to link this client to a
group (in which case, any existing active JLG loan of the client is rescheduled
to match the meeting frequency of the group) and loan Officer at the time of
accepting the transfer\n\n"
+ + "Propose and Accept a Client Transfer:\n\n"
+ + "Abstraction over the Propose and Accept Client Transfer API's
which enable a user with Data Scope over both the Target and Destination
Branches to directly transfer a Client to the destination Office.\n\n"
+ + "Showing request/response for 'Reject a Client Transfer'")
+ @RequestBody(required = true, content = @Content(schema =
@Schema(implementation =
ClientsApiResourceSwagger.PostClientsClientIdRequest.class)))
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.PostClientsClientIdResponse.class))) })
+ public String applyCommand(@PathParam("externalId") @Parameter(description
= "externalId") final String externalId,
+ @QueryParam("command") @Parameter(description = "command") final
String commandParam,
+ @Parameter(hidden = true) final String apiRequestBodyAsJson) {
+ return applyCommandOverClient(null, externalId, commandParam,
apiRequestBodyAsJson);
+ }
+
+ @DELETE
+ @Path("/external-id/{externalId}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Delete a Client", description = "If a client is in
Pending state, you are allowed to Delete it. The delete is a 'hard delete' and
cannot be recovered from. Once clients become active or have loans or savings
associated with them, you cannot delete the client but you may Close the client
if they have left the program.")
+ @RequestBody(required = true, content = @Content(schema =
@Schema(implementation =
ClientsApiResourceSwagger.DeleteClientsClientIdRequest.class)))
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.DeleteClientsClientIdResponse.class))) })
+ public String delete(@PathParam("externalId") @Parameter(description =
"externalId") final String externalId) {
+ return deleteClient(null, externalId);
+ }
+
+ @GET
+ @Path("/external-id/{externalId}/obligeedetails")
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Retrieve client obligee details", description =
"Retrieve client obligee details using the client external Id")
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.GetClientObligeeDetailsResponse.class))),
+ @ApiResponse(responseCode = "400", description = "Bad Request") })
+ public String retrieveObligeeDetails(@PathParam("externalId") final String
externalId, @Context final UriInfo uriInfo) {
+ return retrieveClientObligeeDetails(null, externalId);
+ }
+ @GET
+ @Path("/external-id/{externalId}/transferproposaldate")
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(summary = "Retrieve client transfer template", description =
"Retrieve client transfer template using the client external Id")
+ @ApiResponses({
+ @ApiResponse(responseCode = "200", description = "OK", content =
@Content(schema = @Schema(implementation =
ClientsApiResourceSwagger.GetClientTransferProposalDateResponse.class))),
+ @ApiResponse(responseCode = "400", description = "Bad Request") })
+ public String retrieveTransferTemplate(@PathParam("externalId") final
String externalId, @Context final UriInfo uriInfo) {
+ return retrieveClientTransferTemplate(null, externalId);
+ }
+
+ public String retrieveAll(final UriInfo uriInfo, final String sqlSearch,
final Long officeId, final String externalId,
+ final String displayName, final String firstname, final String
lastname, final String status, final String hierarchy,
+ final Integer offset, final Integer limit, final String orderBy,
final String sortOrder, final Boolean orphansOnly,
+ final boolean isSelfUser) {
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
+ final SearchParameters searchParameters =
SearchParameters.forClients(sqlSearch, officeId, externalId, displayName,
firstname,
+ lastname, status, hierarchy, offset, limit, orderBy,
sortOrder, orphansOnly, isSelfUser);
+ final Page<ClientData> clientData =
clientReadPlatformService.retrieveAll(searchParameters);
+ final ApiRequestJsonSerializationSettings settings =
apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+ return toApiJsonSerializer.serialize(settings, clientData,
ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
+ }
+
+ private ClientData retrieveClientData(Long clientId, final boolean
staffInSelectedOfficeOnly, final boolean isTemplate) {
+ ClientData clientData =
clientReadPlatformService.retrieveOne(clientId);
+ if (isTemplate) {
+ final ClientData templateData =
clientReadPlatformService.retrieveTemplate(clientData.getOfficeId(),
staffInSelectedOfficeOnly);
+ clientData = ClientData.templateOnTop(clientData, templateData);
+ Collection<SavingsAccountData> savingAccountOptions =
savingsAccountReadPlatformService.retrieveForLookup(clientId, null);
+ if (savingAccountOptions != null && savingAccountOptions.size() >
0) {
+ clientData =
ClientData.templateWithSavingAccountOptions(clientData, savingAccountOptions);
+ }
+ }
+ return clientData;
+ }
+
+ private Long getResolvedClientId(final Long clientId, final ExternalId
clientExternalId) {
+ Long resolvedClientId = clientId;
+ if (resolvedClientId == null) {
+ clientExternalId.throwExceptionIfEmpty();
+ resolvedClientId =
clientReadPlatformService.retrieveClientIdByExternalId(clientExternalId);
+ if (resolvedClientId == null) {
+ throw new ClientNotFoundException(resolvedClientId);
+ }
+ }
+ return resolvedClientId;
+ }
+
+ private CommandWrapper evaluateCommand(Long clientId, String commandParam,
CommandWrapperBuilder builder) {
+ CommandWrapper commandRequest = null;
+ if (CommandParameterUtil.is(commandParam, "activate")) {
+ commandRequest = builder.activateClient(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "assignStaff")) {
+ commandRequest = builder.assignClientStaff(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "unassignStaff")) {
+ commandRequest = builder.unassignClientStaff(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "close")) {
+ commandRequest = builder.closeClient(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "proposeTransfer")) {
+ commandRequest = builder.proposeClientTransfer(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam,
"proposeAndAcceptTransfer")) {
+ commandRequest =
builder.proposeAndAcceptClientTransfer(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "withdrawTransfer")) {
+ commandRequest =
builder.withdrawClientTransferRequest(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "acceptTransfer")) {
+ commandRequest = builder.acceptClientTransfer(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "rejectTransfer")) {
+ commandRequest = builder.rejectClientTransfer(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam,
"updateSavingsAccount")) {
+ commandRequest =
builder.updateClientSavingsAccount(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "reject")) {
+ commandRequest = builder.rejectClient(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "withdraw")) {
+ commandRequest = builder.withdrawClient(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "reactivate")) {
+ commandRequest = builder.reActivateClient(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "undoRejection")) {
+ commandRequest = builder.undoRejection(clientId).build();
+ } else if (CommandParameterUtil.is(commandParam, "undoWithdrawal")) {
+ commandRequest = builder.undoWithdrawal(clientId).build();
+ }
+
+ if (commandRequest == null) {
+ throw new UnrecognizedQueryParamException("command", commandParam,
+ new Object[] { "activate", "unassignStaff", "assignStaff",
"close", "proposeTransfer", "withdrawTransfer",
+ "acceptTransfer", "rejectTransfer",
"updateSavingsAccount", "reject", "withdraw", "reactivate" });
+ }
+
+ return commandRequest;
+ }
+
+ private String retrieveClient(Long clientId, String externalId, final
boolean staffInSelectedOfficeOnly, final UriInfo uriInfo) {
+
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
+
+ ExternalId clientExternalId = ExternalIdFactory.produce(externalId);
+ clientId = getResolvedClientId(clientId, clientExternalId);
+
+ final ApiRequestJsonSerializationSettings settings =
apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+ final ClientData clientData = retrieveClientData(clientId,
staffInSelectedOfficeOnly, settings.isTemplate());
+ return toApiJsonSerializer.serialize(settings, clientData,
ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
+ }
+
+ private String updateClient(Long clientId, String externalId, final String
jsonPayload) {
+ ExternalId clientExternalId = ExternalIdFactory.produce(externalId);
+ clientId = getResolvedClientId(clientId, clientExternalId);
+
+ final CommandWrapper commandRequest = new CommandWrapperBuilder() //
+ .updateClient(clientId) //
+ .withJson(jsonPayload) //
+ .build(); //
+
+ final CommandProcessingResult result =
commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ return toApiJsonSerializer.serialize(result);
+ }
+
+ private String deleteClient(Long clientId, String externalId) {
+ ExternalId clientExternalId = ExternalIdFactory.produce(externalId);
+ clientId = getResolvedClientId(clientId, clientExternalId);
+
+ final CommandWrapper commandRequest = new CommandWrapperBuilder() //
+ .deleteClient(clientId) //
+ .build(); //
+
+ final CommandProcessingResult result =
commandsSourceWritePlatformService.logCommandSource(commandRequest);
+ return toApiJsonSerializer.serialize(result);
+ }
+
+ private String retrieveClientAccounts(Long clientId, String externalId,
final UriInfo uriInfo) {
+
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
+ ExternalId clientExternalId = ExternalIdFactory.produce(externalId);
+ clientId = getResolvedClientId(clientId, clientExternalId);
+
+ final AccountSummaryCollectionData clientAccount =
accountDetailsReadPlatformService.retrieveClientAccountDetails(clientId);
+
+ final ApiRequestJsonSerializationSettings settings =
apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+ return clientAccountSummaryToApiJsonSerializer.serialize(settings,
clientAccount,
+ ClientApiConstants.CLIENT_ACCOUNTS_DATA_PARAMETERS);
+ }
+
+ private String applyCommandOverClient(Long clientId, String externalId,
final String command, final String jsonPayload) {
+ ExternalId clientExternalId = ExternalIdFactory.produce(externalId);
Review Comment:
externalId can be final
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]