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