FINERACT-2421: Refractor redundant and some deprecated code as per new Java 21 style (Phase 4)

This commit is contained in:
Aman-Mittal
2026-01-08 22:32:39 +01:00
committed by Adam Saghy
parent 174da7d862
commit d1e456ef43
19 changed files with 322 additions and 300 deletions
@@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
@@ -54,9 +53,12 @@ import org.springframework.stereotype.Component;
@Path("/v1/charges")
@Component
@Tag(name = "Charges", description = "Its typical for MFIs to add extra costs for their financial products. These are typically Fees or Penalties.\n"
+ "\n" + "A Charge on fineract platform is what we use to model both Fees and Penalties.\n" + "\n"
+ "At present we support defining charges for use with Client accounts and both loan and saving products.")
@Tag(name = "Charges", description = """
Its typical for MFIs to add extra costs for their financial products. These are typically Fees or Penalties.
A Charge on fineract platform is what we use to model both Fees and Penalties.
At present we support defining charges for use with Client accounts and both loan and saving products.""")
@RequiredArgsConstructor
public class ChargesApiResource {
@@ -71,8 +73,12 @@ public class ChargesApiResource {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Charges", description = "Returns the list of defined charges.\n" + "\n" + "Example Requests:\n" + "\n"
+ "charges")
@Operation(summary = "Retrieve Charges", description = """
Returns the list of defined charges.
Example Requests:
charges""")
public List<ChargeData> retrieveAllCharges() {
context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
return readPlatformService.retrieveAllCharges();
@@ -82,10 +88,13 @@ public class ChargesApiResource {
@Path("{chargeId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve a Charge", description = "Returns the details of a defined Charge.\n" + "\n" + "Example Requests:\n"
+ "\n" + "charges/1")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.GetChargesResponse.class))) })
@Operation(summary = "Retrieve a Charge", description = """
Returns the details of a defined Charge.
Example Requests:
charges/1""")
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.GetChargesResponse.class)))
public ChargeData retrieveCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
@@ -104,8 +113,15 @@ public class ChargesApiResource {
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Charge Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:\n"
+ "\n" + "Field Defaults\n" + "Allowed description Lists\n" + "Example Request:\n" + "\n" + "charges/template\n")
@Operation(summary = "Retrieve Charge Template", description = """
This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:
Field Defaults
Allowed description Lists
Example Request:
charges/template
""")
public ChargeData retrieveNewChargeDetails() {
context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
return readPlatformService.retrieveNewChargeDetails();
@@ -116,8 +132,7 @@ public class ChargesApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create/Define a Charge", description = "Define a new charge that can later be associated with loans and savings through their respective product definitions or directly on each account instance.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ChargeRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PostChargesResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PostChargesResponse.class)))
public CommandProcessingResult createCharge(@Parameter(hidden = true) ChargeRequest chargeRequest) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().createCharge()
.withJson(toApiJsonSerializer.serialize(chargeRequest)).build();
@@ -130,8 +145,7 @@ public class ChargesApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update a Charge", description = "Updates the details of a Charge.")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ChargeRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PutChargesChargeIdResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.PutChargesChargeIdResponse.class)))
public CommandProcessingResult updateCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId,
@Parameter(hidden = true) ChargeRequest chargeRequest) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCharge(chargeId)
@@ -143,8 +157,7 @@ public class ChargesApiResource {
@Path("{chargeId}")
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Delete a Charge", description = "Deletes a Charge.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.DeleteChargesChargeIdResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ChargesApiResourceSwagger.DeleteChargesChargeIdResponse.class)))
public CommandProcessingResult deleteCharge(@PathParam("chargeId") @Parameter(description = "chargeId") final Long chargeId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCharge(chargeId).build();
return commandsSourceWritePlatformService.logCommandSource(commandRequest);
@@ -55,7 +55,7 @@ public class CodeConstants {
@Override
public String toString() {
return name().toString().replaceAll("_", " ");
return name().replace("_", " ");
}
public String getValue() {
@@ -39,32 +39,17 @@ public enum ClientStatus {
public static ClientStatus fromInt(final Integer statusValue) {
ClientStatus enumeration = ClientStatus.INVALID;
switch (statusValue) {
case 100:
enumeration = ClientStatus.PENDING;
break;
case 300:
enumeration = ClientStatus.ACTIVE;
break;
case 303:
enumeration = ClientStatus.TRANSFER_IN_PROGRESS;
break;
case 304:
enumeration = ClientStatus.TRANSFER_ON_HOLD;
break;
case 600:
enumeration = ClientStatus.CLOSED;
break;
case 700:
enumeration = ClientStatus.REJECTED;
break;
case 800:
enumeration = ClientStatus.WITHDRAWN;
break;
return switch (statusValue) {
case 100 -> ClientStatus.PENDING;
case 300 -> ClientStatus.ACTIVE;
case 303 -> ClientStatus.TRANSFER_IN_PROGRESS;
case 304 -> ClientStatus.TRANSFER_ON_HOLD;
case 600 -> ClientStatus.CLOSED;
case 700 -> ClientStatus.REJECTED;
case 800 -> ClientStatus.WITHDRAWN;
default -> ClientStatus.INVALID;
};
}
return enumeration;
}
public static ClientStatus fromString(final String clientString) {
@@ -40,6 +40,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
@@ -61,15 +62,18 @@ import org.springframework.security.core.userdetails.User;
@Table(name = "m_appuser", uniqueConstraints = @UniqueConstraint(columnNames = { "username" }, name = "username_org"))
public class AppUser extends AbstractPersistableCustom<Long> implements PlatformUser {
@Getter
@Column(name = "email", nullable = false, length = 100)
private String email;
@Column(name = "username", nullable = false, length = 100)
private String username;
@Getter
@Column(name = "firstname", nullable = false, length = 100)
private String firstname;
@Getter
@Column(name = "lastname", nullable = false, length = 100)
private String lastname;
@@ -94,27 +98,33 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
@Column(name = "is_deleted", nullable = false)
private boolean deleted;
@Getter
@ManyToOne
@JoinColumn(name = "office_id", nullable = false)
private Office office;
@Getter
@ManyToOne
@JoinColumn(name = "staff_id", nullable = true)
private Staff staff;
@Getter
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "m_appuser_role", joinColumns = @JoinColumn(name = "appuser_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
@Getter
@Column(name = "last_time_password_updated")
private LocalDate lastTimePasswordUpdated;
@Column(name = "password_never_expires", nullable = false)
private boolean passwordNeverExpires;
@Getter
@Column(name = "is_self_service_user", nullable = false)
private boolean isSelfServiceUser;
@Getter
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "appUser")
private Set<AppUserClientMapping> appUserClientMappings = new HashSet<>();
@@ -206,14 +216,13 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
private void updatePassword(JsonCommand command, PlatformPasswordEncoder platformPasswordEncoder, Map<String, Object> actualChanges) {
final String passwordParamName = PASSWORD;
if (command.hasParameter(passwordParamName)) {
if (command.isChangeInPasswordParameterNamed(passwordParamName, this.password, platformPasswordEncoder, getId())) {
final String passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder,
getId());
actualChanges.put(passwordParamName, true);
updatePassword(passwordEncodedValue);
}
if (command.hasParameter(passwordParamName)
&& command.isChangeInPasswordParameterNamed(passwordParamName, this.password, platformPasswordEncoder, getId())) {
final String passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder, getId());
actualChanges.put(passwordParamName, true);
updatePassword(passwordEncodedValue);
}
}
public void updatePassword(final String encodePassword) {
@@ -303,20 +312,18 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
final String passwordNeverExpire = "passwordNeverExpires";
if (command.hasParameter(passwordNeverExpire)) {
if (command.isChangeInBooleanParameterNamed(passwordNeverExpire, this.passwordNeverExpires)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(passwordNeverExpire);
actualChanges.put(passwordNeverExpire, newValue);
this.passwordNeverExpires = newValue;
}
if (command.hasParameter(passwordNeverExpire)
&& command.isChangeInBooleanParameterNamed(passwordNeverExpire, this.passwordNeverExpires)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(passwordNeverExpire);
actualChanges.put(passwordNeverExpire, newValue);
this.passwordNeverExpires = newValue;
}
if (command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)) {
if (command.isChangeInBooleanParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER, this.isSelfServiceUser)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER);
actualChanges.put(AppUserConstants.IS_SELF_SERVICE_USER, newValue);
this.isSelfServiceUser = newValue;
}
if (command.hasParameter(AppUserConstants.IS_SELF_SERVICE_USER)
&& command.isChangeInBooleanParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER, this.isSelfServiceUser)) {
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(AppUserConstants.IS_SELF_SERVICE_USER);
actualChanges.put(AppUserConstants.IS_SELF_SERVICE_USER, newValue);
this.isSelfServiceUser = newValue;
}
if (this.isSelfServiceUser && command.hasParameter(AppUserConstants.CLIENTS)) {
@@ -345,7 +352,7 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
roleIds.add(role.getId().toString());
}
return roleIds.toArray(new String[roleIds.size()]);
return roleIds.toArray(new String[0]);
}
/**
@@ -372,11 +379,7 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
public boolean isSystemUser() {
// TODO Determine system user by ID not by user name
if (this.username.equals(AppUserConstants.SYSTEM_USER_NAME)) {
return true;
}
return false;
return this.username.equals(AppUserConstants.SYSTEM_USER_NAME);
}
@Override
@@ -440,38 +443,10 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
return hasAnyPermission("BYPASS_LOAN_WRITE_PROTECTION");
}
public String getFirstname() {
return this.firstname;
}
public String getLastname() {
return this.lastname;
}
public String getEmail() {
return this.email;
}
public Set<Role> getRoles() {
return this.roles;
}
public Office getOffice() {
return this.office;
}
public Staff getStaff() {
return this.staff;
}
public boolean getPasswordNeverExpires() {
return this.passwordNeverExpires;
}
public LocalDate getLastTimePasswordUpdated() {
return this.lastTimePasswordUpdated;
}
public boolean canNotApproveLoanInPast() {
return hasNotPermissionForAnyOf("ALL_FUNCTIONS", "APPROVEINPAST_LOAN");
}
@@ -494,11 +469,7 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
public boolean hasNotPermissionForReport(final String reportName) {
if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", "REPORTING_SUPER_USER", "READ_" + reportName)) {
return true;
}
return false;
return hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", "REPORTING_SUPER_USER", "READ_" + reportName);
}
public boolean hasNotPermissionForDatatable(final String datatable, final String accessType) {
@@ -507,18 +478,10 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
if (accessType.equalsIgnoreCase("READ")) {
if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", matchPermission)) {
return true;
}
return false;
return hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", matchPermission);
}
if (hasNotPermissionForAnyOf("ALL_FUNCTIONS", matchPermission)) {
return true;
}
return false;
return hasNotPermissionForAnyOf("ALL_FUNCTIONS", matchPermission);
}
public boolean hasNotPermissionForAnyOf(final String... permissionCodes) {
@@ -696,12 +659,11 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
passwordEncodedValue = command.passwordValueOfParameterNamed(passwordParamName, platformPasswordEncoder, getId());
}
} else if (command.hasParameter(passwordEncodedParamName)) {
if (command.isChangeInStringParameterNamed(passwordEncodedParamName, this.password)) {
} else if (command.hasParameter(passwordEncodedParamName)
&& command.isChangeInStringParameterNamed(passwordEncodedParamName, this.password)) {
passwordEncodedValue = command.stringValueOfParameterNamed(passwordEncodedParamName);
passwordEncodedValue = command.stringValueOfParameterNamed(passwordEncodedParamName);
}
}
return passwordEncodedValue;
@@ -711,17 +673,9 @@ public class AppUser extends AbstractPersistableCustom<Long> implements Platform
return !isEnabled();
}
public boolean isSelfServiceUser() {
return this.isSelfServiceUser;
}
public Set<AppUserClientMapping> getAppUserClientMappings() {
return this.appUserClientMappings;
}
private Set<AppUserClientMapping> createAppUserClientMappings(Collection<Client> clients) {
Set<AppUserClientMapping> newAppUserClientMappings = null;
if (clients != null && clients.size() > 0) {
if (clients != null && !clients.isEmpty()) {
newAppUserClientMappings = new HashSet<>();
for (Client client : clients) {
newAppUserClientMappings.add(new AppUserClientMapping(this, client));
@@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
@@ -56,10 +55,17 @@ import org.springframework.stereotype.Component;
@Component
@Path("/v1/{entityType}/{entityId}/documents")
@Tag(name = "Documents", description = "Multiple Documents (a combination of a name, description and a file) may be attached to different Entities like Clients, Groups, Staff, Loans, Savings and Client Identifiers in the system\n"
+ "\n" + "Note: The currently allowed Entities are\n" + "\n" + "Clients: URL Pattern as clients\n" + "Staff: URL Pattern as staff\n"
+ "Loans: URL Pattern as loans\n" + "Savings: URL Pattern as savings\n" + "Client Identifiers: URL Pattern as client_identifiers\n"
+ "Groups: URL Pattern as groups")
@Tag(name = "Documents", description = """
Multiple Documents (a combination of a name, description and a file) may be attached to different Entities like Clients, Groups, Staff, Loans, Savings and Client Identifiers in the system
Note: The currently allowed Entities are
Clients: URL Pattern as clients
Staff: URL Pattern as staff
Loans: URL Pattern as loans
Savings: URL Pattern as savings
Client Identifiers: URL Pattern as client_identifiers
Groups: URL Pattern as groups""")
@RequiredArgsConstructor
public class DocumentManagementApiResource {
@@ -73,8 +79,14 @@ public class DocumentManagementApiResource {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "List documents", description = "Example Requests:\n" + "\n" + "clients/1/documents\n" + "\n"
+ "client_identifiers/1/documents\n" + "\n" + "loans/1/documents?fields=name,description")
@Operation(summary = "List documents", description = """
Example Requests:
clients/1/documents
client_identifiers/1/documents
loans/1/documents?fields=name,description""")
public List<DocumentData> retrieveAllDocuments(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId) {
@@ -87,12 +99,24 @@ public class DocumentManagementApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@RequestBody(description = "Create document", content = {
@Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = DocumentManagementApiResourceSwagger.DocumentUploadRequest.class)) })
@Operation(summary = "Create a Document", description = "Note: A document is created using a Multi-part form upload \n" + "\n"
+ "Body Parts\n" + "\n" + "name : \n" + "Name or summary of the document\n" + "\n" + "description : \n"
+ "Description of the document\n" + "\n" + "file : \n" + "The file to be uploaded\n" + "\n" + "Mandatory Fields : \n"
+ "file and description")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Not Shown (multi-part form data)", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.PostEntityTypeEntityIdDocumentsResponse.class))) })
@Operation(summary = "Create a Document", description = """
Note: A document is created using a Multi-part form upload\s
Body Parts
name :\s
Name or summary of the document
description :\s
Description of the document
file :\s
The file to be uploaded
Mandatory Fields :\s
file and description""")
@ApiResponse(responseCode = "200", description = "Not Shown (multi-part form data)", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.PostEntityTypeEntityIdDocumentsResponse.class)))
public CommandProcessingResult createDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@HeaderParam("Content-Length") @Parameter(description = "Content-Length") final Long fileSize,
@@ -116,11 +140,17 @@ public class DocumentManagementApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@RequestBody(description = "Update document", content = {
@Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = DocumentManagementApiResourceSwagger.DocumentUploadRequest.class)) })
@Operation(summary = "Update a Document", description = "Note: A document is updated using a Multi-part form upload \n" + "Body Parts\n"
+ "name\n" + "Name or summary of the document\n" + "description\n" + "Description of the document\n" + "file\n"
+ "The file to be uploaded")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Not Shown (multi-part form data)", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.PutEntityTypeEntityIdDocumentsResponse.class))) })
@Operation(summary = "Update a Document", description = """
Note: A document is updated using a Multi-part form upload\s
Body Parts
name
Name or summary of the document
description
Description of the document
file
The file to be uploaded""")
@ApiResponse(responseCode = "200", description = "Not Shown (multi-part form data)", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.PutEntityTypeEntityIdDocumentsResponse.class)))
public CommandProcessingResult updateDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId,
@@ -159,8 +189,16 @@ public class DocumentManagementApiResource {
@Path("{documentId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve a Document", description = "Example Requests:\n" + "\n" + "clients/1/documents/1\n" + "\n" + "\n"
+ "loans/1/documents/1\n" + "\n" + "\n" + "client_identifiers/1/documents/1?fields=name,description")
@Operation(summary = "Retrieve a Document", description = """
Example Requests:
clients/1/documents/1
loans/1/documents/1
client_identifiers/1/documents/1?fields=name,description""")
public DocumentData getDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId) {
@@ -173,9 +211,16 @@ public class DocumentManagementApiResource {
@Path("{documentId}/attachment")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_OCTET_STREAM })
@Operation(summary = "Retrieve Binary File associated with Document", description = "Request used to download the file associated with the document\n"
+ "\n" + "Example Requests:\n" + "\n" + "clients/1/documents/1/attachment\n" + "\n" + "\n" + "loans/1/documents/1/attachment")
@ApiResponses({ @ApiResponse(responseCode = "200", description = "Not Shown: The corresponding Binary file") })
@Operation(summary = "Retrieve Binary File associated with Document", description = """
Request used to download the file associated with the document
Example Requests:
clients/1/documents/1/attachment
loans/1/documents/1/attachment""")
@ApiResponse(responseCode = "200", description = "Not Shown: The corresponding Binary file")
public Response downloadFile(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId) {
@@ -190,8 +235,8 @@ public class DocumentManagementApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Remove a Document", description = "")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.DeleteEntityTypeEntityIdDocumentsResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.DeleteEntityTypeEntityIdDocumentsResponse.class)))
public CommandProcessingResult deleteDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId) {
@@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
@@ -59,6 +58,7 @@ public class DelinquencyApiResource {
private final DefaultToApiJsonSerializer<DelinquencyRangeData> jsonSerializerRange;
private final DelinquencyReadPlatformService readPlatformService;
private final PortfolioCommandSourceWritePlatformService commandWritePlatformService;
public static final String DELINQUENCY_BUCKET = "DELINQUENCY_BUCKET";
@GET
@Path("ranges")
@@ -66,7 +66,7 @@ public class DelinquencyApiResource {
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "List all Delinquency Ranges", description = "")
public List<DelinquencyRangeData> getDelinquencyRanges() {
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasReadPermission(DELINQUENCY_BUCKET);
return this.readPlatformService.retrieveAllDelinquencyRanges();
}
@@ -77,7 +77,7 @@ public class DelinquencyApiResource {
@Operation(summary = "Retrieve a specific Delinquency Range based on the Id", description = "")
public DelinquencyRangeData getDelinquencyRange(
@PathParam("delinquencyRangeId") @Parameter(description = "delinquencyRangeId") final Long delinquencyRangeId) {
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasReadPermission(DELINQUENCY_BUCKET);
return this.readPlatformService.retrieveDelinquencyRange(delinquencyRangeId);
}
@@ -87,10 +87,9 @@ public class DelinquencyApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create Delinquency Range", description = "")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyRangeRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyRangeResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyRangeResponse.class)))
public CommandProcessingResult createDelinquencyRange(final DelinquencyRangeRequest delinquencyRangeRequest) {
securityContext.authenticatedUser().validateHasCreatePermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasCreatePermission(DELINQUENCY_BUCKET);
final CommandWrapper commandRequest = new CommandWrapperBuilder().createDelinquencyRange()
.withJson(jsonSerializerRange.serialize(delinquencyRangeRequest)).build();
@@ -103,12 +102,11 @@ public class DelinquencyApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update Delinquency Range based on the Id", description = "")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyRangeRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PutDelinquencyRangeResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PutDelinquencyRangeResponse.class)))
public CommandProcessingResult updateDelinquencyRange(
@PathParam("delinquencyRangeId") @Parameter(description = "delinquencyRangeId") final Long delinquencyRangeId,
final DelinquencyRangeRequest delinquencyRangeRequest) {
securityContext.authenticatedUser().validateHasUpdatePermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasUpdatePermission(DELINQUENCY_BUCKET);
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDelinquencyRange(delinquencyRangeId)
.withJson(jsonSerializerRange.serialize(delinquencyRangeRequest)).build();
@@ -120,11 +118,10 @@ public class DelinquencyApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update Delinquency Range based on the Id", description = "")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.DeleteDelinquencyRangeResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.DeleteDelinquencyRangeResponse.class)))
public CommandProcessingResult deleteDelinquencyRange(
@PathParam("delinquencyRangeId") @Parameter(description = "delinquencyRangeId") final Long delinquencyRangeId) {
securityContext.authenticatedUser().validateHasDeletePermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasDeletePermission(DELINQUENCY_BUCKET);
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDelinquencyRange(delinquencyRangeId).build();
return commandWritePlatformService.logCommandSource(commandRequest);
@@ -136,7 +133,7 @@ public class DelinquencyApiResource {
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "List all Delinquency Buckets", description = "")
public List<DelinquencyBucketData> getDelinquencyBuckets() {
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasReadPermission(DELINQUENCY_BUCKET);
return this.readPlatformService.retrieveAllDelinquencyBuckets();
}
@@ -147,7 +144,7 @@ public class DelinquencyApiResource {
@Operation(summary = "Retrieve a specific Delinquency Bucket based on the Id", description = "")
public DelinquencyBucketData getDelinquencyBucket(
@PathParam("delinquencyBucketId") @Parameter(description = "delinquencyBucketId") final Long delinquencyBucketId) {
securityContext.authenticatedUser().validateHasReadPermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasReadPermission(DELINQUENCY_BUCKET);
return this.readPlatformService.retrieveDelinquencyBucket(delinquencyBucketId);
}
@@ -157,10 +154,10 @@ public class DelinquencyApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create Delinquency Bucket", description = "")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyBucketRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyBucketResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PostDelinquencyBucketResponse.class)))
public CommandProcessingResult createDelinquencyBucket(final DelinquencyBucketRequest delinquencyBucketRequest) {
securityContext.authenticatedUser().validateHasCreatePermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasCreatePermission(DELINQUENCY_BUCKET);
final CommandWrapper commandRequest = new CommandWrapperBuilder().createDelinquencyBucket()
.withJson(jsonSerializerBucket.serialize(delinquencyBucketRequest)).build();
@@ -173,12 +170,12 @@ public class DelinquencyApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update Delinquency Bucket based on the Id", description = "")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = DelinquencyBucketRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PutDelinquencyBucketResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.PutDelinquencyBucketResponse.class)))
public CommandProcessingResult updateDelinquencyBucket(
@PathParam("delinquencyBucketId") @Parameter(description = "delinquencyBucketId") final Long delinquencyBucketId,
final DelinquencyBucketRequest delinquencyBucketRequest) {
securityContext.authenticatedUser().validateHasUpdatePermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasUpdatePermission(DELINQUENCY_BUCKET);
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateDelinquencyBucket(delinquencyBucketId)
.withJson(jsonSerializerBucket.serialize(delinquencyBucketRequest)).build();
@@ -190,11 +187,11 @@ public class DelinquencyApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Delete Delinquency Bucket based on the Id", description = "")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.DeleteDelinquencyBucketResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DelinquencyApiResourceSwagger.DeleteDelinquencyBucketResponse.class)))
public CommandProcessingResult deleteDelinquencyBucket(
@PathParam("delinquencyBucketId") @Parameter(description = "delinquencyBucketId") final Long delinquencyBucketId) {
securityContext.authenticatedUser().validateHasDeletePermission("DELINQUENCY_BUCKET");
securityContext.authenticatedUser().validateHasDeletePermission(DELINQUENCY_BUCKET);
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteDelinquencyBucket(delinquencyBucketId).build();
return commandWritePlatformService.logCommandSource(commandRequest);
@@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.delinquency.service;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -139,14 +138,8 @@ public class DelinquencyWritePlatformServiceHelper {
}
public List<DelinquencyRange> sortDelinquencyRangesByMinAge(List<DelinquencyRange> ranges) {
final Comparator<DelinquencyRange> orderByMinAge = new Comparator<DelinquencyRange>() {
@Override
public int compare(DelinquencyRange o1, DelinquencyRange o2) {
return o1.getMinimumAgeDays().compareTo(o2.getMinimumAgeDays());
}
};
Collections.sort(ranges, orderByMinAge);
final Comparator<DelinquencyRange> orderByMinAge = Comparator.comparing(DelinquencyRange::getMinimumAgeDays);
ranges.sort(orderByMinAge);
return ranges;
}
@@ -87,11 +87,9 @@ public class CheckDueInstallmentsBusinessStep implements LoanCOBBusinessStep {
ThreadLocalContextUtil.setActionContext(ActionContext.COB);
}
}
}, duration -> {
log.debug(
"Ending custom snapshot event processing for loan with Id [{}], account number [{}], external Id [{}], finished in [{}]ms.",
loan.getId(), loan.getAccountNumber(), externalId, duration.toMillis());
});
}, duration -> log.debug(
"Ending custom snapshot event processing for loan with Id [{}], account number [{}], external Id [{}], finished in [{}]ms.",
loan.getId(), loan.getAccountNumber(), externalId, duration.toMillis()));
return loan;
}
@@ -44,8 +44,6 @@ public class ChargeWorkbookPopulator extends AbstractWorkbookPopulator {
worksheet.setColumnWidth(ChargeConstants.CHARGE_NAME_COL, TemplatePopulateImportConstants.SMALL_COL_SIZE);
worksheet.setColumnWidth(ChargeConstants.CHARGE_AMOUNT_COL, TemplatePopulateImportConstants.MEDIUM_COL_SIZE);
worksheet.setColumnWidth(ChargeConstants.CHARGE_CALCULATION_TYPE_COL, TemplatePopulateImportConstants.MEDIUM_COL_SIZE);
// worksheet.setColumnWidth(ChargeConstants.CHARGE_DUE_DATE_COL,
// TemplatePopulateImportConstants.MEDIUM_COL_SIZE);
worksheet.setColumnWidth(ChargeConstants.CHARGE_TIME_TYPE_COL, TemplatePopulateImportConstants.MEDIUM_COL_SIZE);
writeString(0, rowHeader, "ID");
@@ -56,19 +54,4 @@ public class ChargeWorkbookPopulator extends AbstractWorkbookPopulator {
writeString(ChargeConstants.CHARGE_TIME_TYPE_COL, rowHeader, "Charge Time Type*");
}
@SuppressWarnings("unused")
private void setRules(Sheet workSheet, final String dateFormat) {
// CellRangeAddressList dueDateRange = new CellRangeAddressList(1, SpreadsheetVersion.EXCEL97.getLastRowIndex(),
// ChargeConstants.CHARGE_DUE_DATE_COL, ChargeConstants.CHARGE_DUE_DATE_COL);
// DataValidationHelper validationHelper = new HSSFDataValidationHelper((HSSFSheet) workSheet);
// DataValidationConstraint dueDateConstraint = validationHelper
// .createDateConstraint(DataValidationConstraint.OperatorType.GREATER_OR_EQUAL, "=TODAY()", null, dateFormat);
// DataValidation dueDateValidation = validationHelper.createValidation(dueDateConstraint, dueDateRange);
// workSheet.addValidationData(dueDateValidation);
}
}
@@ -92,8 +92,13 @@ public class ClientAddressApiResource {
@Path("/{clientid}/addresses")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "List all addresses for a Client", description = "Example Requests:\n" + "\n" + "client/1/addresses\n" + "\n"
+ "\n" + "clients/1/addresses?status=false,true&&type=1,2,3")
@Operation(summary = "List all addresses for a Client", description = """
Example Requests:
client/1/addresses
clients/1/addresses?status=false,true&&type=1,2,3""")
public List<AddressData> getAddresses(@QueryParam("status") @Parameter(description = "status") final String status,
@QueryParam("type") @Parameter(description = "type") final long addressTypeId,
@PathParam("clientid") @Parameter(description = "clientId") final long clientid) {
@@ -105,11 +110,14 @@ public class ClientAddressApiResource {
@Path("/{clientid}/addresses")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update an address for a Client", description = "All the address fields can be updated by using update client address API\n"
+ "\n" + "Mandatory Fields\n" + "type and addressId")
@Operation(summary = "Update an address for a Client", description = """
All the address fields can be updated by using update client address API
Mandatory Fields
type and addressId""")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientAddressRequest.class)))
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientAddressApiResourcesSwagger.PutClientClientIdAddressesResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientAddressApiResourcesSwagger.PutClientClientIdAddressesResponse.class)))
public CommandProcessingResult updateClientAddress(@PathParam("clientid") @Parameter(description = "clientId") final long clientid,
@Parameter(hidden = true) ClientAddressRequest clientAddressRequest) {
@@ -34,17 +34,12 @@ public class ClientAddressRepositoryWrapper {
public ClientAddress findOneByClientIdAndAddressTypeAndIsActive(final long clientId, final CodeValue addressType,
final boolean isActive) {
final ClientAddress clientAddress = this.clientAddressRepository.findByClientIdAndAddressTypeAndIsActive(clientId, addressType,
isActive);
// if (clientAddress == null) { throw new
// AddressNotFoundException(clientId, addressType); }
return clientAddress;
return this.clientAddressRepository.findByClientIdAndAddressTypeAndIsActive(clientId, addressType, isActive);
}
public ClientAddress findOneByClientIdAndAddressId(final long clientId, final long addressId) {
final ClientAddress clientAddress = this.clientAddressRepository.findByClientIdAndAddressId(clientId, addressId);
return clientAddress;
return this.clientAddressRepository.findByClientIdAndAddressId(clientId, addressId);
}
}
@@ -73,8 +73,7 @@ public final class ClientEnumerations {
}
public static EnumOptionData legalForm(final LegalForm legalForm) {
final EnumOptionData optionData = new EnumOptionData(legalForm.getValue().longValue(), legalForm.getCode(), legalForm.toString());
return optionData;
return new EnumOptionData(legalForm.getValue().longValue(), legalForm.getCode(), legalForm.toString());
}
public static List<EnumOptionData> legalForm(final LegalForm[] legalForms) {
@@ -90,9 +89,8 @@ public final class ClientEnumerations {
}
public static EnumOptionData clientTransactionType(final ClientTransactionType clientTransactionType) {
final EnumOptionData optionData = new EnumOptionData(clientTransactionType.getValue().longValue(), clientTransactionType.getCode(),
return new EnumOptionData(clientTransactionType.getValue().longValue(), clientTransactionType.getCode(),
clientTransactionType.toString());
return optionData;
}
public static List<EnumOptionData> clientTransactionType(final ClientTransactionType[] clientTransactionTypes) {
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.client.domain;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
public enum ClientTransactionType {
@@ -43,7 +44,9 @@ public enum ClientTransactionType {
}
private static final Map<Integer, ClientTransactionType> intToEnumMap = new HashMap<>();
@Getter
private static int minValue;
@Getter
private static int maxValue;
static {
@@ -64,21 +67,12 @@ public enum ClientTransactionType {
}
public static ClientTransactionType fromInt(final int i) {
final ClientTransactionType type = intToEnumMap.get(Integer.valueOf(i));
return type;
}
public static int getMinValue() {
return minValue;
}
public static int getMaxValue() {
return maxValue;
return intToEnumMap.get(i);
}
@Override
public String toString() {
return name().toString();
return name();
}
}
@@ -21,7 +21,6 @@ package org.apache.fineract.portfolio.client.service.search;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.service.PagedRequest;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.client.domain.ClientRepository;
@@ -58,7 +57,7 @@ public class ClientSearchService {
Optional<ClientTextSearch> request = searchRequest.getRequest();
String requestSearchText = request.map(ClientTextSearch::getText).orElse(null);
String searchText = StringUtils.defaultString(requestSearchText, "");
String searchText = Objects.toString(requestSearchText, "");
Pageable pageable = searchRequest.toPageable();
@@ -28,17 +28,17 @@ public class CollateralCannotBeCreatedException extends AbstractPlatformDomainRu
LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE;
public String errorMessage() {
if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
if (name().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
return "This collateral cannot be created as the loan it is associated with is not in submitted and pending approval stage";
}
return name().toString();
return name();
}
public String errorCode() {
if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
if (name().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
return "error.msg.loan.collateral.associated.loan.not.in.submitted.and.pending.approval.stage";
}
return name().toString();
return name();
}
}
@@ -24,7 +24,6 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
@@ -109,8 +108,7 @@ public class ClientCollateralManagementApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Operation(summary = "Add New Collateral For a Client", description = "Add New Collateral For a Client")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = ClientCollateralRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientCollateralManagementApiResourceSwagger.PostClientCollateralResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientCollateralManagementApiResourceSwagger.PostClientCollateralResponse.class)))
public CommandProcessingResult addCollateral(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId,
@Parameter(hidden = true) ClientCollateralRequest clientCollateralRequest) {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().addClientCollateralProduct(clientId)
@@ -125,8 +123,7 @@ public class ClientCollateralManagementApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update New Collateral of a Client", description = "Update New Collateral of a Client")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = UpdateClientCollateralRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientCollateralManagementApiResourceSwagger.PutClientCollateralResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientCollateralManagementApiResourceSwagger.PutClientCollateralResponse.class)))
public CommandProcessingResult updateCollateral(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId,
@PathParam("collateralId") @Parameter(description = "collateralId") final Long collateralId,
@Parameter(hidden = true) UpdateClientCollateralRequest updateClientCollateralRequest) {
@@ -142,8 +139,8 @@ public class ClientCollateralManagementApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
@Operation(summary = "Delete Client Collateral", description = "Delete Client Collateral")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientCollateralManagementApiResourceSwagger.DeleteClientCollateralResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = ClientCollateralManagementApiResourceSwagger.DeleteClientCollateralResponse.class)))
public CommandProcessingResult deleteCollateral(@PathParam("clientId") @Parameter(description = "clientId") final Long clientId,
@PathParam("collateralId") @Parameter(description = "collateralId") final Long collateralId) {
final CommandWrapper commandWrapper = new CommandWrapperBuilder().deleteClientCollateralProduct(collateralId, clientId).build();
@@ -38,7 +38,7 @@ public class ClientCollateralCannotBeDeletedException extends AbstractPlatformDo
if (name().equalsIgnoreCase("CLIENT_COLLATERAL_IS_ALREADY_ATTACHED")) {
return "error.msg.client.collateral.is.already.associated.with.loan.collateral";
}
return name().toString();
return name();
}
}
@@ -47,6 +47,8 @@ public class ClientCollateralManagementWritePlatformServiceImpl implements Clien
private final ClientCollateralManagementRepositoryWrapper clientCollateralManagementRepositoryWrapper;
private final CollateralManagementRepositoryWrapper collateralManagementRepositoryWrapper;
private final ClientRepositoryWrapper clientRepositoryWrapper;
public static final String COLLATERAL_ID = "collateralId";
public static final String QUANTITY = "quantity";
@Transactional
@Override
@@ -54,8 +56,8 @@ public class ClientCollateralManagementWritePlatformServiceImpl implements Clien
validateForCreation(command);
Long collateralId = command.longValueOfParameterNamed("collateralId");
BigDecimal quantity = command.bigDecimalValueOfParameterNamed("quantity");
Long collateralId = command.longValueOfParameterNamed(COLLATERAL_ID);
BigDecimal quantity = command.bigDecimalValueOfParameterNamed(QUANTITY);
final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(command.getClientId(), false);
@@ -73,17 +75,17 @@ public class ClientCollateralManagementWritePlatformServiceImpl implements Clien
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("client-collateral");
if (!command.parameterExists("collateralId")) {
if (!command.parameterExists(COLLATERAL_ID)) {
errorCode += "collateralId.not.exists";
baseDataValidator.reset().parameter("collateralId").failWithCode(errorCode);
baseDataValidator.reset().parameter(COLLATERAL_ID).failWithCode(errorCode);
}
if (!command.parameterExists("quantity")) {
if (!command.parameterExists(QUANTITY)) {
errorCode += ".quantity.not.exists";
baseDataValidator.reset().parameter("quantity").failWithCode(errorCode);
baseDataValidator.reset().parameter(QUANTITY).failWithCode(errorCode);
} else {
BigDecimal quantity = command.bigDecimalValueOfParameterNamed("quantity");
baseDataValidator.reset().parameter("quantity").value(quantity).notNull().positiveAmount();
BigDecimal quantity = command.bigDecimalValueOfParameterNamed(QUANTITY);
baseDataValidator.reset().parameter(QUANTITY).value(quantity).notNull().positiveAmount();
}
if (!dataValidationErrors.isEmpty()) {
@@ -109,12 +111,12 @@ public class ClientCollateralManagementWritePlatformServiceImpl implements Clien
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("client-collateral");
BigDecimal quantity = null;
if (!command.parameterExists("quantity")) {
if (!command.parameterExists(QUANTITY)) {
errorCode += ".quantity.not.exists";
baseDataValidator.reset().parameter("quantity").failWithCode(errorCode);
baseDataValidator.reset().parameter(QUANTITY).failWithCode(errorCode);
} else {
quantity = command.bigDecimalValueOfParameterNamed("quantity");
baseDataValidator.reset().parameter("quantity").value(quantity).notNull().positiveAmount();
quantity = command.bigDecimalValueOfParameterNamed(QUANTITY);
baseDataValidator.reset().parameter(QUANTITY).value(quantity).notNull().positiveAmount();
}
final ClientCollateralManagement clientCollateralManagement = this.clientCollateralManagementRepositoryWrapper
@@ -132,7 +134,7 @@ public class ClientCollateralManagementWritePlatformServiceImpl implements Clien
}
if (totalQuantity.compareTo(quantity) >= 0) {
baseDataValidator.reset().parameter("quantity").value(quantity).notLessThanMin(totalQuantity);
baseDataValidator.reset().parameter(QUANTITY).value(quantity).notLessThanMin(totalQuantity);
}
if (!dataValidationErrors.isEmpty()) {
@@ -25,7 +25,6 @@ import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
@@ -120,10 +119,20 @@ public class CentersApiResource {
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve a Center Template", description = "Retrieves a Center Template\n\n" + "Example Requests:\n\n" + "\n\n"
+ "centers/template\n\n" + "\n\n" + "centers/template?officeId=2")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersTemplateResponse.class))) })
@Operation(summary = "Retrieve a Center Template", description = """
Retrieves a Center Template
Example Requests:
centers/template
centers/template?officeId=2""")
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersTemplateResponse.class)))
public String retrieveTemplate(@Context final UriInfo uriInfo,
@QueryParam("command") @Parameter(description = "command") final String commandParam,
@QueryParam("officeId") @Parameter(description = "officeId") final Long officeId,
@@ -150,11 +159,28 @@ public class CentersApiResource {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "List Centers", description = "The default implementation supports pagination and sorting with the default pagination size set to 200 records. The parameter limit with description -1 will return all entries.\n\n"
+ "Example Requests:\n\n" + "\n\n" + "centers\n\n" + "\n\n" + "centers?fields=name,officeName,joinedDate\n\n" + "\n\n"
+ "centers?offset=10&limit=50\n\n" + "\n\n" + "centers?orderBy=name&sortOrder=DESC")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersResponse.class))) })
@Operation(summary = "List Centers", description = """
The default implementation supports pagination and sorting with the default pagination size set to 200 records. The parameter limit with description -1 will return all entries.
Example Requests:
centers
centers?fields=name,officeName,joinedDate
centers?offset=10&limit=50
centers?orderBy=name&sortOrder=DESC""")
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersResponse.class)))
public String retrieveAll(@Context final UriInfo uriInfo,
@QueryParam("officeId") @Parameter(description = "officeId") final Long officeId,
@QueryParam("staffId") @Parameter(description = "staffId") final Long staffId,
@@ -200,10 +226,20 @@ public class CentersApiResource {
@Path("{centerId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve a Center", description = "Retrieves a Center\n\n" + "Example Requests:\n\n" + "\n\n" + "centers/1\n\n"
+ "\n\n" + "centers/1?associations=groupMembers")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersCenterIdResponse.class))) })
@Operation(summary = "Retrieve a Center", description = """
Retrieves a Center
Example Requests:
centers/1
centers/1?associations=groupMembers""")
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersCenterIdResponse.class)))
public String retrieveOne(@Context final UriInfo uriInfo,
@PathParam("centerId") @Parameter(description = "centerId") final Long centerId,
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") @Parameter(description = "staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) {
@@ -254,12 +290,15 @@ public class CentersApiResource {
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Create a Center", description = "Creates a Center\n\n"
+ "Mandatory Fields: name, officeId, active, activationDate (if active=true)\n\n"
+ "Optional Fields: externalId, staffId, groupMembers")
@Operation(summary = "Create a Center", description = """
Creates a Center
Mandatory Fields: name, officeId, active, activationDate (if active=true)
Optional Fields: externalId, staffId, groupMembers""")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersResponse.class)))
public String create(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
@@ -277,8 +316,8 @@ public class CentersApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update a Center", description = "Updates a Center")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PutCentersCenterIdRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PutCentersCenterIdResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PutCentersCenterIdResponse.class)))
public String update(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId,
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
@@ -295,8 +334,7 @@ public class CentersApiResource {
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Delete a Center", description = "A Center can be deleted if it is in pending state and has no association - groups, loans or savings")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.DeleteCentersCenterIdResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.DeleteCentersCenterIdResponse.class)))
public String delete(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
@@ -310,20 +348,35 @@ public class CentersApiResource {
@Path("{centerId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Activate a Center | Generate Collection Sheet | Save Collection Sheet | Close a Center | Associate Groups | Disassociate Groups", description = "Activate a Center:\n\n"
+ "Centers can be created in a Pending state. This API exists to enable center activation. If the center happens to be already active, this API will result in an error.\n\n"
+ "Close a Center:\n\n"
+ "Centers can be closed if they don't have any non-closed groups or saving accounts. If the Center has any active groups or savings accounts, this API will result in an error.\n\n"
+ "Associate Groups:\n\n"
+ "This API allows associating existing groups to a center. The groups are listed from the office to which the center is associated. If group(s) is already associated with a center, this API will result in an error.\n\n"
+ "Disassociate Groups:\n\n" + "This API allows to disassociate groups from a center.\n\n" + "Generate Collection Sheet:\n\n"
+ "This Api retrieves repayment details of all jlg loans under a center as on a specified meeting date.\n\n"
+ "Save Collection Sheet:\n\n"
+ "This Api allows the loan officer to perform bulk repayments of JLG loans for a center on a given meeting date.\n\n"
+ "Showing Request/Response for Close a Center")
@Operation(summary = "Activate a Center | Generate Collection Sheet | Save Collection Sheet | Close a Center | Associate Groups | Disassociate Groups", description = """
Activate a Center:
Centers can be created in a Pending state. This API exists to enable center activation. If the center happens to be already active, this API will result in an error.
Close a Center:
Centers can be closed if they don't have any non-closed groups or saving accounts. If the Center has any active groups or savings accounts, this API will result in an error.
Associate Groups:
This API allows associating existing groups to a center. The groups are listed from the office to which the center is associated. If group(s) is already associated with a center, this API will result in an error.
Disassociate Groups:
This API allows to disassociate groups from a center.
Generate Collection Sheet:
This Api retrieves repayment details of all jlg loans under a center as on a specified meeting date.
Save Collection Sheet:
This Api allows the loan officer to perform bulk repayments of JLG loans for a center on a given meeting date.
Showing Request/Response for Close a Center""")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersCenterIdRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersCenterIdResponse.class))) })
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersCenterIdResponse.class)))
public String activate(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId,
@QueryParam("command") @Parameter(description = "command") final String commandParam,
@Parameter(hidden = true) final String apiRequestBodyAsJson, @Context final UriInfo uriInfo) {
@@ -373,11 +426,19 @@ public class CentersApiResource {
@Path("{centerId}/accounts")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve Center accounts overview", description = "An example of how a savings summary for a Center can be provided. This is requested in a specific use case of the reference application.\n\n"
+ "It is quite reasonable to add resources like this to simplify User Interface development.\n\n" + "\n\n"
+ "Example Requests:\n\n" + "\n\n" + "centers/9/accounts")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersCenterIdAccountsResponse.class))) })
@Operation(summary = "Retrieve Center accounts overview", description = """
An example of how a savings summary for a Center can be provided. This is requested in a specific use case of the reference application.
It is quite reasonable to add resources like this to simplify User Interface development.
Example Requests:
centers/9/accounts""")
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersCenterIdAccountsResponse.class)))
public String retrieveGroupAccount(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId,
@Context final UriInfo uriInfo) {