diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index fed93fe0e27..9469231121b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -29,10 +29,7 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_APPROVALUNDO; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_APPROVE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_APPROVE_DIVIDEND; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_ASSIGNROLE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_ASSIGNSTAFF; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_ASSOCIATECLIENTS; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_ASSOCIATEGROUPS; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_ATTACH; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_BLOCK; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_BLOCKCREDIT; @@ -67,8 +64,6 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DEPOSIT; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DETACH; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DISABLE; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DISASSOCIATECLIENTS; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DISASSOCIATEGROUPS; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DISBURSALLASTUNDO; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DISBURSALUNDO; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_DISBURSE; @@ -117,11 +112,8 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_REVERSETRANSACTION; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_SALE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_SAVE; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_SAVECOLLECTIONSHEET; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_SETFRAUD; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_SETTLECASHFROMCASHIER; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_TRANSFERCLIENTS; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UNASSIGNROLE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UNASSIGNSTAFF; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UNBLOCK; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UNBLOCKCREDIT; @@ -140,7 +132,6 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATECASHIERALLOCATION; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATEDELINQUENCY; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATELOANOFFICER; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATEROLE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATERUNNINGBALANCE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATESAVINGSACCOUNT; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ACTION_UPDATESAVINGSOFFICER; @@ -159,7 +150,6 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_ASSET_OWNER_TRANSACTION; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_BATCH_BUSINESS_STEP; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CALENDAR; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CENTER; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CHARGE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CLIENT; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_CLIENTIDENTIFIER; @@ -193,7 +183,6 @@ import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_GLACCOUNT; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_GLCLOSURE; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_GLIMLOAN; -import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_GROUP; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_GSIMACCOUNT; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_GUARANTOR; import static org.apache.fineract.commands.domain.CommandWrapperConstants.ENTITY_HOLIDAY; @@ -2271,40 +2260,6 @@ public CommandWrapperBuilder deleteCalendar(final String supportedEntityType, fi return this; } - public CommandWrapperBuilder createGroup() { - this.actionName = ACTION_CREATE; - this.entityName = ENTITY_GROUP; - this.href = "/groups/template"; - return this; - } - - public CommandWrapperBuilder updateGroup(final Long groupId) { - this.actionName = ACTION_UPDATE; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId; - return this; - } - - public CommandWrapperBuilder activateGroup(final Long groupId) { - this.actionName = ACTION_ACTIVATE; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId + "?command=activate"; - return this; - } - - public CommandWrapperBuilder saveGroupCollectionSheet(final Long groupId) { - this.actionName = ACTION_SAVECOLLECTIONSHEET; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId + "?command=saveCollectionSheet"; - return this; - } - public CommandWrapperBuilder saveIndividualCollectionSheet() { this.actionName = ACTION_SAVE; this.entityName = ENTITY_COLLECTIONSHEET; @@ -2312,69 +2267,6 @@ public CommandWrapperBuilder saveIndividualCollectionSheet() { return this; } - public CommandWrapperBuilder deleteGroup(final Long groupId) { - this.actionName = ACTION_DELETE; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId; - return this; - } - - public CommandWrapperBuilder associateClientsToGroup(final Long groupId) { - this.actionName = ACTION_ASSOCIATECLIENTS; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId + "?command=associateClients"; - return this; - } - - public CommandWrapperBuilder disassociateClientsFromGroup(final Long groupId) { - this.actionName = ACTION_DISASSOCIATECLIENTS; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId + "?command=disassociateClients"; - return this; - } - - public CommandWrapperBuilder transferClientsBetweenGroups(final Long sourceGroupId) { - this.actionName = ACTION_TRANSFERCLIENTS; - this.entityName = ENTITY_GROUP; - this.entityId = sourceGroupId; - this.groupId = sourceGroupId; - this.href = "/groups/" + sourceGroupId + "?command=transferClients"; - return this; - } - - public CommandWrapperBuilder unassignGroupStaff(final Long groupId) { - this.actionName = ACTION_UNASSIGNSTAFF; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId; - return this; - } - - public CommandWrapperBuilder assignGroupStaff(final Long groupId) { - this.actionName = ACTION_ASSIGNSTAFF; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId + "?command=assignStaff"; - return this; - } - - public CommandWrapperBuilder closeGroup(final Long groupId) { - this.actionName = ACTION_CLOSE; - this.entityName = ENTITY_GROUP; - this.entityId = groupId; - this.groupId = groupId; - this.href = "/groups/" + groupId + "?command=close"; - return this; - } - public CommandWrapperBuilder createCollateral(final Long loanId) { this.actionName = ACTION_CREATE; this.entityName = ENTITY_COLLATERAL; @@ -2437,74 +2329,6 @@ public CommandWrapperBuilder addClientCollateralProduct(final Long clientId) { return this; } - public CommandWrapperBuilder createCenter() { - this.actionName = ACTION_CREATE; - this.entityName = ENTITY_CENTER; - this.href = "/centers/template"; - return this; - } - - public CommandWrapperBuilder updateCenter(final Long centerId) { - this.actionName = ACTION_UPDATE; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.href = "/centers/" + centerId; - return this; - } - - public CommandWrapperBuilder deleteCenter(final Long centerId) { - this.actionName = ACTION_DELETE; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.href = "/centers/" + centerId; - return this; - } - - public CommandWrapperBuilder activateCenter(final Long centerId) { - this.actionName = ACTION_ACTIVATE; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.groupId = centerId; - this.href = "/centers/" + centerId + "?command=activate"; - return this; - } - - public CommandWrapperBuilder saveCenterCollectionSheet(final Long centerId) { - this.actionName = ACTION_SAVECOLLECTIONSHEET; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.groupId = centerId; - this.href = "/centers/" + centerId + "?command=saveCollectionSheet"; - return this; - } - - public CommandWrapperBuilder closeCenter(final Long centerId) { - this.actionName = ACTION_CLOSE; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.groupId = centerId; - this.href = "/centers/" + centerId + "?command=close"; - return this; - } - - public CommandWrapperBuilder associateGroupsToCenter(final Long centerId) { - this.actionName = ACTION_ASSOCIATEGROUPS; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.groupId = centerId; - this.href = "/groups/" + centerId + "?command=associateGroups"; - return this; - } - - public CommandWrapperBuilder disassociateGroupsFromCenter(final Long centerId) { - this.actionName = ACTION_DISASSOCIATEGROUPS; - this.entityName = ENTITY_CENTER; - this.entityId = centerId; - this.groupId = centerId; - this.href = "/groups/" + centerId + "?command=disassociateGroups"; - return this; - } - public CommandWrapperBuilder createAccountingRule() { this.actionName = ACTION_CREATE; this.entityName = ENTITY_ACCOUNTINGRULE; @@ -2561,33 +2385,6 @@ public CommandWrapperBuilder deleteHoliday(final Long holidayId) { return this; } - public CommandWrapperBuilder assignRole(final Long groupId) { - this.actionName = ACTION_ASSIGNROLE; - this.entityName = ENTITY_GROUP; - this.groupId = groupId; - this.entityId = null; - this.href = "/groups/" + groupId + "?command=assignRole"; - return this; - } - - public CommandWrapperBuilder unassignRole(final Long groupId, final Long roleId) { - this.actionName = ACTION_UNASSIGNROLE; - this.entityName = ENTITY_GROUP; - this.groupId = groupId; - this.entityId = roleId; - this.href = "/groups/" + groupId + "?command=unassignRole"; - return this; - } - - public CommandWrapperBuilder updateRole(final Long groupId, final Long roleId) { - this.actionName = ACTION_UPDATEROLE; - this.entityName = ENTITY_GROUP; - this.groupId = groupId; - this.entityId = roleId; - this.href = "/groups/" + groupId + "?command=updateRole"; - return this; - } - public CommandWrapperBuilder unassignClientStaff(final Long clientId) { this.actionName = ACTION_UNASSIGNSTAFF; this.entityName = ENTITY_CLIENT; diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java index 75480ed8445..acb29f62d93 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/group/data/CenterData.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.List; import java.util.Objects; +import lombok.Getter; import org.apache.commons.collections4.CollectionUtils; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; @@ -35,6 +36,7 @@ /** * Immutable data object representing groups. */ +@Getter public final class CenterData implements Serializable { private final Long id; diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java index a03593cd5cc..dc7d844d14a 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/Group.java @@ -31,15 +31,12 @@ import java.time.LocalDate; import java.util.ArrayList; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Set; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.codes.domain.CodeValue; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; @@ -281,67 +278,6 @@ public boolean isPending() { return GroupingTypeStatus.fromInt(this.status).isPending(); } - public Map update(final JsonCommand command) { - final Map actualChanges = new LinkedHashMap<>(9); - - if (command.isChangeInIntegerParameterNamed(GroupingTypesApiConstants.statusParamName, this.status)) { - final Integer newValue = command.integerValueOfParameterNamed(GroupingTypesApiConstants.statusParamName); - actualChanges.put(GroupingTypesApiConstants.statusParamName, GroupingTypeEnumerations.status(newValue)); - this.status = GroupingTypeStatus.fromInt(newValue).getValue(); - } - - if (command.isChangeInStringParameterNamed(GroupingTypesApiConstants.externalIdParamName, this.externalId)) { - final String newValue = command.stringValueOfParameterNamed(GroupingTypesApiConstants.externalIdParamName); - actualChanges.put(GroupingTypesApiConstants.externalIdParamName, newValue); - this.externalId = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInLongParameterNamed(GroupingTypesApiConstants.officeIdParamName, this.office.getId())) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.officeIdParamName); - actualChanges.put(GroupingTypesApiConstants.officeIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(GroupingTypesApiConstants.staffIdParamName, staffId())) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.staffIdParamName); - actualChanges.put(GroupingTypesApiConstants.staffIdParamName, newValue); - } - - if (command.isChangeInStringParameterNamed(GroupingTypesApiConstants.nameParamName, this.name)) { - final String newValue = command.stringValueOfParameterNamed(GroupingTypesApiConstants.nameParamName); - actualChanges.put(GroupingTypesApiConstants.nameParamName, newValue); - this.name = StringUtils.defaultIfEmpty(newValue, null); - } - - final String dateFormatAsInput = command.dateFormat(); - final String localeAsInput = command.locale(); - - if (command.isChangeInLocalDateParameterNamed(GroupingTypesApiConstants.activationDateParamName, getActivationDate())) { - final String valueAsInput = command.stringValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName); - actualChanges.put(GroupingTypesApiConstants.activationDateParamName, valueAsInput); - actualChanges.put(GroupingTypesApiConstants.dateFormatParamName, dateFormatAsInput); - actualChanges.put(GroupingTypesApiConstants.localeParamName, localeAsInput); - - this.activationDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName); - } - - if (command.isChangeInStringParameterNamed(GroupingTypesApiConstants.accountNoParamName, this.accountNumber)) { - final String newValue = command.stringValueOfParameterNamed(GroupingTypesApiConstants.accountNoParamName); - actualChanges.put(GroupingTypesApiConstants.accountNoParamName, newValue); - this.accountNumber = StringUtils.defaultIfEmpty(newValue, null); - } - - if (command.isChangeInLocalDateParameterNamed(GroupingTypesApiConstants.submittedOnDateParamName, getSubmittedOnDate())) { - final String valueAsInput = command.stringValueOfParameterNamed(GroupingTypesApiConstants.submittedOnDateParamName); - actualChanges.put(GroupingTypesApiConstants.submittedOnDateParamName, valueAsInput); - actualChanges.put(GroupingTypesApiConstants.dateFormatParamName, dateFormatAsInput); - actualChanges.put(GroupingTypesApiConstants.localeParamName, localeAsInput); - - this.submittedOnDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.submittedOnDateParamName); - } - - return actualChanges; - } - public List associateClients(final Set clientMembersSet) { final List differences = new ArrayList<>(); for (final Client client : clientMembersSet) { diff --git a/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRole.java b/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRole.java index eca7328dc28..bf699de9d7a 100644 --- a/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRole.java +++ b/fineract-core/src/main/java/org/apache/fineract/portfolio/group/domain/GroupRole.java @@ -23,14 +23,12 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import java.util.LinkedHashMap; -import java.util.Map; +import lombok.Getter; import org.apache.fineract.infrastructure.codes.domain.CodeValue; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.portfolio.client.domain.Client; -import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; +@Getter @Entity @Table(name = "m_group_roles") public class GroupRole extends AbstractPersistableCustom { @@ -61,23 +59,6 @@ public GroupRole(final Group group, final Client client, final CodeValue role) { this.role = role; } - public Map update(final JsonCommand command) { - - final Map actualChanges = new LinkedHashMap<>(2); - - if (command.isChangeInLongParameterNamed(GroupingTypesApiConstants.clientIdParamName, this.client.getId())) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.clientIdParamName); - actualChanges.put(GroupingTypesApiConstants.clientIdParamName, newValue); - } - - if (command.isChangeInLongParameterNamed(GroupingTypesApiConstants.roleParamName, this.role.getId())) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.roleParamName); - actualChanges.put(GroupingTypesApiConstants.roleParamName, newValue); - } - - return actualChanges; - } - public void updateRole(final CodeValue role) { this.role = role; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java index def9e8161f0..dcbf40860e6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/center/CenterImportHandler.java @@ -18,14 +18,14 @@ */ package org.apache.fineract.infrastructure.bulkimport.importhandler.center; -import com.google.common.reflect.TypeToken; import com.google.gson.GsonBuilder; -import java.lang.reflect.Type; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.function.Supplier; +import org.apache.fineract.command.core.CommandDispatcher; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.IdempotencyKeyGenerator; @@ -37,11 +37,13 @@ import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.EnumOptionDataValueSerializer; -import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.GroupIdSerializer; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; +import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; import org.apache.fineract.portfolio.calendar.data.CalendarData; +import org.apache.fineract.portfolio.group.command.CenterCreateCommand; +import org.apache.fineract.portfolio.group.data.CenterCreateRequest; +import org.apache.fineract.portfolio.group.data.CenterCreateResponse; import org.apache.fineract.portfolio.group.data.CenterData; import org.apache.fineract.portfolio.group.data.GroupGeneralData; import org.apache.poi.ss.usermodel.Cell; @@ -61,12 +63,14 @@ public class CenterImportHandler implements ImportHandler { private static final Logger LOG = LoggerFactory.getLogger(CenterImportHandler.class); private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final IdempotencyKeyGenerator idempotencyKeyGenerator; + private final CommandDispatcher dispatcher; @Autowired public CenterImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, - IdempotencyKeyGenerator idempotencyKeyGenerator) { + IdempotencyKeyGenerator idempotencyKeyGenerator, final CommandDispatcher dispatcher) { this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.idempotencyKeyGenerator = idempotencyKeyGenerator; + this.dispatcher = dispatcher; } @Override @@ -174,7 +178,7 @@ private Count importEntity(final Workbook workbook, final List cente Row row = centerSheet.getRow(centers.get(i).getRowIndex()); Cell errorReportCell = row.createCell(CenterConstants.FAILURE_COL); Cell statusCell = row.createCell(CenterConstants.STATUS_COL); - CommandProcessingResult result = null; + CenterCreateResponse result = null; try { String status = statuses.get(i); progressLevel = getProgressLevel(status); @@ -233,19 +237,20 @@ private int getProgressLevel(String status) { return 0; } - private CommandProcessingResult importCenter(final List centers, final int rowIndex, final String dateFormat) { - GsonBuilder gsonBuilder = GoogleGsonSerializerHelper.createGsonBuilder(); - gsonBuilder.registerTypeAdapter(LocalDate.class, new DateSerializer(dateFormat)); - Type groupCollectionType = new TypeToken>() { - - }.getType(); - gsonBuilder.registerTypeAdapter(groupCollectionType, new GroupIdSerializer()); - String payload = gsonBuilder.create().toJson(centers.get(rowIndex)); - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .createCenter() // - .withJson(payload) // - .build(); // - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + private CenterCreateResponse importCenter(final List centers, final int rowIndex, final String dateFormat) { + final CenterData row = centers.get(rowIndex); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat, JsonParserHelper.localeFromString(row.getLocale())); + final List groupIds = row.getGroupMembers() == null ? null + : row.getGroupMembers().stream().map(GroupGeneralData::getId).toList(); + final CenterCreateRequest request = CenterCreateRequest.builder().name(row.getName()).officeId(row.officeId()) + .staffId(row.staffId()).externalId(row.getExternalId()).active(row.isActive()) + .activationDate(row.getActivationDate() == null ? null : formatter.format(row.getActivationDate())) + .submittedOnDate(row.getSubmittedOnDate() == null ? null : formatter.format(row.getSubmittedOnDate())) + .groupMembers(groupIds).dateFormat(dateFormat).locale(row.getLocale()).build(); + final CenterCreateCommand command = new CenterCreateCommand(); + command.setPayload(request); + final Supplier response = dispatcher.dispatch(command); + return response.get(); } private void setReportHeaders(final Sheet sheet) { @@ -257,7 +262,7 @@ private void setReportHeaders(final Sheet sheet) { TemplatePopulateImportConstants.FAILURE_COL_REPORT_HEADER); } - private Integer importCenterMeeting(final List meetings, final CommandProcessingResult result, final int rowIndex, + private Integer importCenterMeeting(final List meetings, final CenterCreateResponse result, final int rowIndex, final String dateFormat) { CalendarData calendarData = meetings.get(rowIndex); calendarData.setTitle("centers_" + result.getGroupId().toString() + "_CollectionMeeting"); @@ -266,9 +271,8 @@ private Integer importCenterMeeting(final List meetings, final Com gsonBuilder.registerTypeAdapter(EnumOptionData.class, new EnumOptionDataValueSerializer()); String payload = gsonBuilder.create().toJson(calendarData); - CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(), - result.getLoanId(), result.getSavingsId(), null, null, null, null, null, payload, result.getTransactionId(), - result.getProductId(), null, null, null, null, idempotencyKeyGenerator.create(), null, null); + CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), null, null, null, null, null, null, + null, null, payload, null, null, null, null, null, null, idempotencyKeyGenerator.create(), null, null); final CommandWrapper commandRequest = new CommandWrapperBuilder() // .createCalendar(commandWrapper, TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) // .withJson(payload) // diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java index 227da531c7a..7b3c6c3a1f2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/importhandler/group/GroupImportHandler.java @@ -18,14 +18,14 @@ */ package org.apache.fineract.infrastructure.bulkimport.importhandler.group; -import com.google.common.reflect.TypeToken; import com.google.gson.GsonBuilder; -import java.lang.reflect.Type; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.function.Supplier; +import org.apache.fineract.command.core.CommandDispatcher; import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.IdempotencyKeyGenerator; @@ -35,14 +35,16 @@ import org.apache.fineract.infrastructure.bulkimport.data.Count; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandler; import org.apache.fineract.infrastructure.bulkimport.importhandler.ImportHandlerUtils; -import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.ClientIdSerializer; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.DateSerializer; import org.apache.fineract.infrastructure.bulkimport.importhandler.helper.EnumOptionDataValueSerializer; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper; +import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; import org.apache.fineract.portfolio.calendar.data.CalendarData; import org.apache.fineract.portfolio.client.data.ClientData; +import org.apache.fineract.portfolio.group.command.GroupCreateCommand; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; import org.apache.fineract.portfolio.group.data.GroupGeneralData; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.IndexedColors; @@ -61,12 +63,14 @@ public class GroupImportHandler implements ImportHandler { private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final IdempotencyKeyGenerator idempotencyKeyGenerator; + private final CommandDispatcher dispatcher; @Autowired public GroupImportHandler(final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, - IdempotencyKeyGenerator idempotencyKeyGenerator) { + IdempotencyKeyGenerator idempotencyKeyGenerator, final CommandDispatcher dispatcher) { this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.idempotencyKeyGenerator = idempotencyKeyGenerator; + this.dispatcher = dispatcher; } @Override @@ -178,7 +182,7 @@ private Count importEntity(final Workbook workbook, final List Row row = groupSheet.getRow(groups.get(i).getRowIndex()); Cell errorReportCell = row.createCell(GroupConstants.FAILURE_COL); Cell statusCell = row.createCell(GroupConstants.STATUS_COL); - CommandProcessingResult result = null; + GroupCreateResponse result = null; try { String status = statuses.get(i); progressLevel = getProgressLevel(status); @@ -237,7 +241,7 @@ private void setReportHeaders(Sheet groupSheet) { TemplatePopulateImportConstants.FAILURE_COL_REPORT_HEADER); } - private Integer importGroupMeeting(final List meetings, CommandProcessingResult result, int rowIndex, String dateFormat) { + private Integer importGroupMeeting(final List meetings, GroupCreateResponse result, int rowIndex, String dateFormat) { CalendarData calendarData = meetings.get(rowIndex); calendarData.setTitle("group_" + result.getGroupId().toString() + "_CollectionMeeting"); GsonBuilder gsonBuilder = GoogleGsonSerializerHelper.createGsonBuilder(); @@ -259,9 +263,8 @@ private Integer importGroupMeeting(final List meetings, CommandPro } payload = gsonBuilder.create().toJson(modifiedCalendarData); - CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(), - result.getLoanId(), result.getSavingsId(), null, null, null, null, null, payload, result.getTransactionId(), - result.getProductId(), null, null, null, null, idempotencyKeyGenerator.create(), null, null); + CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), null, null, null, null, null, null, + null, null, payload, null, null, null, null, null, null, idempotencyKeyGenerator.create(), null, null); final CommandWrapper commandRequest = new CommandWrapperBuilder() // .createCalendar(commandWrapper, TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) // .withJson(payload) // @@ -270,19 +273,20 @@ private Integer importGroupMeeting(final List meetings, CommandPro return 2; } - private CommandProcessingResult importGroup(final List groups, final int rowIndex, final String dateFormat) { - GsonBuilder gsonBuilder = GoogleGsonSerializerHelper.createGsonBuilder(); - gsonBuilder.registerTypeAdapter(LocalDate.class, new DateSerializer(dateFormat, groups.get(rowIndex).getLocale())); - Type clientCollectionType = new TypeToken>() { - - }.getType(); - gsonBuilder.registerTypeAdapter(clientCollectionType, new ClientIdSerializer()); - String payload = gsonBuilder.create().toJson(groups.get(rowIndex)); - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .createGroup() // - .withJson(payload) // - .build(); // - return commandsSourceWritePlatformService.logCommandSource(commandRequest); + private GroupCreateResponse importGroup(final List groups, final int rowIndex, final String dateFormat) { + final GroupGeneralData row = groups.get(rowIndex); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat, JsonParserHelper.localeFromString(row.getLocale())); + final List clientIds = row.getClientMembers() == null ? null + : row.getClientMembers().stream().map(ClientData::getId).toList(); + final GroupCreateRequest request = GroupCreateRequest.builder().name(row.getName()).officeId(row.getOfficeId()) + .staffId(row.getStaffId()).centerId(row.getCenterId()).externalId(row.getExternalId()).active(row.getActive()) + .activationDate(row.getActivationDate() == null ? null : formatter.format(row.getActivationDate())) + .submittedOnDate(row.getSubmittedOnDate() == null ? null : formatter.format(row.getSubmittedOnDate())) + .clientMembers(clientIds).dateFormat(dateFormat).locale(row.getLocale()).build(); + final GroupCreateCommand command = new GroupCreateCommand(); + command.setPayload(request); + final Supplier response = dispatcher.dispatch(command); + return response.get(); } private int getProgressLevel(String status) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java index 6becefa5f82..b9b4a29a001 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java @@ -25,6 +25,7 @@ import jakarta.servlet.Filter; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService; import org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; @@ -78,6 +79,9 @@ import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; import org.springframework.security.web.context.SecurityContextHolderFilter; import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; +import org.springframework.security.web.util.matcher.AndRequestMatcher; +import org.springframework.security.web.util.matcher.OrRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; @Configuration @ConditionalOnProperty("fineract.security.basicauth.enabled") @@ -89,6 +93,16 @@ public class SecurityConfig { private static final String ALL_FUNCTIONS_READ = "ALL_FUNCTIONS_READ"; private static final String ALL_FUNCTIONS_WRITE = "ALL_FUNCTIONS_WRITE"; + // Jersey treats a trailing slash as optional, so the group and centre matchers must too. + static RequestMatcher pathMatcher(final HttpMethod method, final String pattern) { + return new OrRequestMatcher(API_MATCHER.matcher(method, pattern), API_MATCHER.matcher(method, pattern + "/")); + } + + static RequestMatcher commandMatcher(final HttpMethod method, final String pattern, final String command) { + return new AndRequestMatcher(pathMatcher(method, pattern), + request -> command.equalsIgnoreCase(StringUtils.trim(request.getParameter("command")))); + } + @Autowired private ApplicationContext applicationContext; @Autowired @@ -353,6 +367,70 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_INTERESTRATECHART") .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/interestratecharts/*")) .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_INTERESTRATECHART") + // groups + .requestMatchers(pathMatcher(HttpMethod.POST, "/api/*/groups/uploadtemplate")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_GROUP") + .requestMatchers(pathMatcher(HttpMethod.POST, "/api/*/groups/*/command/unassign_staff")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UNASSIGNSTAFF_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "activate")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "ACTIVATE_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "close")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CLOSE_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "associateClients")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "ASSOCIATECLIENTS_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "disassociateClients")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DISASSOCIATECLIENTS_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "assignStaff")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "ASSIGNSTAFF_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "unassignStaff")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UNASSIGNSTAFF_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "assignRole")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "ASSIGNROLE_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "unassignRole")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UNASSIGNROLE_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "updateRole")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATEROLE_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "transferClients")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "TRANSFERCLIENTS_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "saveCollectionSheet")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "SAVECOLLECTIONSHEET_GROUP") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/groups/*", "generateCollectionSheet")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_GROUP") + .requestMatchers(pathMatcher(HttpMethod.POST, "/api/*/groups")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_GROUP") + .requestMatchers(pathMatcher(HttpMethod.PUT, "/api/*/groups/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_GROUP") + .requestMatchers(pathMatcher(HttpMethod.DELETE, "/api/*/groups/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_GROUP") + .requestMatchers(pathMatcher(HttpMethod.GET, "/api/*/groups"), pathMatcher(HttpMethod.GET, "/api/*/groups/*"), + pathMatcher(HttpMethod.GET, "/api/*/groups/*/accounts"), + pathMatcher(HttpMethod.GET, "/api/*/groups/*/glimaccounts"), + pathMatcher(HttpMethod.GET, "/api/*/groups/*/gsimaccounts")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_GROUP") + // centers + .requestMatchers(pathMatcher(HttpMethod.POST, "/api/*/centers/uploadtemplate")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_CENTER") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/centers/*", "activate")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "ACTIVATE_CENTER") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/centers/*", "close")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CLOSE_CENTER") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/centers/*", "associateGroups")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "ASSOCIATEGROUPS_CENTER") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/centers/*", "disassociateGroups")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DISASSOCIATEGROUPS_CENTER") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/centers/*", "saveCollectionSheet")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "SAVECOLLECTIONSHEET_CENTER") + .requestMatchers(commandMatcher(HttpMethod.POST, "/api/*/centers/*", "generateCollectionSheet")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_CENTER") + .requestMatchers(pathMatcher(HttpMethod.POST, "/api/*/centers")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_CENTER") + .requestMatchers(pathMatcher(HttpMethod.PUT, "/api/*/centers/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_CENTER") + .requestMatchers(pathMatcher(HttpMethod.DELETE, "/api/*/centers/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_CENTER") + .requestMatchers(pathMatcher(HttpMethod.GET, "/api/*/centers"), pathMatcher(HttpMethod.GET, "/api/*/centers/*"), + pathMatcher(HttpMethod.GET, "/api/*/centers/*/accounts")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_CENTER") // staff .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/staff/*")) .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_STAFF") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformService.java index 0ebe8b1d6ac..e000abb1a15 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformService.java @@ -20,10 +20,18 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterSaveCollectionSheetRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupSaveCollectionSheetRequest; public interface CollectionSheetWritePlatformService { CommandProcessingResult updateCollectionSheet(JsonCommand command); CommandProcessingResult saveIndividualCollectionSheet(JsonCommand command); + + GroupCommandResponse saveGroupCollectionSheet(GroupSaveCollectionSheetRequest request); + + CenterCommandResponse saveCenterCollectionSheet(CenterSaveCollectionSheetRequest request); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java index e2e787b098b..6a51719d01d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java @@ -18,6 +18,9 @@ */ package org.apache.fineract.portfolio.collectionsheet.service; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -29,12 +32,17 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.TransactionBoundApplicationEventPublisher; import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand; import org.apache.fineract.portfolio.collectionsheet.data.CollectionSheetTransactionDataValidator; import org.apache.fineract.portfolio.collectionsheet.serialization.CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer; import org.apache.fineract.portfolio.collectionsheet.serialization.CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterSaveCollectionSheetRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupSaveCollectionSheetRequest; import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; @@ -59,6 +67,7 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col private final DepositAccountWritePlatformService accountWritePlatformService; private final PaymentDetailWritePlatformService paymentDetailWritePlatformService; private final TransactionBoundApplicationEventPublisher eventPublisher; + private final FromJsonHelper fromApiJsonHelper; @Override public CommandProcessingResult updateCollectionSheet(final JsonCommand command) { @@ -157,4 +166,28 @@ private Map updateBulkMandatorySavingsDuePayments(final JsonComm changes.put("SavingsTransactions", depositTransactionIds); return changes; } + + @Override + public GroupCommandResponse saveGroupCollectionSheet(final GroupSaveCollectionSheetRequest request) { + final CommandProcessingResult result = updateCollectionSheet(toLegacyCommand(request, request.getId())); + return GroupCommandResponse.builder().groupId(request.getId()).resourceId(request.getId()).changes(result.getChanges()).build(); + } + + @Override + public CenterCommandResponse saveCenterCollectionSheet(final CenterSaveCollectionSheetRequest request) { + final CommandProcessingResult result = updateCollectionSheet(toLegacyCommand(request, request.getId())); + return CenterCommandResponse.builder().groupId(request.getId()).resourceId(request.getId()).changes(result.getChanges()).build(); + } + + private JsonCommand toLegacyCommand(final Object request, final Long groupId) { + final JsonElement parsed = toLegacyJson(request, fromApiJsonHelper); + return JsonCommand.from(parsed.toString(), parsed, fromApiJsonHelper, "GROUP", groupId, null, groupId, null, null, null, null, + "/groups/" + groupId, null, null, null, null, null); + } + + static JsonElement toLegacyJson(final Object request, final FromJsonHelper fromApiJsonHelper) { + final JsonObject json = new GsonBuilder().create().toJsonTree(request).getAsJsonObject(); + json.remove("id"); + return fromApiJsonHelper.parse(json.toString()); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CenterCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CenterCommand.java new file mode 100644 index 00000000000..0ebaea20043 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CenterCommand.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.api; + +import java.util.Arrays; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; + +public enum CenterCommand { + + ACTIVATE("activate"), // + GENERATE_COLLECTION_SHEET("generateCollectionSheet"), // + SAVE_COLLECTION_SHEET("saveCollectionSheet"), // + CLOSE("close"), // + ASSOCIATE_GROUPS("associateGroups"), // + DISASSOCIATE_GROUPS("disassociateGroups"); + + private final String value; + + CenterCommand(final String value) { + this.value = value; + } + + public static CenterCommand from(final String commandParam) { + return Arrays.stream(values()).filter(c -> StringUtils.isNotBlank(commandParam) && c.value.equalsIgnoreCase(commandParam.trim())) + .findFirst().orElseThrow(() -> new UnrecognizedQueryParamException("command", commandParam, + Arrays.stream(values()).map(c -> c.value).toArray(Object[]::new))); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java index 96ee759f0f5..6ea642eb1c0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResource.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.group.api; +import com.google.gson.Gson; import com.google.gson.JsonElement; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -26,6 +27,9 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; @@ -47,24 +51,21 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.service.CommandWrapperBuilder; -import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandDispatcher; import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType; import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookPopulatorService; -import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookService; import org.apache.fineract.infrastructure.core.annotation.AlternativeOperationId; import org.apache.fineract.infrastructure.core.api.ApiParameterHelper; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.api.DateParam; import org.apache.fineract.infrastructure.core.api.JsonQuery; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.DateFormat; import org.apache.fineract.infrastructure.core.data.PaginationParameters; import org.apache.fineract.infrastructure.core.data.UploadRequest; -import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; @@ -74,7 +75,6 @@ import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.SqlValidator; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; @@ -83,9 +83,30 @@ import org.apache.fineract.portfolio.calendar.service.CalendarReadPlatformService; import org.apache.fineract.portfolio.collectionsheet.data.JLGCollectionSheetData; import org.apache.fineract.portfolio.collectionsheet.service.CollectionSheetReadPlatformService; +import org.apache.fineract.portfolio.group.command.CenterActivateCommand; +import org.apache.fineract.portfolio.group.command.CenterAssociateGroupsCommand; +import org.apache.fineract.portfolio.group.command.CenterCloseCommand; +import org.apache.fineract.portfolio.group.command.CenterCreateCommand; +import org.apache.fineract.portfolio.group.command.CenterDeleteCommand; +import org.apache.fineract.portfolio.group.command.CenterDisassociateGroupsCommand; +import org.apache.fineract.portfolio.group.command.CenterSaveCollectionSheetCommand; +import org.apache.fineract.portfolio.group.command.CenterUpdateCommand; +import org.apache.fineract.portfolio.group.command.CenterUploadCommand; +import org.apache.fineract.portfolio.group.data.CenterCommandRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterCreateRequest; +import org.apache.fineract.portfolio.group.data.CenterCreateResponse; import org.apache.fineract.portfolio.group.data.CenterData; +import org.apache.fineract.portfolio.group.data.CenterDeleteRequest; +import org.apache.fineract.portfolio.group.data.CenterDeleteResponse; +import org.apache.fineract.portfolio.group.data.CenterUpdateRequest; +import org.apache.fineract.portfolio.group.data.CenterUpdateResponse; +import org.apache.fineract.portfolio.group.data.CenterUploadRequest; +import org.apache.fineract.portfolio.group.data.CenterUploadResponse; +import org.apache.fineract.portfolio.group.data.CentersPageResponse; import org.apache.fineract.portfolio.group.data.GroupGeneralData; import org.apache.fineract.portfolio.group.data.StaffCenterData; +import org.apache.fineract.portfolio.group.mapping.CenterCommandRequestMapper; import org.apache.fineract.portfolio.group.service.CenterReadPlatformService; import org.apache.fineract.portfolio.meeting.data.MeetingData; import org.apache.fineract.portfolio.meeting.service.MeetingReadService; @@ -94,27 +115,28 @@ import org.springframework.stereotype.Component; @Path("/v1/centers") +@Produces({ MediaType.APPLICATION_JSON }) @Component @Tag(name = "Centers", description = "Centers along with Groups are used to provided a distinctive banking distribution channel used in microfinance. Its common in areas such as Southern Asia to use Centers and Group as administrative units in grameen style lending. Typically groups will contain one to five people and centers themselves will be made of anywhere between 2-10 groups.") @RequiredArgsConstructor public class CentersApiResource { - private final PlatformSecurityContext context; private final CenterReadPlatformService centerReadPlatformService; private final ToApiJsonSerializer centerApiJsonSerializer; private final ToApiJsonSerializer toApiJsonSerializer; private final ToApiJsonSerializer groupSummaryToApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final CollectionSheetReadPlatformService collectionSheetReadPlatformService; private final FromJsonHelper fromJsonHelper; private final AccountDetailsReadPlatformService accountDetailsReadPlatformService; private final CalendarReadPlatformService calendarReadPlatformService; private final MeetingReadService meetingReadPlatformService; private final EntityDatatableChecksReadService entityDatatableChecksReadService; - private final BulkImportWorkbookService bulkImportWorkbookService; private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService; private final SqlValidator sqlValidator; + private final CommandDispatcher dispatcher; + private final Validator validator; + private final CenterCommandRequestMapper mapper; @GET @Path("template") @@ -133,14 +155,12 @@ public class CentersApiResource { centers/template?officeId=2""") @AlternativeOperationId("retrieveTemplate_6") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersTemplateResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CenterData.class))) public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("command") @Parameter(description = "command") final String commandParam, @QueryParam("officeId") @Parameter(description = "officeId") final Long officeId, @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") @Parameter(description = "staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) { - this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); - if (is(commandParam, "close")) { final CenterData centerClosureTemplate = this.centerReadPlatformService.retrieveCenterWithClosureReasons(); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); @@ -181,7 +201,7 @@ public String retrieveTemplate(@Context final UriInfo uriInfo, centers?orderBy=name&sortOrder=DESC""") @AlternativeOperationId("retrieveAll_23") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersPageResponse.class))) public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("officeId") @Parameter(description = "officeId") final Long officeId, @QueryParam("staffId") @Parameter(description = "staffId") final Long staffId, @@ -197,7 +217,6 @@ public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("dateFormat") @Parameter(description = "dateFormat") final String dateFormat, @QueryParam("locale") @Parameter(description = "locale") final String locale) { - this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); if (meetingDateParam != null && officeId != null) { LocalDate meetingDate = meetingDateParam.getDate("meetingDate", new DateFormat(dateFormat), locale); @@ -240,12 +259,11 @@ public String retrieveAll(@Context final UriInfo uriInfo, centers/1?associations=groupMembers""") @AlternativeOperationId("retrieveOne_14") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersCenterIdResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CenterData.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) { - this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); final Set associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); CalendarData collectionMeetingCalendar = null; Collection groups = null; @@ -290,7 +308,6 @@ public String retrieveOne(@Context final UriInfo uriInfo, @POST @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create a Center", operationId = "createCenter", description = """ Creates a Center @@ -298,59 +315,32 @@ public String retrieveOne(@Context final UriInfo uriInfo, Optional Fields: externalId, staffId, groupMembers""") @AlternativeOperationId("create_7") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersRequest.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() // - .createCenter() // - .withJson(apiRequestBodyAsJson) // - .build(); // - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); - + public CenterCreateResponse create(@RequestBody(required = true) final CenterCreateRequest request) { + return dispatch(new CenterCreateCommand(), validate(request)); } @PUT @Path("{centerId}") @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update a Center", operationId = "updateCenter", description = "Updates a Center") @AlternativeOperationId("update_12") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PutCentersCenterIdRequest.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) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .updateCenter(centerId) // - .withJson(apiRequestBodyAsJson) // - .build(); // - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); + public CenterUpdateResponse update(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId, + @RequestBody(required = true) final CenterUpdateRequest request) { + request.setId(centerId); + return dispatch(new CenterUpdateCommand(), validate(request)); } @DELETE @Path("{centerId}") - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Delete a Center", operationId = "deleteCenter", description = "A Center can be deleted if it is in pending state and has no association - groups, loans or savings") @AlternativeOperationId("delete_10") - @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() // - .deleteCenter(centerId) // - .build(); // - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); + public CenterDeleteResponse delete(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId) { + return dispatch(new CenterDeleteCommand(), CenterDeleteRequest.builder().id(centerId).build()); } @POST @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", operationId = "handleCommandsCenter", description = """ Activate a Center: @@ -378,52 +368,31 @@ This API allows associating existing groups to a center. The groups are listed f Showing Request/Response for Close a Center""") @AlternativeOperationId("activate_2") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.PostCentersCenterIdRequest.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) { - - final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); - - CommandProcessingResult result = null; - if (is(commandParam, "activate")) { - final CommandWrapper commandRequest = builder.activateCenter(centerId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "generateCollectionSheet")) { - final JsonElement parsedQuery = this.fromJsonHelper.parse(apiRequestBodyAsJson); - final JsonQuery query = JsonQuery.from(apiRequestBodyAsJson, parsedQuery, this.fromJsonHelper); - final JLGCollectionSheetData collectionSheet = this.collectionSheetReadPlatformService.generateCenterCollectionSheet(centerId, - query); - final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.toApiJsonSerializer.serialize(settings, collectionSheet, GroupingTypesApiConstants.COLLECTIONSHEET_DATA_PARAMETERS); - } else if (is(commandParam, "saveCollectionSheet")) { - final CommandWrapper commandRequest = builder.saveCenterCollectionSheet(centerId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "close")) { - final CommandWrapper commandRequest = builder.closeCenter(centerId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "associateGroups")) { - final CommandWrapper commandRequest = builder.associateGroupsToCenter(centerId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "disassociateGroups")) { - final CommandWrapper commandRequest = builder.disassociateGroupsFromCenter(centerId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - return this.toApiJsonSerializer.serialize(result); - } else { - throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "generateCollectionSheet", - "saveCollectionSheet", "close", "associateGroups", "disassociateGroups" }); - } - + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CenterCommandRequest.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CenterCommandResponse.class))) + public Object activate(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId, + @QueryParam("command") @Parameter(description = "command") final String commandParam, final CenterCommandRequest request, + @Context final UriInfo uriInfo) { + final CenterCommandRequest body = request == null ? new CenterCommandRequest() : request; + return switch (CenterCommand.from(commandParam)) { + case ACTIVATE -> dispatch(new CenterActivateCommand(), validate(mapper.toActivate(body, centerId))); + case GENERATE_COLLECTION_SHEET -> generateCollectionSheet(centerId, body, uriInfo); + case SAVE_COLLECTION_SHEET -> + dispatch(new CenterSaveCollectionSheetCommand(), validate(mapper.toSaveCollectionSheet(body, centerId))); + case CLOSE -> dispatch(new CenterCloseCommand(), validate(mapper.toClose(body, centerId))); + case ASSOCIATE_GROUPS -> dispatch(new CenterAssociateGroupsCommand(), validate(mapper.toAssociateGroups(body, centerId))); + case DISASSOCIATE_GROUPS -> + dispatch(new CenterDisassociateGroupsCommand(), validate(mapper.toDisassociateGroups(body, centerId))); + }; } - private boolean is(final String commandParam, final String commandValue) { - return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); + private String generateCollectionSheet(final Long centerId, final CenterCommandRequest body, final UriInfo uriInfo) { + final String json = new Gson().toJson(body); + final JsonElement parsed = fromJsonHelper.parse(json); + final JLGCollectionSheetData collectionSheet = this.collectionSheetReadPlatformService.generateCenterCollectionSheet(centerId, + JsonQuery.from(json, parsed, fromJsonHelper)); + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, collectionSheet, GroupingTypesApiConstants.COLLECTIONSHEET_DATA_PARAMETERS); } @GET @@ -442,12 +411,10 @@ private boolean is(final String commandParam, final String commandValue) { centers/9/accounts""") @AlternativeOperationId("retrieveGroupAccount") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CentersApiResourceSwagger.GetCentersCenterIdAccountsResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountSummaryCollectionData.class))) public String retrieveGroupAccount(@PathParam("centerId") @Parameter(description = "centerId") final Long centerId, @Context final UriInfo uriInfo) { - this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); - final AccountSummaryCollectionData groupAccount = this.accountDetailsReadPlatformService.retrieveGroupAccountDetails(centerId); final Set GROUP_ACCOUNTS_DATA_PARAMETERS = new HashSet<>( @@ -470,15 +437,35 @@ public Response getCentersTemplate(@QueryParam("officeId") final Long officeId, @POST @Path("uploadtemplate") @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces({ MediaType.WILDCARD }) @Operation(summary = "Upload Centers Bulk Template", operationId = "postBulkTemplateCenter") @AlternativeOperationId("postCentersTemplate") @RequestBody(description = "Upload centers template", content = { @Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = UploadRequest.class)) }) - public String postCentersTemplate(@FormDataParam("file") InputStream uploadedInputStream, + public Long postCentersTemplate(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail, @FormDataParam("locale") final String locale, @FormDataParam("dateFormat") final String dateFormat) { - final Long importDocumentId = this.bulkImportWorkbookService.importWorkbook(GlobalEntityType.CENTERS.toString(), - uploadedInputStream, fileDetail, locale, dateFormat); - return this.toApiJsonSerializer.serialize(importDocumentId); + final CenterUploadRequest request = CenterUploadRequest.builder().uploadedInputStream(uploadedInputStream).fileDetail(fileDetail) + .locale(locale).dateFormat(dateFormat).build(); + final CenterUploadResponse response = dispatch(new CenterUploadCommand(), request); + return response.getResourceId(); + } + + private boolean is(final String commandParam, final String commandValue) { + return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); + } + + private T validate(final T request) { + final Set> violations = validator.validate(request); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + return request; + } + + private ResponseT dispatch(final Command command, final RequestT payload) { + command.setPayload(payload); + final Supplier response = dispatcher.dispatch(command); + return response.get(); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResourceSwagger.java deleted file mode 100644 index 04da5592538..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/CentersApiResourceSwagger.java +++ /dev/null @@ -1,394 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.api; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDate; -import java.util.List; -import java.util.Set; - -/** - * Created by Chirag Gupta on 12/18/17. - */ -final class CentersApiResourceSwagger { - - private CentersApiResourceSwagger() {} - - @Schema(description = "GetCentersTemplateResponse") - public static final class GetCentersTemplateResponse { - - private GetCentersTemplateResponse() {} - - static final class GetCentersOfficeOptions { - - private GetCentersOfficeOptions() {} - - @Schema(example = "1") - public Long id; - @Schema(example = "Head Office") - public String name; - @Schema(example = "Head Office") - public String nameDecorated; - } - - static final class GetCentersStaffOptions { - - private GetCentersStaffOptions() {} - - @Schema(example = "2") - public Long id; - @Schema(example = "D, Mary") - public String displayName; - } - - @Schema(example = "false") - public Boolean active; - @Schema(example = "[2013, 4, 18]") - public LocalDate activationDate; - @Schema(example = "2") - public Long officeId; - public Set officeOptions; - public Set staffOptions; - } - - @Schema(description = "GetCentersResponse") - public static final class GetCentersResponse { - - private GetCentersResponse() {} - - static final class GetCentersPageItems { - - private GetCentersPageItems() {} - - static final class GetCentersStatus { - - private GetCentersStatus() {} - - @Schema(example = "100") - public Long id; - @Schema(example = "groupingStatusType.pending") - public String code; - @Schema(example = "Pending") - public String description; - } - - @Schema(example = "2") - public Long id; - public GetCentersStatus status; - @Schema(example = "false") - public Boolean active; - @Schema(example = "Center 1") - public String name; - @Schema(example = "EXT-001") - public String externalId; - @Schema(example = "1") - public Long officeId; - @Schema(example = "Head Office") - public String officeName; - @Schema(example = ".2.") - public String hierarchy; - } - - @Schema(example = "2") - public Integer totalFilteredRecords; - public Set pageItems; - } - - @Schema(description = "GetCentersCenterIdResponse") - public static final class GetCentersCenterIdResponse { - - private GetCentersCenterIdResponse() {} - - static final class GetCentersGroupMembers { - - private GetCentersGroupMembers() {} - - @Schema(example = "4") - public Long id; - @Schema(example = "AnotherGroup") - public String name; - } - - @Schema(example = "8") - public Long id; - public GetCentersResponse.GetCentersPageItems.GetCentersStatus status; - @Schema(example = "false") - public Boolean active; - @Schema(example = "First Center (No groups)") - public String name; - @Schema(example = "externalId1") - public String externalId; - @Schema(example = "1") - public Long staffId; - @Schema(example = "1") - public Long officeId; - @Schema(example = "Head Office") - public String officeName; - @Schema(example = ".8.") - public String hierarchy; - @Schema(description = "Returned when the groupMembers association is requested") - public List groupMembers; - } - - @Schema(description = "PostCentersRequest") - public static final class PostCentersRequest { - - private PostCentersRequest() {} - - @Schema(example = "First Center (No groups)") - public String name; - @Schema(example = "1") - public Long officeId; - @Schema(example = "false") - public Boolean active; - @Schema(example = "externalId1") - public String externalId; - @Schema(example = "1") - public Long staffId; - @Schema(example = "dd MMMM yyyy") - public String dateFormat; - @Schema(example = "en") - public String locale; - @Schema(example = "04 March 2011") - public String activationDate; - @Schema(description = "List of group ids to associate at creation") - public List groupMembers; - } - - @Schema(description = "PostCentersResponse") - public static final class PostCentersResponse { - - private PostCentersResponse() {} - - @Schema(example = "1") - public Long officeId; - @Schema(example = "8") - public Long groupId; - @Schema(example = "8") - public Long resourceId; - } - - @Schema(description = "PutCentersCenterIdRequest") - public static final class PutCentersCenterIdRequest { - - private PutCentersCenterIdRequest() {} - - @Schema(example = "First Center (No groups)") - public String name; - @Schema(example = "externalId1") - public String externalId; - @Schema(example = "1") - public Long staffId; - } - - @Schema(description = "PutCentersCenterIdResponse") - public static final class PutCentersCenterIdResponse { - - private PutCentersCenterIdResponse() {} - - static final class PutCentersChanges { - - private PutCentersChanges() {} - - @Schema(example = "First Center (No groups) - modified") - public String name; - @Schema(example = "externalId1") - public String externalId; - @Schema(example = "1") - public Long staffId; - } - - @Schema(example = "1") - public Long officeId; - @Schema(example = "8") - public Long groupId; - @Schema(example = "8") - public Long resourceId; - public PutCentersChanges changes; - } - - @Schema(description = "DeleteCentersCenterIdResponse") - public static final class DeleteCentersCenterIdResponse { - - private DeleteCentersCenterIdResponse() {} - - static final class DeleteCentersChanges { - - private DeleteCentersChanges() {} - } - - @Schema(example = "1") - public Long resourceId; - public DeleteCentersChanges changes; - } - - @Schema(description = "PostCentersCenterIdRequest") - public static final class PostCentersCenterIdRequest { - - private PostCentersCenterIdRequest() {} - - @Schema(example = "32") - public Long closureReasonId; - @Schema(example = "05 May 2014") - public String closureDate; - @Schema(example = "en") - public String locale; - @Schema(example = "dd MMMM yyyy") - public String dateFormat; - @Schema(description = "List of group ids to associate with or disassociate from the center") - public List groupMembers; - } - - @Schema(description = "PostCentersCenterIdResponse") - public static final class PostCentersCenterIdResponse { - - private PostCentersCenterIdResponse() {} - - static final class PostCentersCenterIdChanges { - - private PostCentersCenterIdChanges() {} - - @Schema(description = "Ids of the groups associated or disassociated by the command") - public List groupMembers; - } - - @Schema(example = "1") - public Long officeId; - @Schema(example = "1") - public Long groupId; - @Schema(example = "1") - public Long resourceId; - public PostCentersCenterIdChanges changes; - } - - @Schema(description = "GetCentersCenterIdAccountsResponse") - public static final class GetCentersCenterIdAccountsResponse { - - private GetCentersCenterIdAccountsResponse() {} - - static final class GetCentersSavingsAccounts { - - private GetCentersSavingsAccounts() {} - - static final class GetCentersCenterIdStatus { - - private GetCentersCenterIdStatus() {} - - @Schema(example = "100") - public Long id; - @Schema(example = "savingsAccountStatusType.submitted.and.pending.approval") - public String code; - @Schema(example = "Submitted and pending approval") - public String description; - @Schema(example = "true") - public Boolean submittedAndPendingApproval; - @Schema(example = "false") - public Boolean approved; - @Schema(example = "false") - public Boolean rejected; - @Schema(example = "false") - public Boolean withdrawnByApplicant; - @Schema(example = "false") - public Boolean active; - @Schema(example = "false") - public Boolean closed; - @Schema(example = "false") - public Boolean prematureClosed; - @Schema(example = "false") - public Boolean transferInProgress; - @Schema(example = "false") - public Boolean transferOnHold; - } - - static final class GetCentersCenterIdCurrency { - - private GetCentersCenterIdCurrency() {} - - @Schema(example = "USD") - public String code; - @Schema(example = "US Dollar") - public String name; - @Schema(example = "2") - public Integer decimalPlaces; - @Schema(example = "0") - public Integer inMultiplesOf; - @Schema(example = "$") - public String displaySymbol; - @Schema(example = "currency.USD") - public String nameCode; - @Schema(example = "US Dollar ($)") - public String displayLabel; - } - - static final class GetCentersAccountType { - - private GetCentersAccountType() {} - - @Schema(example = "2") - public Long id; - @Schema(example = "accountType.group") - public String code; - @Schema(example = "Group") - public String description; - } - - static final class GetCentersTimeline { - - private GetCentersTimeline() {} - - @Schema(example = "[2014, 5, 1]") - public LocalDate submittedOnDate; - @Schema(example = "mifos") - public String submittedByUsername; - @Schema(example = "App") - public String submittedByFirstname; - @Schema(example = "Administrator") - public String submittedByLastname; - } - - static final class GetCentersDepositType { - - private GetCentersDepositType() {} - - @Schema(example = "100") - public Long id; - @Schema(example = "depositAccountType.savingsDeposit") - public String code; - @Schema(example = "Savings") - public String description; - } - - @Schema(example = "16") - public Long id; - @Schema(example = "000000016") - public Long accountNo; - @Schema(example = "1") - public Long productId; - @Schema(example = "Voluntary savings") - public String productName; - public GetCentersCenterIdStatus status; - public GetCentersCenterIdCurrency currency; - public GetCentersAccountType accountType; - public GetCentersTimeline timeline; - public GetCentersDepositType depositType; - } - - public Set savingsAccounts; - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupCommand.java new file mode 100644 index 00000000000..7241e1aeec1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupCommand.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.api; + +import java.util.Arrays; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; + +public enum GroupCommand { + + ACTIVATE("activate"), // + ASSOCIATE_CLIENTS("associateClients"), // + DISASSOCIATE_CLIENTS("disassociateClients"), // + GENERATE_COLLECTION_SHEET("generateCollectionSheet"), // + SAVE_COLLECTION_SHEET("saveCollectionSheet"), // + UNASSIGN_STAFF("unassignStaff"), // + ASSIGN_STAFF("assignStaff"), // + ASSIGN_ROLE("assignRole"), // + UNASSIGN_ROLE("unassignRole"), // + UPDATE_ROLE("updateRole"), // + TRANSFER_CLIENTS("transferClients"), // + CLOSE("close"); + + private final String value; + + GroupCommand(final String value) { + this.value = value; + } + + public static GroupCommand from(final String commandParam) { + return Arrays.stream(values()).filter(c -> StringUtils.isNotBlank(commandParam) && c.value.equalsIgnoreCase(commandParam.trim())) + .findFirst().orElseThrow(() -> new UnrecognizedQueryParamException("command", commandParam, + Arrays.stream(values()).map(c -> c.value).toArray(Object[]::new))); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java index 6d42b6d5305..9926ae43488 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResource.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.group.api; +import com.google.gson.Gson; import com.google.gson.JsonElement; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -26,6 +27,9 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validator; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.DefaultValue; @@ -48,22 +52,19 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.service.CommandWrapperBuilder; -import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandDispatcher; import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType; import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookPopulatorService; -import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookService; import org.apache.fineract.infrastructure.core.annotation.AlternativeOperationId; import org.apache.fineract.infrastructure.core.api.ApiParameterHelper; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.api.JsonQuery; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.PaginationParameters; import org.apache.fineract.infrastructure.core.data.UploadRequest; -import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; @@ -73,7 +74,6 @@ import org.apache.fineract.infrastructure.dataqueries.data.EntityTables; import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum; import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksReadService; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.infrastructure.security.service.SqlValidator; import org.apache.fineract.portfolio.accountdetails.data.AccountSummaryCollectionData; import org.apache.fineract.portfolio.accountdetails.service.AccountDetailsReadPlatformService; @@ -85,8 +85,36 @@ import org.apache.fineract.portfolio.client.service.ClientReadPlatformService; import org.apache.fineract.portfolio.collectionsheet.data.JLGCollectionSheetData; import org.apache.fineract.portfolio.collectionsheet.service.CollectionSheetReadPlatformService; +import org.apache.fineract.portfolio.group.command.GroupActivateCommand; +import org.apache.fineract.portfolio.group.command.GroupAssignRoleCommand; +import org.apache.fineract.portfolio.group.command.GroupAssignStaffCommand; +import org.apache.fineract.portfolio.group.command.GroupAssociateClientsCommand; +import org.apache.fineract.portfolio.group.command.GroupCloseCommand; +import org.apache.fineract.portfolio.group.command.GroupCreateCommand; +import org.apache.fineract.portfolio.group.command.GroupDeleteCommand; +import org.apache.fineract.portfolio.group.command.GroupDisassociateClientsCommand; +import org.apache.fineract.portfolio.group.command.GroupSaveCollectionSheetCommand; +import org.apache.fineract.portfolio.group.command.GroupTransferClientsCommand; +import org.apache.fineract.portfolio.group.command.GroupUnassignRoleCommand; +import org.apache.fineract.portfolio.group.command.GroupUnassignStaffCommand; +import org.apache.fineract.portfolio.group.command.GroupUpdateCommand; +import org.apache.fineract.portfolio.group.command.GroupUpdateRoleCommand; +import org.apache.fineract.portfolio.group.command.GroupUploadCommand; +import org.apache.fineract.portfolio.group.data.GroupCommandRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; +import org.apache.fineract.portfolio.group.data.GroupDeleteRequest; +import org.apache.fineract.portfolio.group.data.GroupDeleteResponse; import org.apache.fineract.portfolio.group.data.GroupGeneralData; import org.apache.fineract.portfolio.group.data.GroupRoleData; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateResponse; +import org.apache.fineract.portfolio.group.data.GroupUploadRequest; +import org.apache.fineract.portfolio.group.data.GroupUploadResponse; +import org.apache.fineract.portfolio.group.data.GroupsPageResponse; +import org.apache.fineract.portfolio.group.mapping.GroupCommandRequestMapper; import org.apache.fineract.portfolio.group.service.CenterReadPlatformService; import org.apache.fineract.portfolio.group.service.GroupReadPlatformService; import org.apache.fineract.portfolio.group.service.GroupRolesReadPlatformService; @@ -102,6 +130,7 @@ import org.springframework.util.CollectionUtils; @Path("/v1/groups") +@Produces({ MediaType.APPLICATION_JSON }) @Component @Tag(name = "Groups", description = "Groups are used to provide a distinctive banking distribution channel used in microfinances throughout the world. The Group is an administrative unit. It can contain as few as 5 people or as many as 40 depending on how its used.\n" + "\n" @@ -109,7 +138,6 @@ @RequiredArgsConstructor public class GroupsApiResource { - private final PlatformSecurityContext context; private final GroupReadPlatformService groupReadPlatformService; private final CenterReadPlatformService centerReadPlatformService; private final ClientReadPlatformService clientReadPlatformService; @@ -119,7 +147,6 @@ public class GroupsApiResource { private final ToApiJsonSerializer glimContainerToApiJsonSerializer; private final ToApiJsonSerializer gsimContainerToApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final CollectionSheetReadPlatformService collectionSheetReadPlatformService; private final FromJsonHelper fromJsonHelper; private final GroupRolesReadPlatformService groupRolesReadPlatformService; @@ -127,11 +154,13 @@ public class GroupsApiResource { private final CalendarReadPlatformService calendarReadPlatformService; private final MeetingReadService meetingReadPlatformService; private final EntityDatatableChecksReadService entityDatatableChecksReadService; - private final BulkImportWorkbookService bulkImportWorkbookService; private final BulkImportWorkbookPopulatorService bulkImportWorkbookPopulatorService; private final GLIMAccountInfoReadPlatformService glimAccountInfoReadPlatformService; private final GSIMReadPlatformService gsimReadPlatformService; private final SqlValidator sqlValidator; + private final CommandDispatcher dispatcher; + private final Validator validator; + private final GroupCommandRequestMapper mapper; @GET @Path("template") @@ -141,7 +170,7 @@ public class GroupsApiResource { + "groups/template?officeId=2\n\n" + "\n\n" + "groups/template?centerId=1\n\n" + "\n\n" + "groups/template?centerId=1&staffInSelectedOfficeOnly=true") @AlternativeOperationId("retrieveTemplate_7") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.GetGroupsTemplateResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupGeneralData.class))) public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("officeId") @Parameter(description = "officeId") final Long officeId, @QueryParam("center") @Parameter(description = "center") final boolean isCenterGroup, @@ -149,8 +178,6 @@ public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("command") @Parameter(description = "command") final String commandParam, @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") @Parameter(description = "staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) { - context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - if (is(commandParam, "close")) { final GroupGeneralData groupClosureTemplate = groupReadPlatformService.retrieveGroupWithClosureReasons(); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); @@ -180,9 +207,10 @@ public String retrieveTemplate(@Context final UriInfo uriInfo, @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "List Groups", operationId = "retrieveAllGroups", description = "The default implementation of listing Groups returns 200 entries with support for pagination and sorting. Using the parameter limit with description -1 returns all entries.\n\n" + "Example Requests:\n\n" + "\n\n" + "groups\n\n" + "\n\n" + "groups?fields=name,officeName,joinedDate\n\n" + "\n\n" - + "groups?offset=10&limit=50\n\n" + "\n\n" + "groups?orderBy=name&sortOrder=DESC") + + "groups?offset=10&limit=50\n\n" + "\n\n" + "groups?orderBy=name&sortOrder=DESC" + + " When paged=true the response is GroupsPageResponse, otherwise a JSON array of GroupGeneralData.") @AlternativeOperationId("retrieveAll_24") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.GetGroupsResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsPageResponse.class))) public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("officeId") @Parameter(description = "officeId") final Long officeId, @QueryParam("staffId") @Parameter(description = "staffId") final Long staffId, @@ -196,7 +224,6 @@ public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("sortOrder") @Parameter(description = "sortOrder") final String sortOrder, @QueryParam("orphansOnly") @Parameter(description = "orphansOnly") final Boolean orphansOnly) { - context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); sqlValidator.validate(orderBy); sqlValidator.validate(sortOrder); sqlValidator.validate(externalId); @@ -223,12 +250,11 @@ public String retrieveAll(@Context final UriInfo uriInfo, @Operation(summary = "Retrieve a Group", operationId = "retrieveOneGroup", description = "Retrieve group information.\n\n" + "Example Requests:\n\n" + "\n\n" + "groups/1\n\n" + "\n\n" + "groups/1?associations=clientMembers") @AlternativeOperationId("retrieveOne_15") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.GetGroupsGroupIdResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupGeneralData.class))) public String retrieveOne(@Context final UriInfo uriInfo, @PathParam("groupId") @Parameter(description = "groupId") final Long groupId, @DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") @Parameter(description = "staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly, @QueryParam("roleId") @Parameter(description = "roleId") final Long roleId) { - context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); final Set associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); GroupGeneralData group = groupReadPlatformService.retrieveOne(groupId); @@ -320,82 +346,48 @@ public String retrieveOne(@Context final UriInfo uriInfo, @PathParam("groupId") @POST @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create a Group", operationId = "createGroup", description = "Creates a Group\n\n" + "Mandatory Fields: name, officeId, active, activationDate (if active=true)\n\n" + "Optional Fields: externalId, staffId, clientMembers") @AlternativeOperationId("create_8") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PostGroupsRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PostGroupsResponse.class))) - public String create(@Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .createGroup() // - .withJson(apiRequestBodyAsJson) // - .build(); // - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); + public GroupCreateResponse create(@RequestBody(required = true) final GroupCreateRequest request) { + return dispatch(new GroupCreateCommand(), validate(request)); } @POST @Path("{groupId}/command/unassign_staff") @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Unassign a Staff", operationId = "unassignLoanOfficerGroup", description = "Allows you to unassign the Staff.\n\n" + "Mandatory Fields: staffId") @AlternativeOperationId("unassignLoanOfficer") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PostGroupsGroupIdCommandUnassignStaffRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PostGroupsGroupIdCommandUnassignStaffResponse.class))) - public String unassignLoanOfficer(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, - @Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .unassignGroupStaff(groupId) // - .withJson(apiRequestBodyAsJson) // - .build(); // - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - + public GroupCommandResponse unassignLoanOfficer(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, + @RequestBody(required = true) final GroupUnassignStaffRequest request) { + request.setId(groupId); + return dispatch(new GroupUnassignStaffCommand(), validate(request)); } @PUT @Path("{groupId}") @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update a Group", operationId = "updateGroup", description = "Updates a Group") @AlternativeOperationId("update_13") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PutGroupsGroupIdRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PutGroupsGroupIdResponse.class))) - public String update(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, - @Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .updateGroup(groupId) // - .withJson(apiRequestBodyAsJson) // - .build(); // - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); + public GroupUpdateResponse update(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, + @RequestBody(required = true) final GroupUpdateRequest request) { + request.setId(groupId); + return dispatch(new GroupUpdateCommand(), validate(request)); } @DELETE @Path("{groupId}") - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Delete a Group", operationId = "deleteGroup", description = "A group can be deleted if it is in pending state and has no associations - clients, loans or savings") @AlternativeOperationId("delete_11") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.DeleteGroupsGroupIdResponse.class))) - public String delete(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder() // - .deleteGroup(groupId) // - .build(); // - final CommandProcessingResult result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); + public GroupDeleteResponse delete(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId) { + return dispatch(new GroupDeleteCommand(), GroupDeleteRequest.builder().id(groupId).build()); } @POST @Path("{groupId}") @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Activate a Group | Associate Clients | Disassociate Clients | Transfer Clients across groups | Generate Collection Sheet | Save Collection Sheet | Unassign a Staff | Assign a Staff | Close a Group | Unassign a Role | Update a Role", operationId = "handleCommandsGroup", description = "Activate a Group:\n\n" + "Groups can be created in a Pending state. This API exists to enable group activation.\n\n" + "\n\n" + "If the group happens to be already active this API will result in an error.\n\n" + "Mandatory Fields: activationDate\n\n" @@ -426,76 +418,41 @@ public String delete(@PathParam("groupId") @Parameter(description = "groupId") f + "Mandatory Fields: clientId, role\n\n" + "Unassign a Role:\n\n" + "Allows you to unassign Roles associated tp Group members.\n\n" + "Update a Role:\n\n" + "Allows you to update the member Role.\n\n" + "Mandatory Fields: role\n\n" - + "Showing request/response for Transfer Clients across groups") + + "Showing request/response for Transfer Clients across groups" + + " The generateCollectionSheet command returns JLGCollectionSheetData; all other commands return GroupCommandResponse.") @AlternativeOperationId("activateOrGenerateCollectionSheet") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PostGroupsGroupIdRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.PostGroupsGroupIdResponse.class))) - public String activateOrGenerateCollectionSheet(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = GroupCommandRequest.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupCommandResponse.class))) + public Object activateOrGenerateCollectionSheet(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, @QueryParam("command") @Parameter(description = "command") final String commandParam, - @QueryParam("roleId") @Parameter(description = "roleId") final Long roleId, - @Parameter(hidden = true) final String apiRequestBodyAsJson, @Context final UriInfo uriInfo) { - final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); - - CommandProcessingResult result = null; - if (is(commandParam, "activate")) { - final CommandWrapper commandRequest = builder.activateGroup(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "associateClients")) { - final CommandWrapper commandRequest = builder.associateClientsToGroup(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "disassociateClients")) { - final CommandWrapper commandRequest = builder.disassociateClientsFromGroup(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "generateCollectionSheet")) { - final JsonElement parsedQuery = fromJsonHelper.parse(apiRequestBodyAsJson); - final JsonQuery query = JsonQuery.from(apiRequestBodyAsJson, parsedQuery, fromJsonHelper); - final JLGCollectionSheetData collectionSheet = collectionSheetReadPlatformService.generateGroupCollectionSheet(groupId, query); - final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return toApiJsonSerializer.serialize(settings, collectionSheet, GroupingTypesApiConstants.COLLECTIONSHEET_DATA_PARAMETERS); - } else if (is(commandParam, "saveCollectionSheet")) { - final CommandWrapper commandRequest = builder.saveGroupCollectionSheet(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "unassignStaff")) { - final CommandWrapper commandRequest = builder.unassignGroupStaff(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "assignStaff")) { - final CommandWrapper commandRequest = builder.assignGroupStaff(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "assignRole")) { - final CommandWrapper commandRequest = builder.assignRole(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "unassignRole")) { - final CommandWrapper commandRequest = builder.unassignRole(groupId, roleId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "updateRole")) { - final CommandWrapper commandRequest = builder.updateRole(groupId, roleId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "transferClients")) { - final CommandWrapper commandRequest = builder.transferClientsBetweenGroups(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else if (is(commandParam, "close")) { - final CommandWrapper commandRequest = builder.closeGroup(groupId).build(); - result = commandsSourceWritePlatformService.logCommandSource(commandRequest); - return toApiJsonSerializer.serialize(result); - } else { - throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "generateCollectionSheet", - "saveCollectionSheet", "unassignStaff", "assignRole", "unassignRole", "updateassignRole" }); - } - + @QueryParam("roleId") @Parameter(description = "roleId") final Long roleId, final GroupCommandRequest request, + @Context final UriInfo uriInfo) { + final GroupCommandRequest body = request == null ? new GroupCommandRequest() : request; + return switch (GroupCommand.from(commandParam)) { + case ACTIVATE -> dispatch(new GroupActivateCommand(), validate(mapper.toActivate(body, groupId))); + case ASSOCIATE_CLIENTS -> dispatch(new GroupAssociateClientsCommand(), validate(mapper.toAssociateClients(body, groupId))); + case DISASSOCIATE_CLIENTS -> + dispatch(new GroupDisassociateClientsCommand(), validate(mapper.toDisassociateClients(body, groupId))); + case GENERATE_COLLECTION_SHEET -> generateCollectionSheet(groupId, body, uriInfo); + case SAVE_COLLECTION_SHEET -> + dispatch(new GroupSaveCollectionSheetCommand(), validate(mapper.toSaveCollectionSheet(body, groupId))); + case UNASSIGN_STAFF -> dispatch(new GroupUnassignStaffCommand(), validate(mapper.toUnassignStaff(body, groupId))); + case ASSIGN_STAFF -> dispatch(new GroupAssignStaffCommand(), validate(mapper.toAssignStaff(body, groupId))); + case ASSIGN_ROLE -> dispatch(new GroupAssignRoleCommand(), validate(mapper.toAssignRole(body, groupId))); + case UNASSIGN_ROLE -> dispatch(new GroupUnassignRoleCommand(), validate(mapper.toUnassignRole(body, groupId, roleId))); + case UPDATE_ROLE -> dispatch(new GroupUpdateRoleCommand(), validate(mapper.toUpdateRole(body, groupId, roleId))); + case TRANSFER_CLIENTS -> dispatch(new GroupTransferClientsCommand(), validate(mapper.toTransferClients(body, groupId))); + case CLOSE -> dispatch(new GroupCloseCommand(), validate(mapper.toClose(body, groupId))); + }; } - private boolean is(final String commandParam, final String commandValue) { - return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); + private String generateCollectionSheet(final Long groupId, final GroupCommandRequest body, final UriInfo uriInfo) { + final String json = new Gson().toJson(body); + final JsonElement parsed = fromJsonHelper.parse(json); + final JLGCollectionSheetData collectionSheet = collectionSheetReadPlatformService.generateGroupCollectionSheet(groupId, + JsonQuery.from(json, parsed, fromJsonHelper)); + final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return toApiJsonSerializer.serialize(settings, collectionSheet, GroupingTypesApiConstants.COLLECTIONSHEET_DATA_PARAMETERS); } @GET @@ -505,12 +462,10 @@ private boolean is(final String commandParam, final String commandValue) { + "\n\n" + "Example Requests:\n\n" + "\n\n" + "groups/1/accounts\n\n" + "\n\n" + "\n\n" + "groups/1/accounts?fields=loanAccounts,savingsAccounts,memberLoanAccounts,\n\n" + "memberSavingsAccounts") @AlternativeOperationId("retrieveAccounts") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GroupsApiResourceSwagger.GetGroupsGroupIdAccountsResponse.class))) + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = AccountSummaryCollectionData.class))) public String retrieveAccounts(@PathParam("groupId") @Parameter(description = "groupId") final Long groupId, @Context final UriInfo uriInfo) { - context.authenticatedUser().validateHasReadPermission("GROUP"); - final AccountSummaryCollectionData groupAccount = accountDetailsReadPlatformService.retrieveGroupAccountDetails(groupId); final Set GROUP_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("loanAccounts", @@ -533,16 +488,18 @@ public Response getGroupsTemplate(@QueryParam("officeId") final Long officeId, @ @POST @Path("uploadtemplate") @Consumes(MediaType.MULTIPART_FORM_DATA) + @Produces({ MediaType.WILDCARD }) @Operation(summary = "Upload Groups Bulk Template", operationId = "postBulkTemplateGroup") @AlternativeOperationId("postGroupTemplate") @RequestBody(description = "Upload group template", content = { @Content(mediaType = MediaType.MULTIPART_FORM_DATA, schema = @Schema(implementation = UploadRequest.class)) }) - public String postGroupTemplate(@FormDataParam("file") InputStream uploadedInputStream, + public Long postGroupTemplate(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail, @FormDataParam("locale") final String locale, @FormDataParam("dateFormat") final String dateFormat) { - final Long importDocumentId = bulkImportWorkbookService.importWorkbook(GlobalEntityType.GROUPS.toString(), uploadedInputStream, - fileDetail, locale, dateFormat); - return toApiJsonSerializer.serialize(importDocumentId); + final GroupUploadRequest request = GroupUploadRequest.builder().uploadedInputStream(uploadedInputStream).fileDetail(fileDetail) + .locale(locale).dateFormat(dateFormat).build(); + final GroupUploadResponse response = dispatch(new GroupUploadCommand(), request); + return response.getResourceId(); } @GET @@ -552,7 +509,6 @@ public String postGroupTemplate(@FormDataParam("file") InputStream uploadedInput @AlternativeOperationId("retrieveglimAccounts") public String retrieveglimAccounts(@PathParam("groupId") final Long groupId, @QueryParam("parentLoanAccountNo") final String parentLoanAccountNo, @Context final UriInfo uriInfo) { - context.authenticatedUser().validateHasReadPermission("GROUP"); List glimContainer = Collections.emptyList(); if (parentLoanAccountNo == null) { glimContainer = (List) glimAccountInfoReadPlatformService.findGlimAccount(groupId); @@ -578,7 +534,6 @@ public String retrieveGsimAccounts(@PathParam("groupId") final Long groupId, @QueryParam("parentGSIMAccountNo") final String parentGSIMAccountNo, @QueryParam("parentGSIMId") final Long parentGSIMId, @Context final UriInfo uriInfo) { List gsimContainer; - context.authenticatedUser().validateHasReadPermission("GROUP"); if (parentGSIMAccountNo == null && parentGSIMId != null) { gsimContainer = gsimReadPlatformService.findGsimAccountContainerbyGsimAccountId(parentGSIMId); @@ -597,4 +552,21 @@ public String retrieveGsimAccounts(@PathParam("groupId") final Long groupId, } + private boolean is(final String commandParam, final String commandValue) { + return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue); + } + + private T validate(final T request) { + final Set> violations = validator.validate(request); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + return request; + } + + private ResponseT dispatch(final Command command, final RequestT payload) { + command.setPayload(payload); + final Supplier response = dispatcher.dispatch(command); + return response.get(); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResourceSwagger.java deleted file mode 100644 index e9fed4aeb1a..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/api/GroupsApiResourceSwagger.java +++ /dev/null @@ -1,590 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.api; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDate; -import java.util.List; -import java.util.Set; - -/** - * Created by Chirag Gupta on 12/10/17. - */ -final class GroupsApiResourceSwagger { - - private GroupsApiResourceSwagger() {} - - @Schema(description = "GetGroupsTemplateResponse") - public static final class GetGroupsTemplateResponse { - - private GetGroupsTemplateResponse() {} - - static final class GetGroupsTemplateOfficeOptions { - - private GetGroupsTemplateOfficeOptions() {} - - @Schema(example = "1") - public Long id; - @Schema(example = "Head Office") - public String name; - @Schema(example = "Head Office") - public String nameDecorated; - } - - static final class GetGroupsTemplateStaffOptions { - - private GetGroupsTemplateStaffOptions() {} - - @Schema(example = "1") - public Long id; - @Schema(example = "C, Mike") - public String displayName; - } - - static final class GetGroupsTemplateClientOptions { - - private GetGroupsTemplateClientOptions() {} - - @Schema(example = "1") - public Long id; - @Schema(example = "Petra Yton") - public String displayName; - @Schema(example = "1") - public Long officeId; - @Schema(example = "Head Office") - public String officeName; - } - - static final class GetGroupsTemplateDatatables { - - private GetGroupsTemplateDatatables() {} - - static final class GetGroupsTemplateColumnHeaderData { - - private GetGroupsTemplateColumnHeaderData() {} - - static final class GetGroupsTemplateColumnValues { - - private GetGroupsTemplateColumnValues() {} - } - - @Schema(example = "group_id") - public String columnName; - @Schema(example = "bigint") - public String columnType; - @Schema(example = "0") - public Integer columnLength; - @Schema(example = "INTEGER") - public String columnDisplayType; - @Schema(example = "false") - public Boolean isColumnNullable; - @Schema(example = "true") - public Boolean isColumnPrimaryKey; - public Set columnValues; - } - - @Schema(example = "m_group") - public String applicationTableName; - @Schema(example = "Group Activation Data") - public String registeredTableName; - public Set columnHeaderData; - } - - @Schema(example = "1") - public Long officeId; - public Set officeOptions; - public Set staffOptions; - public Set clientOptions; - public Set datatables; - } - - @Schema(description = "GetGroupsResponse") - public static final class GetGroupsResponse { - - private GetGroupsResponse() {} - - static final class GetGroupsPageItems { - - private GetGroupsPageItems() {} - - static final class GetGroupsStatus { - - private GetGroupsStatus() {} - - @Schema(example = "100") - public Long id; - @Schema(example = "clientStatusType.pending") - public String code; - @Schema(example = "Pending") - public String description; - } - - @Schema(example = "4") - public Long id; - @Schema(example = "AnotherGroup") - public String name; - @Schema(example = "000-1A") - public String externalId; - public GetGroupsStatus status; - @Schema(example = "false") - public Boolean active; - @Schema(example = "1") - public Long officeId; - @Schema(example = "Head Office") - public String officeName; - @Schema(example = ".4.") - public String hierarchy; - } - - @Schema(example = "2") - public Integer totalFilteredRecords; - public Set pageItems; - } - - @Schema(description = "GetGroupsGroupIdResponse") - public static final class GetGroupsGroupIdResponse { - - private GetGroupsGroupIdResponse() {} - - static final class GetGroupsGroupIdTimeline { - - private GetGroupsGroupIdTimeline() {} - - @Schema(example = "[2013, 11, 14]") - public LocalDate activatedOnDate; - @Schema(example = "mifos") - public String activatedByUsername; - @Schema(example = "App") - public String activatedByFirstname; - @Schema(example = "Administrator") - public String activatedByLastname; - } - - static final class GetGroupsGroupIdClientMembers { - - private GetGroupsGroupIdClientMembers() {} - - @Schema(example = "1") - public Long id; - @Schema(example = "Sangamesh MB") - public String displayName; - } - - @Schema(example = "1") - public Long id; - @Schema(example = "First Group") - public String name; - @Schema(example = "000-1A") - public String externalId; - @Schema(example = "true") - public Boolean active; - @Schema(example = "1") - public Long staffId; - @Schema(example = "1") - public Long officeId; - @Schema(example = "Head Office") - public String officeName; - @Schema(example = ".1.") - public String hierarchy; - public GetGroupsGroupIdTimeline timeline; - @Schema(description = "Returned when the clientMembers association is requested") - public Set clientMembers; - } - - @Schema(description = "PostGroupsRequest") - public static final class PostGroupsRequest { - - private PostGroupsRequest() {} - - @Schema(example = "1") - public Long officeId; - @Schema(example = "Pending Group") - public String name; - @Schema(example = "false") - public Boolean active; - @Schema(example = "externalId1") - public String externalId; - @Schema(example = "dd MMMM yyyy") - public String dateFormat; - @Schema(example = "en") - public String locale; - @Schema(example = "04 March 2011") - public String activationDate; - @Schema(example = "04 March 2011") - public String submittedOnDate; - } - - @Schema(description = "PostGroupsResponse") - public static final class PostGroupsResponse { - - private PostGroupsResponse() {} - - @Schema(example = "1") - public Long officeId; - @Schema(example = "2") - public Long groupId; - @Schema(example = "2") - public Long resourceId; - } - - @Schema(description = "DeleteGroupsGroupIdResponse") - public static final class DeleteGroupsGroupIdResponse { - - private DeleteGroupsGroupIdResponse() {} - - @Schema(example = "1") - public Long officeId; - @Schema(example = "2") - public Long groupId; - @Schema(example = "2") - public Long resourceId; - } - - @Schema(description = "PostGroupsGroupIdCommandUnassignStaffRequest") - public static final class PostGroupsGroupIdCommandUnassignStaffRequest { - - private PostGroupsGroupIdCommandUnassignStaffRequest() {} - - @Schema(example = "1") - public Long staffId; - } - - @Schema(description = "PostGroupsGroupIdCommandUnassignStaffResponse") - public static final class PostGroupsGroupIdCommandUnassignStaffResponse { - - private PostGroupsGroupIdCommandUnassignStaffResponse() {} - - static final class PostGroupsGroupIdCommandUnassignStaffChanges { - - private PostGroupsGroupIdCommandUnassignStaffChanges() {} - } - - @Schema(example = "1") - public Long officeId; - @Schema(example = "1") - public Long groupId; - @Schema(example = "1") - public Long resourceId; - public PostGroupsGroupIdCommandUnassignStaffChanges changes; - } - - @Schema(description = "PutGroupsGroupIdRequest") - public static final class PutGroupsGroupIdRequest { - - private PutGroupsGroupIdRequest() {} - - @Schema(example = "First Group (changed)") - public String name; - } - - @Schema(description = "PutGroupsGroupIdResponse") - public static final class PutGroupsGroupIdResponse { - - private PutGroupsGroupIdResponse() {} - - static final class PutGroupsGroupIdChanges { - - private PutGroupsGroupIdChanges() {} - - @Schema(example = "First Group (changed)") - public String name; - } - - @Schema(example = "1") - public Long officeId; - @Schema(example = "1") - public Long groupId; - @Schema(example = "1") - public Long resourceId; - public PutGroupsGroupIdChanges changes; - } - - @Schema(description = "GetGroupsGroupIdAccountsResponse") - public static final class GetGroupsGroupIdAccountsResponse { - - private GetGroupsGroupIdAccountsResponse() {} - - static final class GetGroupsGroupIdAccountsLoanAccounts { - - private GetGroupsGroupIdAccountsLoanAccounts() {} - - static final class GetGroupsGroupIdAccountsStatus { - - private GetGroupsGroupIdAccountsStatus() {} - - @Schema(example = "100") - public Long id; - @Schema(example = "loanStatusType.submitted.and.pending.approval") - public String code; - @Schema(example = "Submitted and pending approval") - public String description; - @Schema(example = "true") - public Boolean pendingApproval; - @Schema(example = "false") - public Boolean waitingForDisbursal; - @Schema(example = "false") - public Boolean active; - @Schema(example = "false") - public Boolean closedObligationsMet; - @Schema(example = "false") - public Boolean closedWrittenOff; - @Schema(example = "false") - public Boolean closedRescheduled; - @Schema(example = "false") - public Boolean closed; - @Schema(example = "false") - public Boolean overpaid; - } - - static final class GetGroupsGroupIdAccountsLoanType { - - private GetGroupsGroupIdAccountsLoanType() {} - - @Schema(example = "2") - public Long id; - @Schema(example = "accountType.group") - public String code; - @Schema(example = "Group") - public String description; - } - - @Schema(example = "3") - public Long id; - @Schema(example = "000000003") - public Long accountNo; - @Schema(example = "3") - public Long productId; - @Schema(example = "daily product") - public String productName; - public GetGroupsGroupIdAccountsStatus status; - public GetGroupsGroupIdAccountsLoanType loanType; - } - - static final class GetGroupsGroupIdAccountsSavingAccounts { - - private GetGroupsGroupIdAccountsSavingAccounts() {} - - static final class GetGroupsGroupIdAccountsSavingStatus { - - private GetGroupsGroupIdAccountsSavingStatus() {} - - @Schema(example = "100") - public Long id; - @Schema(example = "savingsAccountStatusType.submitted.and.pending.approval") - public String code; - @Schema(example = "Submitted and pending approval") - public String description; - @Schema(example = "true") - public Boolean submittedAndPendingApproval; - @Schema(example = "false") - public Boolean approved; - @Schema(example = "false") - public Boolean rejected; - @Schema(example = "false") - public Boolean withdrawnByApplicant; - @Schema(example = "false") - public Boolean active; - @Schema(example = "false") - public Boolean closed; - } - - static final class GetGroupsGroupIdAccountsSavingCurrency { - - private GetGroupsGroupIdAccountsSavingCurrency() {} - - @Schema(example = "USD") - public String code; - @Schema(example = "US Dollar") - public String name; - @Schema(example = "2") - public Integer decimalPlaces; - @Schema(example = "$") - public String displaySymbol; - @Schema(example = "currency.USD") - public String nameCode; - @Schema(example = "US Dollar ($)") - public String displayLabel; - } - - static final class GetGroupsGroupIdAccountsSavingAccountType { - - private GetGroupsGroupIdAccountsSavingAccountType() {} - - @Schema(example = "2") - public Long id; - @Schema(example = "accountType.group") - public String code; - @Schema(example = "Group") - public String description; - } - - @Schema(example = "9") - public Long id; - @Schema(example = "000000009") - public Long accountNo; - @Schema(example = "1") - public Long productId; - @Schema(example = "p_sav") - public String productName; - public GetGroupsGroupIdAccountsSavingStatus status; - public GetGroupsGroupIdAccountsSavingCurrency currency; - @Schema(example = "5000.00") - public java.math.BigDecimal accountBalance; - @Schema(example = "300.00") - public java.math.BigDecimal onHoldFunds; - @Schema(example = "200.00") - public java.math.BigDecimal savingsAmountOnHold; - @Schema(example = "4500.00") - public java.math.BigDecimal availableBalance; - public GetGroupsGroupIdAccountsSavingAccountType accountType; - } - - static final class GetGroupsGroupIdAccountsMemberLoanAccounts { - - private GetGroupsGroupIdAccountsMemberLoanAccounts() {} - - static final class GetGroupsGroupIdAccountsMemberLoanStatus { - - private GetGroupsGroupIdAccountsMemberLoanStatus() {} - - @Schema(example = "200") - public Long id; - @Schema(example = "loanStatusType.approved") - public String code; - @Schema(example = "Approved") - public String description; - @Schema(example = "false") - public Boolean pendingApproval; - @Schema(example = "true") - public Boolean waitingForDisbursal; - @Schema(example = "false") - public Boolean active; - @Schema(example = "false") - public Boolean closedObligationsMet; - @Schema(example = "false") - public Boolean closedWrittenOff; - @Schema(example = "false") - public Boolean closedRescheduled; - @Schema(example = "false") - public Boolean closed; - @Schema(example = "false") - public Boolean overpaid; - } - - static final class GetGroupsGroupIdAccountsMemberLoanType { - - private GetGroupsGroupIdAccountsMemberLoanType() {} - - @Schema(example = "3") - public Long id; - @Schema(example = "accountType.jlg") - public String code; - @Schema(example = "JLG") - public String description; - } - - @Schema(example = "4") - public Long id; - @Schema(example = "000000004") - public Long accountNo; - @Schema(example = "1") - public Long productId; - @Schema(example = "testLoan") - public String productName; - public GetGroupsGroupIdAccountsMemberLoanStatus status; - public GetGroupsGroupIdAccountsMemberLoanType loanType; - } - - static final class GetGroupsGroupIdAccountsMemberSavingsAccounts { - - private GetGroupsGroupIdAccountsMemberSavingsAccounts() {} - - @Schema(example = "3") - public Long id; - @Schema(example = "000000003") - public Long accountNo; - @Schema(example = "1") - public Long productId; - @Schema(example = "p_sav") - public String productName; - public GetGroupsGroupIdAccountsSavingAccounts.GetGroupsGroupIdAccountsSavingStatus status; - public GetGroupsGroupIdAccountsSavingAccounts.GetGroupsGroupIdAccountsSavingCurrency currency; - public GetGroupsGroupIdAccountsMemberLoanAccounts.GetGroupsGroupIdAccountsMemberLoanType accountType; - } - - public Set loanAccounts; - public Set savingsAccounts; - public Set memberLoanAccounts; - public Set memberSavingsAccounts; - } - - @Schema(description = "PostGroupsGroupIdRequest") - public static final class PostGroupsGroupIdRequest { - - private PostGroupsGroupIdRequest() {} - - static final class PostGroupsGroupIdClients { - - private PostGroupsGroupIdClients() {} - - @Schema(example = "1") - public Long id; - } - - @Schema(example = "2") - public Long destinationGroupId; - public Set clients; - @Schema(example = "dd MMMM yyyy") - public String dateFormat; - @Schema(example = "en") - public String locale; - @Schema(example = "04 March 2011") - public String activationDate; - @Schema(example = "1") - public Long staffId; - @Schema(example = "false") - public Boolean inheritStaffForClientAccounts; - @Schema(description = "List of client ids to associate with or disassociate from the group") - public List clientMembers; - } - - @Schema(description = "PostGroupsGroupIdResponse") - public static final class PostGroupsGroupIdResponse { - - private PostGroupsGroupIdResponse() {} - - static final class PostGroupsGroupIdChanges { - - private PostGroupsGroupIdChanges() {} - - @Schema(example = "1") - public Long staffId; - @Schema(description = "Ids of the clients associated or disassociated by the command") - public List clientMembers; - } - - @Schema(example = "1") - public Long officeId; - @Schema(example = "1") - public Long groupId; - @Schema(example = "1") - public Long resourceId; - public PostGroupsGroupIdChanges changes; - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterActivateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterActivateCommand.java new file mode 100644 index 00000000000..fc909b3d007 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterActivateCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterActivateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterActivateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterAssociateGroupsCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterAssociateGroupsCommand.java new file mode 100644 index 00000000000..3cafdf4f72b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterAssociateGroupsCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterAssociateGroupsRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterAssociateGroupsCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterCloseCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterCloseCommand.java new file mode 100644 index 00000000000..accabaeecca --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterCloseCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterCloseRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterCloseCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterCreateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterCreateCommand.java new file mode 100644 index 00000000000..baa6174f00b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterCreateCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterCreateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterCreateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterDeleteCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterDeleteCommand.java new file mode 100644 index 00000000000..b848a6af47c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterDeleteCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterDeleteRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterDeleteCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterDisassociateGroupsCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterDisassociateGroupsCommand.java new file mode 100644 index 00000000000..dcec5d787db --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterDisassociateGroupsCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterDisassociateGroupsRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterDisassociateGroupsCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterSaveCollectionSheetCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterSaveCollectionSheetCommand.java new file mode 100644 index 00000000000..f3360d43dee --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterSaveCollectionSheetCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterSaveCollectionSheetRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterSaveCollectionSheetCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterUpdateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterUpdateCommand.java new file mode 100644 index 00000000000..64bfd90b509 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterUpdateCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterUpdateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterUpdateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterUploadCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterUploadCommand.java new file mode 100644 index 00000000000..2181955f808 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/CenterUploadCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.CenterUploadRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CenterUploadCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupActivateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupActivateCommand.java new file mode 100644 index 00000000000..030c763f1ca --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupActivateCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupActivateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssignRoleCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssignRoleCommand.java new file mode 100644 index 00000000000..3334a20fee0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssignRoleCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupAssignRoleRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupAssignRoleCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssignStaffCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssignStaffCommand.java new file mode 100644 index 00000000000..263c2cb1982 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssignStaffCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupAssignStaffRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupAssignStaffCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssociateClientsCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssociateClientsCommand.java new file mode 100644 index 00000000000..09e408b18bb --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupAssociateClientsCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupAssociateClientsRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupAssociateClientsCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupCloseCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupCloseCommand.java new file mode 100644 index 00000000000..c67d7cce45c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupCloseCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupCloseRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupCloseCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupCreateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupCreateCommand.java new file mode 100644 index 00000000000..886ccee8e28 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupCreateCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupCreateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupDeleteCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupDeleteCommand.java new file mode 100644 index 00000000000..b3c2fdd8259 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupDeleteCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupDeleteRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupDeleteCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupDisassociateClientsCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupDisassociateClientsCommand.java new file mode 100644 index 00000000000..42f701c9c66 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupDisassociateClientsCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupDisassociateClientsRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupDisassociateClientsCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupSaveCollectionSheetCommand.java similarity index 66% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWritePlatformService.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupSaveCollectionSheetCommand.java index 21eb88a1da0..d73f8c297a9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupSaveCollectionSheetCommand.java @@ -16,17 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.group.service; +package org.apache.fineract.portfolio.group.command; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupSaveCollectionSheetRequest; -public interface GroupRolesWritePlatformService { - - CommandProcessingResult createRole(JsonCommand command); - - CommandProcessingResult updateRole(JsonCommand command); - - CommandProcessingResult deleteRole(Long ruleId); - -} +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupSaveCollectionSheetCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupTransferClientsCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupTransferClientsCommand.java new file mode 100644 index 00000000000..99c8bc9a1f4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupTransferClientsCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupTransferClientsCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUnassignRoleCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUnassignRoleCommand.java new file mode 100644 index 00000000000..650a3e7f9c4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUnassignRoleCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupUnassignRoleRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupUnassignRoleCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUnassignStaffCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUnassignStaffCommand.java new file mode 100644 index 00000000000..9ba7e373aa5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUnassignStaffCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupUnassignStaffCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUpdateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUpdateCommand.java new file mode 100644 index 00000000000..819ad04e7d3 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUpdateCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupUpdateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupUpdateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUpdateRoleCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUpdateRoleCommand.java new file mode 100644 index 00000000000..4e0098b64fa --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUpdateRoleCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupUpdateRoleRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupUpdateRoleCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUploadCommand.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUploadCommand.java new file mode 100644 index 00000000000..ee7d515007d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/command/GroupUploadCommand.java @@ -0,0 +1,28 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.portfolio.group.data.GroupUploadRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class GroupUploadCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterActivateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterActivateRequest.java new file mode 100644 index 00000000000..0aeefe73101 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterActivateRequest.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterActivateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.activation-date.not-null}") + private String activationDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterAssociateGroupsRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterAssociateGroupsRequest.java new file mode 100644 index 00000000000..96d11ff8987 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterAssociateGroupsRequest.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotEmpty; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterAssociateGroupsRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotEmpty(message = "{org.apache.fineract.portfolio.group.group-members.not-empty}") + private List groupMembers; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCloseRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCloseRequest.java new file mode 100644 index 00000000000..320ed5add23 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCloseRequest.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterCloseRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.closure-date.not-null}") + private String closureDate; + @NotNull(message = "{org.apache.fineract.portfolio.group.closure-reason-id.not-null}") + private Long closureReasonId; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCommandRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCommandRequest.java new file mode 100644 index 00000000000..07c53cebd4f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCommandRequest.java @@ -0,0 +1,61 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterCommandRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private String activationDate; + private String closureDate; + private Long closureReasonId; + private List groupMembers; + private Long calendarId; + private String transactionDate; + private String actualDisbursementDate; + private String note; + private List clientsAttendance; + private List bulkRepaymentTransactions; + private List bulkDisbursementTransactions; + private List bulkSavingsDueTransactions; + private Integer paymentTypeId; + private String accountNumber; + private String checkNumber; + private String routingCode; + private String receiptNumber; + private String bankNumber; + @JsonProperty("isTransactionDateOnNonMeetingDate") + private Boolean isTransactionDateOnNonMeetingDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCommandResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCommandResponse.java new file mode 100644 index 00000000000..69ce3588532 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCommandResponse.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterCommandResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; + private Map changes; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCreateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCreateRequest.java new file mode 100644 index 00000000000..d505c79f6fc --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCreateRequest.java @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fineract.portfolio.group.validation.ActivationDateRequiredWhenActive; +import org.apache.fineract.portfolio.group.validation.HasActivation; +import org.hibernate.validator.constraints.Length; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@ActivationDateRequiredWhenActive +public class CenterCreateRequest implements Serializable, HasActivation { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "{org.apache.fineract.portfolio.group.name.not-null}") + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.name.max}") + private String name; + @NotNull(message = "{org.apache.fineract.portfolio.group.office-id.not-null}") + @Positive(message = "{org.apache.fineract.portfolio.group.office-id.positive}") + private Long officeId; + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.external-id.max}") + private String externalId; + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; + private Boolean active; + private String activationDate; + private String submittedOnDate; + private List groupMembers; + @Size(min = 1, message = "{org.apache.fineract.portfolio.group.datatables.not-empty}") + private List> datatables; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCreateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCreateResponse.java new file mode 100644 index 00000000000..3037cb43778 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterCreateResponse.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterCreateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDeleteRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDeleteRequest.java new file mode 100644 index 00000000000..acc4c63dbc5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDeleteRequest.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterDeleteRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDeleteResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDeleteResponse.java new file mode 100644 index 00000000000..27174f1e766 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDeleteResponse.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterDeleteResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDisassociateGroupsRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDisassociateGroupsRequest.java new file mode 100644 index 00000000000..cd941974850 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterDisassociateGroupsRequest.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotEmpty; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterDisassociateGroupsRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotEmpty(message = "{org.apache.fineract.portfolio.group.group-members.not-empty}") + private List groupMembers; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterSaveCollectionSheetRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterSaveCollectionSheetRequest.java new file mode 100644 index 00000000000..641e8a480c3 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterSaveCollectionSheetRequest.java @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterSaveCollectionSheetRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.calendar-id.not-null}") + private Long calendarId; + @NotNull(message = "{org.apache.fineract.portfolio.group.transaction-date.not-null}") + private String transactionDate; + private String actualDisbursementDate; + @Length(max = 1000, message = "{org.apache.fineract.portfolio.group.note.max}") + private String note; + private List clientsAttendance; + private List bulkRepaymentTransactions; + private List bulkDisbursementTransactions; + private List bulkSavingsDueTransactions; + private Integer paymentTypeId; + private String accountNumber; + private String checkNumber; + private String routingCode; + private String receiptNumber; + private String bankNumber; + @JsonProperty("isTransactionDateOnNonMeetingDate") + private Boolean isTransactionDateOnNonMeetingDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUpdateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUpdateRequest.java new file mode 100644 index 00000000000..482f149cb12 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUpdateRequest.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterUpdateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; // set from the path by the resource, never from the body + @NotNull(message = "{org.apache.fineract.portfolio.group.name.not-null}") + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.name.max}") + private String name; + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.external-id.max}") + private String externalId; + @Positive(message = "{org.apache.fineract.portfolio.group.office-id.positive}") + private Long officeId; + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; + private String activationDate; + private String submittedOnDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUpdateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUpdateResponse.java new file mode 100644 index 00000000000..80d31d00cfa --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUpdateResponse.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterUpdateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; + private Map changes; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUploadRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUploadRequest.java new file mode 100644 index 00000000000..51eb3d9a25e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUploadRequest.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.InputStream; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterUploadRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private transient InputStream uploadedInputStream; + private transient FormDataContentDisposition fileDetail; + private String locale; + private String dateFormat; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUploadResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUploadResponse.java new file mode 100644 index 00000000000..e8b1a363ef0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CenterUploadResponse.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CenterUploadResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CentersPageResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CentersPageResponse.java new file mode 100644 index 00000000000..472dd79c5d0 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CentersPageResponse.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.util.List; +import org.apache.fineract.infrastructure.core.service.Page; + +public class CentersPageResponse extends Page { + + public CentersPageResponse(final List pageItems, final int totalFilteredRecords) { + super(pageItems, totalFilteredRecords); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetAttendanceItem.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetAttendanceItem.java new file mode 100644 index 00000000000..b9182a08235 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetAttendanceItem.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CollectionSheetAttendanceItem implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long clientId; + private Long attendanceType; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetLoanTransactionItem.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetLoanTransactionItem.java new file mode 100644 index 00000000000..ac9b92b5f84 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetLoanTransactionItem.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CollectionSheetLoanTransactionItem implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long loanId; + private BigDecimal transactionAmount; + private String externalId; + private Long paymentTypeId; + private String accountNumber; + private String checkNumber; + private String routingCode; + private String receiptNumber; + private String bankNumber; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetSavingsTransactionItem.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetSavingsTransactionItem.java new file mode 100644 index 00000000000..b58347bb12f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/CollectionSheetSavingsTransactionItem.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class CollectionSheetSavingsTransactionItem implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long savingsId; + private BigDecimal transactionAmount; + private Integer paymentTypeId; + private Integer depositAccountType; + private String accountNumber; + private String checkNumber; + private String routingCode; + private String receiptNumber; + private String bankNumber; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupActivateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupActivateRequest.java new file mode 100644 index 00000000000..b36831d7368 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupActivateRequest.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupActivateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.activation-date.not-null}") + private String activationDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssignRoleRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssignRoleRequest.java new file mode 100644 index 00000000000..85240f4786c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssignRoleRequest.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupAssignRoleRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long groupId; + @NotNull(message = "{org.apache.fineract.portfolio.group.client-id.not-null}") + @Positive(message = "{org.apache.fineract.portfolio.group.client-id.not-null}") + private Long clientId; + @NotNull(message = "{org.apache.fineract.portfolio.group.role.not-null}") + @Positive(message = "{org.apache.fineract.portfolio.group.role.not-null}") + private Long role; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssignStaffRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssignStaffRequest.java new file mode 100644 index 00000000000..ab7a86831ac --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssignStaffRequest.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupAssignStaffRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; + private Boolean inheritStaffForClientAccounts; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssociateClientsRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssociateClientsRequest.java new file mode 100644 index 00000000000..07501b3e328 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupAssociateClientsRequest.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotEmpty; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupAssociateClientsRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotEmpty(message = "{org.apache.fineract.portfolio.group.client-members.not-empty}") + private List clientMembers; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCloseRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCloseRequest.java new file mode 100644 index 00000000000..3639112a379 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCloseRequest.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupCloseRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.closure-date.not-null}") + private String closureDate; + @NotNull(message = "{org.apache.fineract.portfolio.group.closure-reason-id.not-null}") + private Long closureReasonId; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCommandRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCommandRequest.java new file mode 100644 index 00000000000..61f7a970c2e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCommandRequest.java @@ -0,0 +1,69 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupCommandRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private String activationDate; + private String closureDate; + private Long closureReasonId; + private List clientMembers; + private Long staffId; + private Boolean inheritStaffForClientAccounts; + private Long clientId; + private Long role; + private Long destinationGroupId; + private List clients; + private Boolean inheritDestinationGroupLoanOfficer; + private Boolean transferActiveLoans; + private Long calendarId; + private String transactionDate; + private String actualDisbursementDate; + private String note; + private List clientsAttendance; + private List bulkRepaymentTransactions; + private List bulkDisbursementTransactions; + private List bulkSavingsDueTransactions; + private Integer paymentTypeId; + private String accountNumber; + private String checkNumber; + private String routingCode; + private String receiptNumber; + private String bankNumber; + @JsonProperty("isTransactionDateOnNonMeetingDate") + private Boolean isTransactionDateOnNonMeetingDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCommandResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCommandResponse.java new file mode 100644 index 00000000000..2aa5e536fae --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCommandResponse.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupCommandResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long clientId; + private Long resourceId; + private Map changes; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCreateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCreateRequest.java new file mode 100644 index 00000000000..7dcc4397c0e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCreateRequest.java @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.fineract.portfolio.group.validation.ActivationDateRequiredWhenActive; +import org.apache.fineract.portfolio.group.validation.HasActivation; +import org.apache.fineract.portfolio.group.validation.OfficeIdRequiredUnlessCenter; +import org.hibernate.validator.constraints.Length; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@ActivationDateRequiredWhenActive +@OfficeIdRequiredUnlessCenter +public class GroupCreateRequest implements Serializable, HasActivation { + + @Serial + private static final long serialVersionUID = 1L; + + @NotNull(message = "{org.apache.fineract.portfolio.group.name.not-null}") + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.name.max}") + private String name; + @Positive(message = "{org.apache.fineract.portfolio.group.office-id.positive}") + private Long officeId; + @Positive(message = "{org.apache.fineract.portfolio.group.center-id.positive}") + private Long centerId; + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.external-id.max}") + private String externalId; + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; + private Boolean active; + private String activationDate; + private String submittedOnDate; + private List clientMembers; + @Size(min = 1, message = "{org.apache.fineract.portfolio.group.datatables.not-empty}") + private List> datatables; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCreateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCreateResponse.java new file mode 100644 index 00000000000..a9e06986e27 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupCreateResponse.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupCreateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDeleteRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDeleteRequest.java new file mode 100644 index 00000000000..20d8601980e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDeleteRequest.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupDeleteRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDeleteResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDeleteResponse.java new file mode 100644 index 00000000000..ecfc7bca72f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDeleteResponse.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupDeleteResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDisassociateClientsRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDisassociateClientsRequest.java new file mode 100644 index 00000000000..59b5274836c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupDisassociateClientsRequest.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotEmpty; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupDisassociateClientsRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotEmpty(message = "{org.apache.fineract.portfolio.group.client-members.not-empty}") + private List clientMembers; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupSaveCollectionSheetRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupSaveCollectionSheetRequest.java new file mode 100644 index 00000000000..36b14f286b1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupSaveCollectionSheetRequest.java @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupSaveCollectionSheetRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.calendar-id.not-null}") + private Long calendarId; + @NotNull(message = "{org.apache.fineract.portfolio.group.transaction-date.not-null}") + private String transactionDate; + private String actualDisbursementDate; + @Length(max = 1000, message = "{org.apache.fineract.portfolio.group.note.max}") + private String note; + private List clientsAttendance; + private List bulkRepaymentTransactions; + private List bulkDisbursementTransactions; + private List bulkSavingsDueTransactions; + private Integer paymentTypeId; + private String accountNumber; + private String checkNumber; + private String routingCode; + private String receiptNumber; + private String bankNumber; + @JsonProperty("isTransactionDateOnNonMeetingDate") + private Boolean isTransactionDateOnNonMeetingDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupTransferClientItem.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupTransferClientItem.java new file mode 100644 index 00000000000..dc5c1bcd67e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupTransferClientItem.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupTransferClientItem implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupTransferClientsRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupTransferClientsRequest.java new file mode 100644 index 00000000000..3fcff59c82e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupTransferClientsRequest.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupTransferClientsRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; // source group, from the path + @NotNull(message = "{org.apache.fineract.portfolio.group.destination-group-id.not-null}") + @Positive(message = "{org.apache.fineract.portfolio.group.destination-group-id.positive}") + private Long destinationGroupId; + @NotEmpty(message = "{org.apache.fineract.portfolio.group.clients.not-empty}") + @Valid + private List clients; + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; + private Boolean inheritDestinationGroupLoanOfficer; + private Boolean transferActiveLoans; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUnassignRoleRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUnassignRoleRequest.java new file mode 100644 index 00000000000..25505cb1d2c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUnassignRoleRequest.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUnassignRoleRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long groupId; + private Long roleId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUnassignStaffRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUnassignStaffRequest.java new file mode 100644 index 00000000000..8bfa9231f8c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUnassignStaffRequest.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUnassignStaffRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; + @NotNull(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateRequest.java new file mode 100644 index 00000000000..e1039d3a862 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateRequest.java @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.hibernate.validator.constraints.Length; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUpdateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; // set from the path by the resource, never from the body + @NotNull(message = "{org.apache.fineract.portfolio.group.name.not-null}") + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.name.max}") + private String name; + @Length(max = 100, message = "{org.apache.fineract.portfolio.group.external-id.max}") + private String externalId; + @Positive(message = "{org.apache.fineract.portfolio.group.office-id.positive}") + private Long officeId; + @Positive(message = "{org.apache.fineract.portfolio.group.staff-id.positive}") + private Long staffId; + @Positive(message = "{org.apache.fineract.portfolio.group.center-id.positive}") + private Long centerId; + private String activationDate; + private String submittedOnDate; + private String dateFormat; + private String locale; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateResponse.java new file mode 100644 index 00000000000..7882a389437 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateResponse.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUpdateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long officeId; + private Long groupId; + private Long resourceId; + private Map changes; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateRoleRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateRoleRequest.java new file mode 100644 index 00000000000..4872b45c9c5 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUpdateRoleRequest.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import jakarta.validation.constraints.Positive; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUpdateRoleRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long groupId; + private Long roleId; + @Positive(message = "{org.apache.fineract.portfolio.group.role.not-null}") + private Long role; + @Positive(message = "{org.apache.fineract.portfolio.group.client-id.not-null}") + private Long clientId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUploadRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUploadRequest.java new file mode 100644 index 00000000000..2bae70579c8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUploadRequest.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.InputStream; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.glassfish.jersey.media.multipart.FormDataContentDisposition; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUploadRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private transient InputStream uploadedInputStream; + private transient FormDataContentDisposition fileDetail; + private String locale; + private String dateFormat; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUploadResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUploadResponse.java new file mode 100644 index 00000000000..634eb52aab2 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupUploadResponse.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GroupUploadResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupsPageResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupsPageResponse.java new file mode 100644 index 00000000000..9d2348177cd --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/data/GroupsPageResponse.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import java.util.List; +import org.apache.fineract.infrastructure.core.service.Page; + +public class GroupsPageResponse extends Page { + + public GroupsPageResponse(final List pageItems, final int totalFilteredRecords) { + super(pageItems, totalFilteredRecords); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssignGroupStaffCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssignGroupStaffCommandHandler.java deleted file mode 100644 index d98aa218412..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssignGroupStaffCommandHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "ASSIGNSTAFF") -@RequiredArgsConstructor -public class AssignGroupStaffCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupWritePlatformService.assignGroupOrCenterStaff(command.entityId(), command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterActivateCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterActivateCommandHandler.java new file mode 100644 index 00000000000..1e65dc8940e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterActivateCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterActivateRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterActivateCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterActivate", fallbackMethod = "fallback") + @Override + @Transactional + public CenterCommandResponse handle(Command command) { + return writeService.activateCenter(command.getPayload()); + } + + @Override + public CenterCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterAssociateGroupsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterAssociateGroupsCommandHandler.java new file mode 100644 index 00000000000..476a2d2cb72 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterAssociateGroupsCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterAssociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterAssociateGroupsCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterAssociateGroups", fallbackMethod = "fallback") + @Override + @Transactional + public CenterCommandResponse handle(Command command) { + return writeService.associateGroups(command.getPayload()); + } + + @Override + public CenterCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterCloseCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterCloseCommandHandler.java new file mode 100644 index 00000000000..d9c7c18ee89 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterCloseCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterCloseRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterCloseCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterClose", fallbackMethod = "fallback") + @Override + @Transactional + public CenterCommandResponse handle(Command command) { + return writeService.closeCenter(command.getPayload()); + } + + @Override + public CenterCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterCreateCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterCreateCommandHandler.java new file mode 100644 index 00000000000..3aeafe3e278 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterCreateCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterCreateRequest; +import org.apache.fineract.portfolio.group.data.CenterCreateResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterCreateCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterCreate", fallbackMethod = "fallback") + @Override + @Transactional + public CenterCreateResponse handle(Command command) { + return writeService.createCenter(command.getPayload()); + } + + @Override + public CenterCreateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterDeleteCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterDeleteCommandHandler.java new file mode 100644 index 00000000000..2b38b799e9f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterDeleteCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterDeleteRequest; +import org.apache.fineract.portfolio.group.data.CenterDeleteResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterDeleteCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterDelete", fallbackMethod = "fallback") + @Override + @Transactional + public CenterDeleteResponse handle(Command command) { + return writeService.deleteCenter(command.getPayload()); + } + + @Override + public CenterDeleteResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterDisassociateGroupsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterDisassociateGroupsCommandHandler.java new file mode 100644 index 00000000000..9c9c70fcfd7 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterDisassociateGroupsCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterDisassociateGroupsRequest; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterDisassociateGroupsCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterDisassociateGroups", fallbackMethod = "fallback") + @Override + @Transactional + public CenterCommandResponse handle(Command command) { + return writeService.disassociateGroups(command.getPayload()); + } + + @Override + public CenterCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/SaveGroupCollectionSheetCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterSaveCollectionSheetCommandHandler.java similarity index 52% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/SaveGroupCollectionSheetCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterSaveCollectionSheetCommandHandler.java index 18957faae1e..645ade158b2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/SaveGroupCollectionSheetCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterSaveCollectionSheetCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; import org.apache.fineract.portfolio.collectionsheet.service.CollectionSheetWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterSaveCollectionSheetRequest; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "SAVECOLLECTIONSHEET") +@Component @RequiredArgsConstructor -public class SaveGroupCollectionSheetCommandHandler implements NewCommandSourceHandler { +public class CenterSaveCollectionSheetCommandHandler implements CommandHandler { - private final CollectionSheetWritePlatformService writePlatformService; + private final CollectionSheetWritePlatformService writeService; - @Transactional + @Retry(name = "commandCenterSaveCollectionSheet", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { + @Transactional + public CenterCommandResponse handle(Command command) { + return writeService.saveCenterCollectionSheet(command.getPayload()); + } - return this.writePlatformService.updateCollectionSheet(command); + @Override + public CenterCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterUpdateCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterUpdateCommandHandler.java new file mode 100644 index 00000000000..f82d5ae6422 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterUpdateCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.CenterUpdateRequest; +import org.apache.fineract.portfolio.group.data.CenterUpdateResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class CenterUpdateCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandCenterUpdate", fallbackMethod = "fallback") + @Override + @Transactional + public CenterUpdateResponse handle(Command command) { + return writeService.updateCenter(command.getPayload()); + } + + @Override + public CenterUpdateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterUploadCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterUploadCommandHandler.java new file mode 100644 index 00000000000..7644203d5eb --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CenterUploadCommandHandler.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType; +import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookService; +import org.apache.fineract.portfolio.group.data.CenterUploadRequest; +import org.apache.fineract.portfolio.group.data.CenterUploadResponse; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CenterUploadCommandHandler implements CommandHandler { + + private final BulkImportWorkbookService bulkImportWorkbookService; + + @Retry(name = "commandCenterUpload", fallbackMethod = "fallback") + @Override + public CenterUploadResponse handle(Command command) { + final var payload = command.getPayload(); + final Long id = bulkImportWorkbookService.importWorkbook(GlobalEntityType.CENTERS.toString(), payload.getUploadedInputStream(), + payload.getFileDetail(), payload.getLocale(), payload.getDateFormat()); + return CenterUploadResponse.builder().resourceId(id).build(); + } + + @Override + public CenterUploadResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CloseCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CloseCenterCommandHandler.java deleted file mode 100644 index 7a83b280faa..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CloseCenterCommandHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "CENTER", action = "CLOSE") -@RequiredArgsConstructor -public class CloseCenterCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupingTypesWritePlatformService; - - @Override - @Transactional - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupingTypesWritePlatformService.closeCenter(command.entityId(), command); - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CloseGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CloseGroupCommandHandler.java deleted file mode 100644 index ad5885e56d8..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CloseGroupCommandHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "CLOSE") -@RequiredArgsConstructor -public class CloseGroupCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupingTypesWritePlatformService; - - @Override - @Transactional - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupingTypesWritePlatformService.closeGroup(command.entityId(), command); - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CreateCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CreateCenterCommandHandler.java deleted file mode 100644 index 35de614ac52..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CreateCenterCommandHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "CENTER", action = "CREATE") -@RequiredArgsConstructor -public class CreateCenterCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupWritePlatformService.createCenter(command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CreateGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CreateGroupCommandHandler.java deleted file mode 100644 index 62a8e5fb144..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/CreateGroupCommandHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "CREATE") -@RequiredArgsConstructor -public class CreateGroupCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - - final Long centerId = command.longValueOfParameterNamed("centerId"); - return this.groupWritePlatformService.createGroup(centerId, command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DeleteCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DeleteCenterCommandHandler.java deleted file mode 100644 index e6915363456..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DeleteCenterCommandHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "CENTER", action = "DELETE") -@RequiredArgsConstructor -public class DeleteCenterCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupWritePlatformService.deleteGroup(command.entityId()); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DeleteGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DeleteGroupCommandHandler.java deleted file mode 100644 index 4a30787a43f..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DeleteGroupCommandHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "DELETE") -@RequiredArgsConstructor -public class DeleteGroupCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupWritePlatformService.deleteGroup(command.entityId()); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DisassociateClientsFromGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DisassociateClientsFromGroupCommandHandler.java deleted file mode 100644 index 6a45d4b6666..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DisassociateClientsFromGroupCommandHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "DISASSOCIATECLIENTS") -@RequiredArgsConstructor -public class DisassociateClientsFromGroupCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService writePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.writePlatformService.disassociateClientsFromGroup(command.entityId(), command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DisassociateGroupsFromCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DisassociateGroupsFromCenterCommandHandler.java deleted file mode 100644 index fe57e51a3f1..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/DisassociateGroupsFromCenterCommandHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "CENTER", action = "DISASSOCIATEGROUPS") -@RequiredArgsConstructor -public class DisassociateGroupsFromCenterCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService writePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return this.writePlatformService.disassociateGroupsToCenter(command.entityId(), command); - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupActivateCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupActivateCommandHandler.java new file mode 100644 index 00000000000..f94c89585a1 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupActivateCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class GroupActivateCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandGroupActivate", fallbackMethod = "fallback") + @Override + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.activateGroup(command.getPayload()); + } + + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignRoleCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssignRoleCommandHandler.java similarity index 53% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignRoleCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssignRoleCommandHandler.java index a87cc5a9ba0..afc584151e2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignRoleCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssignRoleCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupRolesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupAssignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupRolesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "UNASSIGNROLE") +@Component @RequiredArgsConstructor -public class UnassignRoleCommandHandler implements NewCommandSourceHandler { +public class GroupAssignRoleCommandHandler implements CommandHandler { - private final GroupRolesWritePlatformService groupRolesWritePlatformService; + private final GroupRolesWriteService writeService; + @Retry(name = "commandGroupAssignRole", fallbackMethod = "fallback") @Override @Transactional - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupRolesWritePlatformService.deleteRole(command.entityId()); + public GroupCommandResponse handle(Command command) { + return writeService.assignRole(command.getPayload()); } + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssignStaffCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssignStaffCommandHandler.java new file mode 100644 index 00000000000..0ad29d56944 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssignStaffCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupAssignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class GroupAssignStaffCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandGroupAssignStaff", fallbackMethod = "fallback") + @Override + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.assignStaff(command.getPayload()); + } + + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssociateClientsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssociateClientsCommandHandler.java new file mode 100644 index 00000000000..33da360dcbe --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupAssociateClientsCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupAssociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class GroupAssociateClientsCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandGroupAssociateClients", fallbackMethod = "fallback") + @Override + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.associateClients(command.getPayload()); + } + + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssociateGroupsToCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupCloseCommandHandler.java similarity index 54% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssociateGroupsToCenterCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupCloseCommandHandler.java index 6bbcd508643..b18757c2c5e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssociateGroupsToCenterCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupCloseCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCloseRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "CENTER", action = "ASSOCIATEGROUPS") +@Component @RequiredArgsConstructor -public class AssociateGroupsToCenterCommandHandler implements NewCommandSourceHandler { +public class GroupCloseCommandHandler implements CommandHandler { - private final GroupingTypesWritePlatformService writePlatformService; + private final GroupingTypesWriteService writeService; - @Transactional + @Retry(name = "commandGroupClose", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(JsonCommand command) { - return this.writePlatformService.associateGroupsToCenter(command.entityId(), command); + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.closeGroup(command.getPayload()); } + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssociateClientsToGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupCreateCommandHandler.java similarity index 54% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssociateClientsToGroupCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupCreateCommandHandler.java index f1429b2d9bf..94cbeb9e28c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssociateClientsToGroupCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupCreateCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "ASSOCIATECLIENTS") +@Component @RequiredArgsConstructor -public class AssociateClientsToGroupCommandHandler implements NewCommandSourceHandler { +public class GroupCreateCommandHandler implements CommandHandler { - private final GroupingTypesWritePlatformService writePlatformService; + private final GroupingTypesWriteService writeService; - @Transactional + @Retry(name = "commandGroupCreate", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { + @Transactional + public GroupCreateResponse handle(Command command) { + return writeService.createGroup(command.getPayload()); + } - return this.writePlatformService.associateClientsToGroup(command.entityId(), command); + @Override + public GroupCreateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/ActivateCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupDeleteCommandHandler.java similarity index 54% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/ActivateCenterCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupDeleteCommandHandler.java index 21681a9abbe..ff0b825d3c1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/ActivateCenterCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupDeleteCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupDeleteRequest; +import org.apache.fineract.portfolio.group.data.GroupDeleteResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "CENTER", action = "ACTIVATE") +@Component @RequiredArgsConstructor -public class ActivateCenterCommandHandler implements NewCommandSourceHandler { +public class GroupDeleteCommandHandler implements CommandHandler { - private final GroupingTypesWritePlatformService writePlatformService; + private final GroupingTypesWriteService writeService; - @Transactional + @Retry(name = "commandGroupDelete", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { + @Transactional + public GroupDeleteResponse handle(Command command) { + return writeService.deleteGroup(command.getPayload()); + } - return this.writePlatformService.activateGroupOrCenter(command.entityId(), command); + @Override + public GroupDeleteResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupDisassociateClientsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupDisassociateClientsCommandHandler.java new file mode 100644 index 00000000000..194b27d4532 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupDisassociateClientsCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupDisassociateClientsRequest; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class GroupDisassociateClientsCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandGroupDisassociateClients", fallbackMethod = "fallback") + @Override + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.disassociateClients(command.getPayload()); + } + + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/SaveCenterCollectionSheetCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupSaveCollectionSheetCommandHandler.java similarity index 53% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/SaveCenterCollectionSheetCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupSaveCollectionSheetCommandHandler.java index a68f947ef61..ac491592047 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/SaveCenterCollectionSheetCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupSaveCollectionSheetCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; import org.apache.fineract.portfolio.collectionsheet.service.CollectionSheetWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupSaveCollectionSheetRequest; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "CENTER", action = "SAVECOLLECTIONSHEET") +@Component @RequiredArgsConstructor -public class SaveCenterCollectionSheetCommandHandler implements NewCommandSourceHandler { +public class GroupSaveCollectionSheetCommandHandler implements CommandHandler { - private final CollectionSheetWritePlatformService writePlatformService; + private final CollectionSheetWritePlatformService writeService; - @Transactional + @Retry(name = "commandGroupSaveCollectionSheet", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.saveGroupCollectionSheet(command.getPayload()); + } - return this.writePlatformService.updateCollectionSheet(command); + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/handler/TransferClientsBetweenGroupsCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupTransferClientsCommandHandler.java similarity index 50% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/handler/TransferClientsBetweenGroupsCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupTransferClientsCommandHandler.java index 8dc63cab65e..656a9bc03b4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/handler/TransferClientsBetweenGroupsCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupTransferClientsCommandHandler.java @@ -16,28 +16,33 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.portfolio.transfer.handler; +package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; import org.apache.fineract.portfolio.transfer.service.TransferWritePlatformService; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "TRANSFERCLIENTS") +@Component @RequiredArgsConstructor -public class TransferClientsBetweenGroupsCommandHandler implements NewCommandSourceHandler { +public class GroupTransferClientsCommandHandler implements CommandHandler { - private final TransferWritePlatformService writePlatformService; + private final TransferWritePlatformService writeService; - @Transactional + @Retry(name = "commandGroupTransferClients", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.transferClientsBetweenGroups(command.getPayload()); + } - return this.writePlatformService.transferClientsBetweenGroups(command.entityId(), command); + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateGroupRoleCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUnassignRoleCommandHandler.java similarity index 53% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateGroupRoleCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUnassignRoleCommandHandler.java index 18f28749609..6c149dd6bc1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateGroupRoleCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUnassignRoleCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupRolesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupUnassignRoleRequest; +import org.apache.fineract.portfolio.group.service.GroupRolesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "UPDATEROLE") +@Component @RequiredArgsConstructor -public class UpdateGroupRoleCommandHandler implements NewCommandSourceHandler { +public class GroupUnassignRoleCommandHandler implements CommandHandler { - private final GroupRolesWritePlatformService groupRolesWritePlatformService; + private final GroupRolesWriteService writeService; + @Retry(name = "commandGroupUnassignRole", fallbackMethod = "fallback") @Override @Transactional - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupRolesWritePlatformService.updateRole(command); + public GroupCommandResponse handle(Command command) { + return writeService.unassignRole(command.getPayload()); } + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUnassignStaffCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUnassignStaffCommandHandler.java new file mode 100644 index 00000000000..d5775c71c66 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUnassignStaffCommandHandler.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class GroupUnassignStaffCommandHandler implements CommandHandler { + + private final GroupingTypesWriteService writeService; + + @Retry(name = "commandGroupUnassignStaff", fallbackMethod = "fallback") + @Override + @Transactional + public GroupCommandResponse handle(Command command) { + return writeService.unassignStaff(command.getPayload()); + } + + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/ActivateGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUpdateCommandHandler.java similarity index 54% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/ActivateGroupCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUpdateCommandHandler.java index 20f2aa0d650..b0ef698049e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/ActivateGroupCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUpdateCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupUpdateRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "ACTIVATE") +@Component @RequiredArgsConstructor -public class ActivateGroupCommandHandler implements NewCommandSourceHandler { +public class GroupUpdateCommandHandler implements CommandHandler { - private final GroupingTypesWritePlatformService writePlatformService; + private final GroupingTypesWriteService writeService; - @Transactional + @Retry(name = "commandGroupUpdate", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { + @Transactional + public GroupUpdateResponse handle(Command command) { + return writeService.updateGroup(command.getPayload()); + } - return this.writePlatformService.activateGroupOrCenter(command.entityId(), command); + @Override + public GroupUpdateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssignRoleCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUpdateRoleCommandHandler.java similarity index 53% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssignRoleCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUpdateRoleCommandHandler.java index 4e03454b710..adba3f408f4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/AssignRoleCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUpdateRoleCommandHandler.java @@ -18,26 +18,31 @@ */ package org.apache.fineract.portfolio.group.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupRolesWritePlatformService; -import org.springframework.stereotype.Service; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupUpdateRoleRequest; +import org.apache.fineract.portfolio.group.service.GroupRolesWriteService; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "GROUP", action = "ASSIGNROLE") +@Component @RequiredArgsConstructor -public class AssignRoleCommandHandler implements NewCommandSourceHandler { +public class GroupUpdateRoleCommandHandler implements CommandHandler { - private final GroupRolesWritePlatformService groupRolesWritePlatformService; + private final GroupRolesWriteService writeService; + @Retry(name = "commandGroupUpdateRole", fallbackMethod = "fallback") @Override @Transactional - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupRolesWritePlatformService.createRole(command); + public GroupCommandResponse handle(Command command) { + return writeService.updateRole(command.getPayload()); } + @Override + public GroupCommandResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUploadCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUploadCommandHandler.java new file mode 100644 index 00000000000..bcc60849e3f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/GroupUploadCommandHandler.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import io.github.resilience4j.retry.annotation.Retry; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.infrastructure.bulkimport.data.GlobalEntityType; +import org.apache.fineract.infrastructure.bulkimport.service.BulkImportWorkbookService; +import org.apache.fineract.portfolio.group.data.GroupUploadRequest; +import org.apache.fineract.portfolio.group.data.GroupUploadResponse; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class GroupUploadCommandHandler implements CommandHandler { + + private final BulkImportWorkbookService bulkImportWorkbookService; + + @Retry(name = "commandGroupUpload", fallbackMethod = "fallback") + @Override + public GroupUploadResponse handle(Command command) { + final var payload = command.getPayload(); + final Long id = bulkImportWorkbookService.importWorkbook(GlobalEntityType.GROUPS.toString(), payload.getUploadedInputStream(), + payload.getFileDetail(), payload.getLocale(), payload.getDateFormat()); + return GroupUploadResponse.builder().resourceId(id).build(); + } + + @Override + public GroupUploadResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignGroupStaffCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignGroupStaffCommandHandler.java deleted file mode 100644 index dd069d7085b..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignGroupStaffCommandHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "UNASSIGNSTAFF") -@RequiredArgsConstructor -public class UnassignGroupStaffCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.groupWritePlatformService.unassignGroupOrCenterStaff(command.entityId(), command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignStaffFromCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignStaffFromCenterCommandHandler.java deleted file mode 100644 index e5d42255dee..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UnassignStaffFromCenterCommandHandler.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -public class UnassignStaffFromCenterCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService writePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.writePlatformService.unassignGroupOrCenterStaff(command.entityId(), command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateCenterCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateCenterCommandHandler.java deleted file mode 100644 index 26ee4d63e7b..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateCenterCommandHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "CENTER", action = "UPDATE") -@RequiredArgsConstructor -public class UpdateCenterCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - - return this.groupWritePlatformService.updateCenter(command.entityId(), command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateGroupCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateGroupCommandHandler.java deleted file mode 100644 index ac2b1b9f8ec..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/handler/UpdateGroupCommandHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.handler; - -import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.annotation.CommandType; -import org.apache.fineract.commands.handler.NewCommandSourceHandler; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@CommandType(entity = "GROUP", action = "UPDATE") -@RequiredArgsConstructor -public class UpdateGroupCommandHandler implements NewCommandSourceHandler { - - private final GroupingTypesWritePlatformService groupWritePlatformService; - - @Transactional - @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - - return this.groupWritePlatformService.updateGroup(command.entityId(), command); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/CenterCommandRequestMapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/CenterCommandRequestMapper.java new file mode 100644 index 00000000000..33dab94a9fe --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/CenterCommandRequestMapper.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.mapping; + +import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig; +import org.apache.fineract.portfolio.group.data.CenterActivateRequest; +import org.apache.fineract.portfolio.group.data.CenterAssociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterCloseRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandRequest; +import org.apache.fineract.portfolio.group.data.CenterDisassociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterSaveCollectionSheetRequest; +import org.mapstruct.Mapper; + +@Mapper(config = MapstructMapperConfig.class) +public interface CenterCommandRequestMapper { + + CenterActivateRequest toActivate(CenterCommandRequest source, Long id); + + CenterCloseRequest toClose(CenterCommandRequest source, Long id); + + CenterAssociateGroupsRequest toAssociateGroups(CenterCommandRequest source, Long id); + + CenterDisassociateGroupsRequest toDisassociateGroups(CenterCommandRequest source, Long id); + + CenterSaveCollectionSheetRequest toSaveCollectionSheet(CenterCommandRequest source, Long id); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/GroupCommandRequestMapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/GroupCommandRequestMapper.java new file mode 100644 index 00000000000..883c69c976d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/GroupCommandRequestMapper.java @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.mapping; + +import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupAssignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupAssignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupAssociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupCloseRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandRequest; +import org.apache.fineract.portfolio.group.data.GroupDisassociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupSaveCollectionSheetRequest; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupUnassignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRoleRequest; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapstructMapperConfig.class) +public interface GroupCommandRequestMapper { + + GroupActivateRequest toActivate(GroupCommandRequest source, Long id); + + GroupCloseRequest toClose(GroupCommandRequest source, Long id); + + GroupAssociateClientsRequest toAssociateClients(GroupCommandRequest source, Long id); + + GroupDisassociateClientsRequest toDisassociateClients(GroupCommandRequest source, Long id); + + GroupAssignStaffRequest toAssignStaff(GroupCommandRequest source, Long id); + + GroupUnassignStaffRequest toUnassignStaff(GroupCommandRequest source, Long id); + + @Mapping(target = "groupId", source = "groupId") + GroupAssignRoleRequest toAssignRole(GroupCommandRequest source, Long groupId); + + @Mapping(target = "groupId", source = "groupId") + @Mapping(target = "roleId", source = "roleId") + GroupUnassignRoleRequest toUnassignRole(GroupCommandRequest source, Long groupId, Long roleId); + + @Mapping(target = "groupId", source = "groupId") + @Mapping(target = "roleId", source = "roleId") + GroupUpdateRoleRequest toUpdateRole(GroupCommandRequest source, Long groupId, Long roleId); + + GroupTransferClientsRequest toTransferClients(GroupCommandRequest source, Long id); + + GroupSaveCollectionSheetRequest toSaveCollectionSheet(GroupCommandRequest source, Long id); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/GroupDateMapper.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/GroupDateMapper.java new file mode 100644 index 00000000000..4753953c60d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/mapping/GroupDateMapper.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.mapping; + +import java.time.LocalDate; +import org.apache.commons.lang3.StringUtils; +import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; +import org.springframework.stereotype.Component; + +@Component +public class GroupDateMapper { + + public LocalDate toLocalDate(final String value, final String parameterName, final String dateFormat, final String locale) { + if (StringUtils.isBlank(value)) { + return null; + } + return JsonParserHelper.convertFrom(value, parameterName, dateFormat, JsonParserHelper.localeFromString(locale)); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupRolesDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupRolesDataValidator.java deleted file mode 100644 index 5c38b46ce9b..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupRolesDataValidator.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.serialization; - -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; -import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class GroupRolesDataValidator { - - private final FromJsonHelper fromApiJsonHelper; - private static final Set GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<>( - Arrays.asList(GroupingTypesApiConstants.roleParamName, GroupingTypesApiConstants.clientIdParamName)); - - @Autowired - public GroupRolesDataValidator(final FromJsonHelper fromApiJsonHelper) { - this.fromApiJsonHelper = fromApiJsonHelper; - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException(dataValidationErrors); - } - } - - public void validateForCreateGroupRole(final JsonCommand command) { - - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_ROLES_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_ROLE_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final Long roleId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.roleParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.roleParamName).value(roleId).notNull().longGreaterThanZero(); - - final Long clientId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.clientIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.clientIdParamName).value(clientId).notNull().longGreaterThanZero(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForUpdateRole(final JsonCommand command) { - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_ROLES_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_ROLE_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final Long roleId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.roleParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.roleParamName).value(roleId).ignoreIfNull().notBlank() - .longGreaterThanZero(); - - final Long clientId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.clientIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.clientIdParamName).value(clientId).ignoreIfNull().notBlank() - .longGreaterThanZero(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java deleted file mode 100644 index 25470d90cb8..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/serialization/GroupingTypesDataValidator.java +++ /dev/null @@ -1,617 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.serialization; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; -import java.time.LocalDate; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; -import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.portfolio.client.api.ClientApiConstants; -import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; -import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public final class GroupingTypesDataValidator { - - private final FromJsonHelper fromApiJsonHelper; - private final GroupRepositoryWrapper groupRepositoryWrapper; - - private static final Set CENTER_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(GroupingTypesApiConstants.localeParamName, - GroupingTypesApiConstants.dateFormatParamName, GroupingTypesApiConstants.idParamName, GroupingTypesApiConstants.nameParamName, - GroupingTypesApiConstants.externalIdParamName, GroupingTypesApiConstants.officeIdParamName, - GroupingTypesApiConstants.staffIdParamName, GroupingTypesApiConstants.activeParamName, - GroupingTypesApiConstants.activationDateParamName, GroupingTypesApiConstants.groupMembersParamName, - GroupingTypesApiConstants.submittedOnDateParamName, GroupingTypesApiConstants.datatables)); - - private static final Set GROUP_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(GroupingTypesApiConstants.localeParamName, - GroupingTypesApiConstants.dateFormatParamName, GroupingTypesApiConstants.idParamName, GroupingTypesApiConstants.nameParamName, - GroupingTypesApiConstants.externalIdParamName, GroupingTypesApiConstants.centerIdParamName, - GroupingTypesApiConstants.officeIdParamName, GroupingTypesApiConstants.staffIdParamName, - GroupingTypesApiConstants.activeParamName, GroupingTypesApiConstants.activationDateParamName, - GroupingTypesApiConstants.clientMembersParamName, GroupingTypesApiConstants.collectionMeetingCalendar, - GroupingTypesApiConstants.submittedOnDateParamName, GroupingTypesApiConstants.datatables)); - - private static final Set ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<>( - Arrays.asList(GroupingTypesApiConstants.localeParamName, GroupingTypesApiConstants.dateFormatParamName, - GroupingTypesApiConstants.activationDateParamName)); - - private static final Set GROUP_CLOSE_REQUEST_DATA_PARAMETERS = new HashSet<>( - Arrays.asList(GroupingTypesApiConstants.localeParamName, GroupingTypesApiConstants.dateFormatParamName, - GroupingTypesApiConstants.closureDateParamName, GroupingTypesApiConstants.closureReasonIdParamName)); - - @Autowired - public GroupingTypesDataValidator(final FromJsonHelper fromApiJsonHelper, final GroupRepositoryWrapper groupRepositoryWrapper) { - this.fromApiJsonHelper = fromApiJsonHelper; - this.groupRepositoryWrapper = groupRepositoryWrapper; - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { - // - throw new PlatformApiDataValidationException(dataValidationErrors); - } - } - - public void validateForCreateCenter(final JsonCommand command) { - - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, CENTER_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final String name = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.nameParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.externalIdParamName, element)) { - final String externalId = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.externalIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100); - } - - final Long officeId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.officeIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.officeIdParamName).value(officeId).notNull().integerGreaterThanZero(); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.staffIdParamName, element)) { - final Long staffId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.staffIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.staffIdParamName).value(staffId).integerGreaterThanZero(); - } - - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(GroupingTypesApiConstants.activeParamName, element); - if (active != null) { - if (active.booleanValue()) { - final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.activationDateParamName, - element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activationDateParamName).value(joinedDate).notNull(); - } else { - // TODO - KW - not using config for now - just supporting move - // to pending or active out of box. - final boolean isPendingApprovalEnabled = true; - if (!isPendingApprovalEnabled) { - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activeParamName) - .failWithCode(".pending.status.not.allowed"); - } - } - } else { - baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.submittedOnDateParamName, element)) { - final LocalDate submittedOnDate = this.fromApiJsonHelper - .extractLocalDateNamed(GroupingTypesApiConstants.submittedOnDateParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)) { - final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForCreateCenterGroup(final JsonCommand command) { - - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final String name = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.nameParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.externalIdParamName, element)) { - final String externalId = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.externalIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100); - } - - final Long centerId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.centerIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.centerIdParamName).value(centerId).notNull().integerGreaterThanZero(); - - // office is inherited from center - final Long officeId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.officeIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.officeIdParamName).value(officeId).notNull().integerGreaterThanZero(); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.staffIdParamName, element)) { - final Long staffId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.staffIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.staffIdParamName).value(staffId).integerGreaterThanZero(); - } - - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(GroupingTypesApiConstants.activeParamName, element); - if (active != null) { - if (active.booleanValue()) { - final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.activationDateParamName, - element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activationDateParamName).value(joinedDate).notNull(); - } else { - // TODO - KW - not using config for now - just supporting move - // to pending or active out of box. - final boolean isPendingApprovalEnabled = true; - if (!isPendingApprovalEnabled) { - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activeParamName) - .failWithCode(".pending.status.not.allowed"); - } - } - } else { - baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.submittedOnDateParamName, element)) { - final LocalDate submittedOnDate = this.fromApiJsonHelper - .extractLocalDateNamed(GroupingTypesApiConstants.submittedOnDateParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)) { - final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForCreateGroup(final JsonCommand command) { - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final String name = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.nameParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.externalIdParamName, element)) { - final String externalId = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.externalIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100); - } - - // office is inherited from center - final Long officeId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.officeIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.officeIdParamName).value(officeId).notNull().integerGreaterThanZero(); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.staffIdParamName, element)) { - final Long staffId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.staffIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.staffIdParamName).value(staffId).integerGreaterThanZero(); - } - - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(GroupingTypesApiConstants.activeParamName, element); - if (active != null) { - if (active.booleanValue()) { - final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.activationDateParamName, - element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activationDateParamName).value(joinedDate).notNull(); - } else { - // TODO - KW - not using config for now - just supporting move - // to pending or active out of box. - final boolean isPendingApprovalEnabled = true; - if (!isPendingApprovalEnabled) { - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activeParamName) - .failWithCode(".pending.status.not.allowed"); - } - } - } else { - baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.submittedOnDateParamName, element)) { - final LocalDate submittedOnDate = this.fromApiJsonHelper - .extractLocalDateNamed(GroupingTypesApiConstants.submittedOnDateParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.datatables, element)) { - final JsonArray datatables = this.fromApiJsonHelper.extractJsonArrayNamed(GroupingTypesApiConstants.datatables, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.datatables).value(datatables).notNull().jsonArrayNotEmpty(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForUpdateCenter(final JsonCommand command, final Long centerId) { - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, CENTER_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final String name = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.nameParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.externalIdParamName, element)) { - final String externalId = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.externalIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100); - } - - // dont support update of office at present when updating center? - // final Long officeId = - // this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.officeIdParamName, - // element); - // baseDataValidator.reset().parameter(GroupingTypesApiConstants.officeIdParamName).value(officeId).notNull().integerGreaterThanZero(); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.staffIdParamName, element)) { - final Long staffId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.staffIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.staffIdParamName).value(staffId).integerGreaterThanZero(); - } - - LocalDate submittedOnDate = this.groupRepositoryWrapper.retrieveSubmittedOndate(centerId); - - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(GroupingTypesApiConstants.activeParamName, element); - if ((active != null && active) - || this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.activationDateParamName, element)) { - final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.activationDateParamName, - element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activationDateParamName).value(joinedDate).notNull() - .validateDateAfter(submittedOnDate); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForUpdateGroup(final JsonCommand command, final Long groupId) { - final String json = command.json(); - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final String name = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.nameParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.externalIdParamName, element)) { - final String externalId = this.fromApiJsonHelper.extractStringNamed(GroupingTypesApiConstants.externalIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.officeIdParamName, element)) { - final Long officeId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.officeIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.officeIdParamName).value(officeId).notNull() - .integerGreaterThanZero(); - } - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.staffIdParamName, element)) { - final Long staffId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.staffIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.staffIdParamName).value(staffId).integerGreaterThanZero(); - } - - LocalDate submittedOnDate = this.groupRepositoryWrapper.retrieveSubmittedOndate(groupId); - - if (this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.submittedOnDateParamName, element)) { - submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.submittedOnDateParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull(); - } - - final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(GroupingTypesApiConstants.activeParamName, element); - if ((active != null && active) - || this.fromApiJsonHelper.parameterExists(GroupingTypesApiConstants.activationDateParamName, element)) { - final LocalDate joinedDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.activationDateParamName, - element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activationDateParamName).value(joinedDate).notNull() - .validateDateAfter(submittedOnDate); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForActivation(final JsonCommand command, final String resourceName) { - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ACTIVATION_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(resourceName); - - final JsonElement element = command.parsedJson(); - - final LocalDate activationDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.activationDateParamName, - element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.activationDateParamName).value(activationDate).notNull(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForUnassignStaff(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParametersUnassignStaff = new HashSet<>(Arrays.asList("staffId")); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParametersUnassignStaff); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); - - final String staffIdParameterName = "staffId"; - final Long staffId = this.fromApiJsonHelper.extractLongNamed(staffIdParameterName, element); - baseDataValidator.reset().parameter(staffIdParameterName).value(staffId).notNull().integerGreaterThanZero(); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException(dataValidationErrors); - } - } - - public void validateForAssignStaff(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParametersAssignStaff = new HashSet<>( - Arrays.asList(GroupingTypesApiConstants.staffIdParamName, GroupingTypesApiConstants.inheritStaffForClientAccounts)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParametersAssignStaff); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - - final String staffIdParameterName = GroupingTypesApiConstants.staffIdParamName; - final Long staffId = this.fromApiJsonHelper.extractLongNamed(staffIdParameterName, element); - baseDataValidator.reset().parameter(staffIdParameterName).value(staffId).notNull().longGreaterThanZero(); - - final String inheritStaffForClientAccountsParamName = GroupingTypesApiConstants.inheritStaffForClientAccounts; - final Boolean inheritStaffForClientAccounts = this.fromApiJsonHelper.extractBooleanNamed(inheritStaffForClientAccountsParamName, - element); - baseDataValidator.reset().parameter(inheritStaffForClientAccountsParamName).value(inheritStaffForClientAccounts).ignoreIfNull() - .notBlank().isOneOfTheseValues(true, false); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException(dataValidationErrors); - } - } - - public void validateForAssociateClients(final String json) { - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParameters = new HashSet<>(Arrays.asList(GroupingTypesApiConstants.clientMembersParamName)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); - final String[] clients = this.fromApiJsonHelper.extractArrayNamed(GroupingTypesApiConstants.clientMembersParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.clientMembersParamName).value(clients).arrayNotEmpty(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForDisassociateClients(final String json) { - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParameters = new HashSet<>(Arrays.asList(GroupingTypesApiConstants.clientMembersParamName)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); - final String[] clients = this.fromApiJsonHelper.extractArrayNamed(GroupingTypesApiConstants.clientMembersParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.clientMembersParamName).value(clients).arrayNotEmpty(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForGroupClose(final JsonCommand command) { - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_CLOSE_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final LocalDate closureDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.closureDateParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureDateParamName).value(closureDate).notNull(); - - final Long closureReasonId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.closureReasonIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureReasonIdParamName).value(closureReasonId).notNull() - .longGreaterThanZero(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - - } - - public void validateForCenterClose(final JsonCommand command) { - final String json = command.json(); - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, GROUP_CLOSE_REQUEST_DATA_PARAMETERS); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) - .resource(GroupingTypesApiConstants.CENTER_RESOURCE_NAME); - - final JsonElement element = command.parsedJson(); - - final LocalDate closureDate = this.fromApiJsonHelper.extractLocalDateNamed(GroupingTypesApiConstants.closureDateParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureDateParamName).value(closureDate).notNull(); - - final Long closureReasonId = this.fromApiJsonHelper.extractLongNamed(GroupingTypesApiConstants.closureReasonIdParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.closureReasonIdParamName).value(closureReasonId).notNull() - .longGreaterThanZero(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - - } - - public void validateForAssociateGroups(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParameters = new HashSet<>(Arrays.asList(GroupingTypesApiConstants.groupMembersParamName)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); - final String[] groups = this.fromApiJsonHelper.extractArrayNamed(GroupingTypesApiConstants.groupMembersParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.groupMembersParamName).value(groups).arrayNotEmpty(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - - } - - public void validateForDisassociateGroups(final String json) { - - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - - final Set supportedParameters = new HashSet<>(Arrays.asList(GroupingTypesApiConstants.groupMembersParamName)); - - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList<>(); - - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); - final String[] groups = this.fromApiJsonHelper.extractArrayNamed(GroupingTypesApiConstants.groupMembersParamName, element); - baseDataValidator.reset().parameter(GroupingTypesApiConstants.groupMembersParamName).value(groups).arrayNotEmpty(); - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWritePlatformServiceJpaRepositoryImpl.java deleted file mode 100644 index 6d4825a67b0..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWritePlatformServiceJpaRepositoryImpl.java +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.service; - -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.fineract.infrastructure.codes.domain.CodeValue; -import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; -import org.apache.fineract.infrastructure.core.exception.ErrorHandler; -import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.portfolio.client.domain.Client; -import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; -import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; -import org.apache.fineract.portfolio.group.domain.Group; -import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; -import org.apache.fineract.portfolio.group.domain.GroupRole; -import org.apache.fineract.portfolio.group.domain.GroupRoleRepositoryWrapper; -import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException; -import org.apache.fineract.portfolio.group.serialization.GroupRolesDataValidator; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.dao.NonTransientDataAccessException; -import org.springframework.orm.jpa.JpaSystemException; - -@Slf4j -@RequiredArgsConstructor -public class GroupRolesWritePlatformServiceJpaRepositoryImpl implements GroupRolesWritePlatformService { - - private final PlatformSecurityContext context; - private final GroupRepositoryWrapper groupRepository; - private final GroupRolesDataValidator fromApiJsonDeserializer; - private final CodeValueRepositoryWrapper codeValueRepository; - private final ClientRepositoryWrapper clientRepository; - private final GroupRoleRepositoryWrapper groupRoleRepository; - - @Override - public CommandProcessingResult createRole(final JsonCommand command) { - - try { - this.context.authenticatedUser(); - this.fromApiJsonDeserializer.validateForCreateGroupRole(command); - - final Long roleId = command.longValueOfParameterNamed(GroupingTypesApiConstants.roleParamName); - final CodeValue role = this.codeValueRepository.findOneWithNotFoundDetection(roleId); - - final Long clientId = command.longValueOfParameterNamed(GroupingTypesApiConstants.clientIdParamName); - final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId); - - final Group group = this.groupRepository.findOneWithNotFoundDetection(command.getGroupId()); - if (!group.hasClientAsMember(client)) { - throw new ClientNotInGroupException(clientId, command.getGroupId()); - } - final GroupRole groupRole = GroupRole.createGroupRole(group, client, role); - this.groupRoleRepository.saveAndFlush(groupRole); - return new CommandProcessingResultBuilder() // - .withClientId(client.getId()) // - .withGroupId(group.getId()) // - .withEntityId(groupRole.getId()) // - .build(); - - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - final Throwable throwable = dve.getMostSpecificCause(); - handleGroupDataIntegrityIssues(command, throwable, dve); - return CommandProcessingResult.empty(); - } - - } - - private void handleGroupDataIntegrityIssues(final JsonCommand command, final Throwable realCause, - final NonTransientDataAccessException dve) { - - if (realCause.getMessage().contains("UNIQUE_GROUP_ROLES")) { - final String clientId = command.stringValueOfParameterNamed(GroupingTypesApiConstants.clientIdParamName); - final String roleId = command.stringValueOfParameterNamed(GroupingTypesApiConstants.roleParamName); - final String errorMessageForUser = "Group Role with roleId `" + roleId + "`, clientId `" + clientId + "`, groupId `" - + command.getGroupId() + "` already exists."; - final String errorMessageForMachine = "error.msg.group.role.already.exists"; - throw new PlatformDataIntegrityException(errorMessageForMachine, errorMessageForUser, - GroupingTypesApiConstants.clientIdParamName, roleId, clientId, command.getGroupId()); - } - - log.error("Error occurred.", dve); - throw ErrorHandler.getMappable(dve, "error.msg.group.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); - } - - @Override - public CommandProcessingResult updateRole(final JsonCommand command) { - try { - this.context.authenticatedUser(); - this.fromApiJsonDeserializer.validateForUpdateRole(command); - - final Group group = this.groupRepository.findOneWithNotFoundDetection(command.getGroupId()); - - final GroupRole groupRole = this.groupRoleRepository.findOneWithNotFoundDetection(command.entityId()); - final Map actualChanges = groupRole.update(command); - - if (actualChanges.containsKey(GroupingTypesApiConstants.roleParamName)) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.roleParamName); - - CodeValue role = null; - if (newValue != null) { - role = this.codeValueRepository.findOneWithNotFoundDetection(newValue); - } - groupRole.updateRole(role); - } - - if (actualChanges.containsKey(GroupingTypesApiConstants.clientIdParamName)) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.clientIdParamName); - - Client client = null; - if (newValue != null) { - client = this.clientRepository.findOneWithNotFoundDetection(newValue); - if (!group.hasClientAsMember(client)) { - throw new ClientNotInGroupException(newValue, command.getGroupId()); - } - } - groupRole.updateClient(client); - } - - this.groupRoleRepository.saveAndFlush(groupRole); - return new CommandProcessingResultBuilder() // - .with(actualChanges) // - .withGroupId(group.getId()) // - .withEntityId(groupRole.getId()) // - .build(); - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - final Throwable throwable = dve.getMostSpecificCause(); - handleGroupDataIntegrityIssues(command, throwable, dve); - return CommandProcessingResult.empty(); - } - - } - - @Override - public CommandProcessingResult deleteRole(final Long ruleId) { - this.context.authenticatedUser(); - final GroupRole groupRole = this.groupRoleRepository.findOneWithNotFoundDetection(ruleId); - this.groupRoleRepository.delete(groupRole); - return new CommandProcessingResultBuilder() // - .withEntityId(groupRole.getId()) // - .build(); - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteService.java new file mode 100644 index 00000000000..8aab6fe10cd --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteService.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.service; + +import org.apache.fineract.portfolio.group.data.GroupAssignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupUnassignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRoleRequest; + +public interface GroupRolesWriteService { + + GroupCommandResponse assignRole(GroupAssignRoleRequest request); + + GroupCommandResponse unassignRole(GroupUnassignRoleRequest request); + + GroupCommandResponse updateRole(GroupUpdateRoleRequest request); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteServiceImpl.java new file mode 100644 index 00000000000..7f22f2a6d66 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteServiceImpl.java @@ -0,0 +1,124 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.service; + +import java.util.LinkedHashMap; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.infrastructure.codes.domain.CodeValue; +import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; +import org.apache.fineract.infrastructure.core.exception.ErrorHandler; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; +import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; +import org.apache.fineract.portfolio.group.data.GroupAssignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupUnassignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRoleRequest; +import org.apache.fineract.portfolio.group.domain.Group; +import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; +import org.apache.fineract.portfolio.group.domain.GroupRole; +import org.apache.fineract.portfolio.group.domain.GroupRoleRepositoryWrapper; +import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.NonTransientDataAccessException; +import org.springframework.orm.jpa.JpaSystemException; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@RequiredArgsConstructor +public class GroupRolesWriteServiceImpl implements GroupRolesWriteService { + + private final PlatformSecurityContext context; + private final GroupRepositoryWrapper groupRepository; + private final CodeValueRepositoryWrapper codeValueRepository; + private final ClientRepositoryWrapper clientRepository; + private final GroupRoleRepositoryWrapper groupRoleRepository; + + @Transactional + @Override + public GroupCommandResponse assignRole(final GroupAssignRoleRequest request) { + try { + context.authenticatedUser(); + final CodeValue role = codeValueRepository.findOneWithNotFoundDetection(request.getRole()); + final Client client = clientRepository.findOneWithNotFoundDetection(request.getClientId()); + final Group group = groupRepository.findOneWithNotFoundDetection(request.getGroupId()); + if (!group.hasClientAsMember(client)) { + throw new ClientNotInGroupException(request.getClientId(), request.getGroupId()); + } + final GroupRole groupRole = GroupRole.createGroupRole(group, client, role); + groupRoleRepository.saveAndFlush(groupRole); + return GroupCommandResponse.builder().clientId(client.getId()).groupId(group.getId()).resourceId(groupRole.getId()).build(); + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + throw handleGroupDataIntegrityIssues(request.getGroupId(), request.getClientId(), request.getRole(), dve.getMostSpecificCause(), + dve); + } + } + + @Transactional + @Override + public GroupCommandResponse updateRole(final GroupUpdateRoleRequest request) { + try { + context.authenticatedUser(); + final Group group = groupRepository.findOneWithNotFoundDetection(request.getGroupId()); + final GroupRole groupRole = groupRoleRepository.findOneWithNotFoundDetection(request.getRoleId()); + final Map actualChanges = new LinkedHashMap<>(2); + if (request.getClientId() != null && !request.getClientId().equals(groupRole.getClient().getId())) { + actualChanges.put(GroupingTypesApiConstants.clientIdParamName, request.getClientId()); + final Client client = clientRepository.findOneWithNotFoundDetection(request.getClientId()); + if (!group.hasClientAsMember(client)) { + throw new ClientNotInGroupException(request.getClientId(), request.getGroupId()); + } + groupRole.updateClient(client); + } + if (request.getRole() != null && !request.getRole().equals(groupRole.getRole().getId())) { + actualChanges.put(GroupingTypesApiConstants.roleParamName, request.getRole()); + groupRole.updateRole(codeValueRepository.findOneWithNotFoundDetection(request.getRole())); + } + groupRoleRepository.saveAndFlush(groupRole); + return GroupCommandResponse.builder().groupId(group.getId()).resourceId(groupRole.getId()).changes(actualChanges).build(); + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + throw handleGroupDataIntegrityIssues(request.getGroupId(), request.getClientId(), request.getRole(), dve.getMostSpecificCause(), + dve); + } + } + + @Transactional + @Override + public GroupCommandResponse unassignRole(final GroupUnassignRoleRequest request) { + context.authenticatedUser(); + final GroupRole groupRole = groupRoleRepository.findOneWithNotFoundDetection(request.getRoleId()); + groupRoleRepository.delete(groupRole); + return GroupCommandResponse.builder().groupId(request.getGroupId()).resourceId(groupRole.getId()).build(); + } + + private RuntimeException handleGroupDataIntegrityIssues(final Long groupId, final Long clientId, final Long roleId, + final Throwable realCause, final NonTransientDataAccessException dve) { + if (realCause != null && realCause.getMessage() != null && realCause.getMessage().contains("UNIQUE_GROUP_ROLES")) { + return new PlatformDataIntegrityException("error.msg.group.role.already.exists", + "Group Role with roleId `" + roleId + "`, clientId `" + clientId + "`, groupId `" + groupId + "` already exists.", + GroupingTypesApiConstants.clientIdParamName, roleId, clientId, groupId); + } + log.error("Error occurred.", dve); + return ErrorHandler.getMappable(dve, "error.msg.group.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformService.java deleted file mode 100644 index df8931f3e9e..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformService.java +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.service; - -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; - -public interface GroupingTypesWritePlatformService { - - CommandProcessingResult createCenter(JsonCommand command); - - CommandProcessingResult updateCenter(Long entityId, JsonCommand command); - - CommandProcessingResult createGroup(Long centerId, JsonCommand command); - - CommandProcessingResult activateGroupOrCenter(Long entityId, JsonCommand command); - - CommandProcessingResult updateGroup(Long groupId, JsonCommand command); - - CommandProcessingResult deleteGroup(Long groupId); - - CommandProcessingResult closeGroup(Long groupId, JsonCommand command); - - CommandProcessingResult closeCenter(Long centerId, JsonCommand command); - - CommandProcessingResult unassignGroupOrCenterStaff(Long groupId, JsonCommand command); - - CommandProcessingResult assignGroupOrCenterStaff(Long groupId, JsonCommand command); - - CommandProcessingResult associateClientsToGroup(Long groupId, JsonCommand command); - - CommandProcessingResult disassociateClientsFromGroup(Long groupId, JsonCommand command); - - CommandProcessingResult associateGroupsToCenter(Long centerId, JsonCommand command); - - CommandProcessingResult disassociateGroupsToCenter(Long centerId, JsonCommand command); -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteService.java new file mode 100644 index 00000000000..4b411805f18 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteService.java @@ -0,0 +1,79 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.service; + +import org.apache.fineract.portfolio.group.data.CenterActivateRequest; +import org.apache.fineract.portfolio.group.data.CenterAssociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterCloseRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterCreateRequest; +import org.apache.fineract.portfolio.group.data.CenterCreateResponse; +import org.apache.fineract.portfolio.group.data.CenterDeleteRequest; +import org.apache.fineract.portfolio.group.data.CenterDeleteResponse; +import org.apache.fineract.portfolio.group.data.CenterDisassociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterUpdateRequest; +import org.apache.fineract.portfolio.group.data.CenterUpdateResponse; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupAssignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupAssociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupCloseRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; +import org.apache.fineract.portfolio.group.data.GroupDeleteRequest; +import org.apache.fineract.portfolio.group.data.GroupDeleteResponse; +import org.apache.fineract.portfolio.group.data.GroupDisassociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateResponse; + +public interface GroupingTypesWriteService { + + GroupCreateResponse createGroup(GroupCreateRequest request); + + GroupUpdateResponse updateGroup(GroupUpdateRequest request); + + GroupDeleteResponse deleteGroup(GroupDeleteRequest request); + + GroupCommandResponse activateGroup(GroupActivateRequest request); + + GroupCommandResponse closeGroup(GroupCloseRequest request); + + GroupCommandResponse associateClients(GroupAssociateClientsRequest request); + + GroupCommandResponse disassociateClients(GroupDisassociateClientsRequest request); + + GroupCommandResponse assignStaff(GroupAssignStaffRequest request); + + GroupCommandResponse unassignStaff(GroupUnassignStaffRequest request); + + CenterCreateResponse createCenter(CenterCreateRequest request); + + CenterUpdateResponse updateCenter(CenterUpdateRequest request); + + CenterDeleteResponse deleteCenter(CenterDeleteRequest request); + + CenterCommandResponse activateCenter(CenterActivateRequest request); + + CenterCommandResponse closeCenter(CenterCloseRequest request); + + CenterCommandResponse associateGroups(CenterAssociateGroupsRequest request); + + CenterCommandResponse disassociateGroups(CenterDisassociateGroupsRequest request); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteServiceImpl.java similarity index 50% rename from fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java rename to fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteServiceImpl.java index 996f1d655c5..09458050c77 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteServiceImpl.java @@ -18,33 +18,36 @@ */ package org.apache.fineract.portfolio.group.service; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import jakarta.persistence.PersistenceException; import java.time.LocalDate; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.service.CommandProcessingService; -import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; import org.apache.fineract.infrastructure.accountnumberformat.domain.EntityAccountType; import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; -import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.exception.ErrorHandler; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; @@ -70,6 +73,30 @@ import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.portfolio.client.service.LoanStatusMapper; import org.apache.fineract.portfolio.group.api.GroupingTypesApiConstants; +import org.apache.fineract.portfolio.group.data.CenterActivateRequest; +import org.apache.fineract.portfolio.group.data.CenterAssociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterCloseRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.data.CenterCreateRequest; +import org.apache.fineract.portfolio.group.data.CenterCreateResponse; +import org.apache.fineract.portfolio.group.data.CenterDeleteRequest; +import org.apache.fineract.portfolio.group.data.CenterDeleteResponse; +import org.apache.fineract.portfolio.group.data.CenterDisassociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterUpdateRequest; +import org.apache.fineract.portfolio.group.data.CenterUpdateResponse; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupAssignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupAssociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupCloseRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; +import org.apache.fineract.portfolio.group.data.GroupDeleteRequest; +import org.apache.fineract.portfolio.group.data.GroupDeleteResponse; +import org.apache.fineract.portfolio.group.data.GroupDisassociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateResponse; import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.domain.GroupLevel; import org.apache.fineract.portfolio.group.domain.GroupLevelRepository; @@ -82,7 +109,7 @@ import org.apache.fineract.portfolio.group.exception.GroupMustBePendingToBeDeletedException; import org.apache.fineract.portfolio.group.exception.InvalidGroupLevelException; import org.apache.fineract.portfolio.group.exception.InvalidGroupStateTransitionException; -import org.apache.fineract.portfolio.group.serialization.GroupingTypesDataValidator; +import org.apache.fineract.portfolio.group.mapping.GroupDateMapper; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService; @@ -95,11 +122,10 @@ import org.springframework.orm.jpa.JpaSystemException; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; @Slf4j @RequiredArgsConstructor -public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements GroupingTypesWritePlatformService { +public class GroupingTypesWriteServiceImpl implements GroupingTypesWriteService { private final PlatformSecurityContext context; private final GroupRepositoryWrapper groupRepository; @@ -108,10 +134,8 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group private final StaffRepositoryWrapper staffRepository; private final NoteRepository noteRepository; private final GroupLevelRepository groupLevelRepository; - private final GroupingTypesDataValidator fromApiJsonDeserializer; private final LoanRepositoryWrapper loanRepositoryWrapper; private final CodeValueRepositoryWrapper codeValueRepository; - private final CommandProcessingService commandProcessingService; private final CalendarInstanceRepository calendarInstanceRepository; private final ConfigurationDomainService configurationDomainService; private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper; @@ -121,118 +145,357 @@ public class GroupingTypesWritePlatformServiceJpaRepositoryImpl implements Group private final BusinessEventNotifierService businessEventNotifierService; private final LoanOfficerService loanOfficerService; private final ExternalIdFactory externalIdFactory; + private final GroupDateMapper dateMapper; - private CommandProcessingResult createGroupingType(final JsonCommand command, final GroupTypes groupingType, final Long centerId) { - try { - final String accountNo = command.stringValueOfParameterNamed(GroupingTypesApiConstants.accountNoParamName); - final String name = command.stringValueOfParameterNamed(GroupingTypesApiConstants.nameParamName); - final String externalId = this.externalIdFactory.createFromCommand(command, GroupingTypesApiConstants.externalIdParamName) - .getValue(); + private record Updated(Group group, Map changes) { + } - final AppUser currentUser = this.context.authenticatedUser(); - Long officeId = null; - Group parentGroup = null; + @Transactional + @Override + public GroupCreateResponse createGroup(final GroupCreateRequest request) { + final Group group = createGroupingType(GroupTypes.GROUP, request.getCenterId(), request.getName(), request.getExternalId(), + request.getOfficeId(), request.getStaffId(), request.getActive(), request.getActivationDate(), request.getSubmittedOnDate(), + request.getClientMembers(), null, request.getDatatables(), request.getDateFormat(), request.getLocale()); + final GroupCreateResponse response = GroupCreateResponse.builder().officeId(group.officeId()).groupId(group.getId()) + .resourceId(group.getId()).build(); + businessEventNotifierService.notifyPostBusinessEvent(new GroupsCreateBusinessEvent(toLegacyResult(group))); + return response; + } - if (centerId == null) { - officeId = command.longValueOfParameterNamed(GroupingTypesApiConstants.officeIdParamName); - } else { - parentGroup = this.groupRepository.findOneWithNotFoundDetection(centerId); - officeId = parentGroup.officeId(); + @Transactional + @Override + public CenterCreateResponse createCenter(final CenterCreateRequest request) { + final Group center = createGroupingType(GroupTypes.CENTER, null, request.getName(), request.getExternalId(), request.getOfficeId(), + request.getStaffId(), request.getActive(), request.getActivationDate(), request.getSubmittedOnDate(), null, + request.getGroupMembers(), request.getDatatables(), request.getDateFormat(), request.getLocale()); + final CenterCreateResponse response = CenterCreateResponse.builder().officeId(center.officeId()).groupId(center.getId()) + .resourceId(center.getId()).build(); + businessEventNotifierService.notifyPostBusinessEvent(new CentersCreateBusinessEvent(toLegacyResult(center))); + return response; + } + + @Transactional + @Override + public GroupUpdateResponse updateGroup(final GroupUpdateRequest request) { + final Updated updated = updateGroupingType(request.getId(), request.getName(), request.getExternalId(), request.getOfficeId(), + request.getStaffId(), request.getCenterId(), request.getActivationDate(), request.getSubmittedOnDate(), + request.getDateFormat(), request.getLocale(), GroupTypes.GROUP); + return GroupUpdateResponse.builder().officeId(updated.group().officeId()).groupId(updated.group().getId()) + .resourceId(updated.group().getId()).changes(updated.changes()).build(); + } + + @Transactional + @Override + public CenterUpdateResponse updateCenter(final CenterUpdateRequest request) { + final Updated updated = updateGroupingType(request.getId(), request.getName(), request.getExternalId(), request.getOfficeId(), + request.getStaffId(), null, request.getActivationDate(), request.getSubmittedOnDate(), request.getDateFormat(), + request.getLocale(), GroupTypes.CENTER); + return CenterUpdateResponse.builder().officeId(updated.group().officeId()).groupId(updated.group().getId()) + .resourceId(updated.group().getId()).changes(updated.changes()).build(); + } + + @Transactional + @Override + public GroupDeleteResponse deleteGroup(final GroupDeleteRequest request) { + final Group deleted = deleteGroupingType(request.getId()); + return GroupDeleteResponse.builder().officeId(deleted.officeId()).groupId(deleted.getId()).resourceId(deleted.getId()).build(); + } + + @Transactional + @Override + public CenterDeleteResponse deleteCenter(final CenterDeleteRequest request) { + final Group deleted = deleteGroupingType(request.getId()); + return CenterDeleteResponse.builder().officeId(deleted.officeId()).groupId(deleted.getId()).resourceId(deleted.getId()).build(); + } + + @Transactional + @Override + public GroupCommandResponse activateGroup(final GroupActivateRequest request) { + final Group group = activateGroupingType(request.getId(), request.getActivationDate(), request.getDateFormat(), + request.getLocale()); + return GroupCommandResponse.builder().officeId(group.officeId()).groupId(group.getId()).resourceId(group.getId()).build(); + } + + @Transactional + @Override + public CenterCommandResponse activateCenter(final CenterActivateRequest request) { + final Group center = activateGroupingType(request.getId(), request.getActivationDate(), request.getDateFormat(), + request.getLocale()); + return CenterCommandResponse.builder().officeId(center.officeId()).groupId(center.getId()).resourceId(center.getId()).build(); + } + + @Transactional + @Override + public GroupCommandResponse closeGroup(final GroupCloseRequest request) { + final Group group = groupRepository.findOneWithNotFoundDetection(request.getId()); + final LocalDate closureDate = dateMapper.toLocalDate(request.getClosureDate(), GroupingTypesApiConstants.closureDateParamName, + request.getDateFormat(), request.getLocale()); + final AppUser currentUser = context.authenticatedUser(); + final CodeValue closureReason = codeValueRepository + .findOneByCodeNameAndIdWithNotFoundDetection(GroupingTypesApiConstants.GROUP_CLOSURE_REASON, request.getClosureReasonId()); + if (group.hasActiveClients()) { + throw new InvalidGroupStateTransitionException(group.getGroupLevel().getLevelName(), "close", "active.clients.exist", + group.getGroupLevel().getLevelName() + " cannot be closed because of active clients associated with it."); + } + validateLoansAndSavingsForGroupOrCenterClose(group, closureDate); + entityDatatableChecksWritePlatformService.runTheCheck(group.getId(), EntityTables.GROUP.getName(), StatusEnum.CLOSE.getValue(), + EntityTables.GROUP.getForeignKeyColumnNameOnDatatable(), null); + group.close(currentUser, closureReason, closureDate); + groupRepository.saveAndFlush(group); + return GroupCommandResponse.builder().groupId(group.getId()).resourceId(group.getId()).build(); + } + + @Transactional + @Override + public CenterCommandResponse closeCenter(final CenterCloseRequest request) { + final Group center = groupRepository.findOneWithNotFoundDetection(request.getId()); + final LocalDate closureDate = dateMapper.toLocalDate(request.getClosureDate(), GroupingTypesApiConstants.closureDateParamName, + request.getDateFormat(), request.getLocale()); + final CodeValue closureReason = codeValueRepository + .findOneByCodeNameAndIdWithNotFoundDetection(GroupingTypesApiConstants.CENTER_CLOSURE_REASON, request.getClosureReasonId()); + final AppUser currentUser = context.authenticatedUser(); + if (center.hasActiveGroups()) { + throw new InvalidGroupStateTransitionException(center.getGroupLevel().getLevelName(), "close", "active.groups.exist", + center.getGroupLevel().getLevelName() + " cannot be closed because of active groups associated with it."); + } + validateLoansAndSavingsForGroupOrCenterClose(center, closureDate); + // legacy runs the centre close check against the ACTIVATE status; kept as-is + entityDatatableChecksWritePlatformService.runTheCheck(center.getId(), EntityTables.GROUP.getName(), StatusEnum.ACTIVATE.getValue(), + EntityTables.GROUP.getForeignKeyColumnNameOnDatatable(), null); + center.close(currentUser, closureReason, closureDate); + groupRepository.saveAndFlush(center); + return CenterCommandResponse.builder().resourceId(center.getId()).build(); + } + + @Transactional + @Override + public GroupCommandResponse associateClients(final GroupAssociateClientsRequest request) { + final Group group = groupRepository.findOneWithNotFoundDetection(request.getId()); + final Set clientMembers = assembleSetOfClients(group.officeId(), request.getClientMembers()); + final Map actualChanges = new HashMap<>(); + final List changes = group.associateClients(clientMembers); + if (group.isGroup()) { + validateGroupRulesBeforeClientAssociation(group); + } + if (!changes.isEmpty()) { + actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); + } + groupRepository.saveAndFlush(group); + return GroupCommandResponse.builder().officeId(group.officeId()).groupId(group.getId()).resourceId(group.getId()) + .changes(actualChanges).build(); + } + + @Transactional + @Override + public GroupCommandResponse disassociateClients(final GroupDisassociateClientsRequest request) { + final Group group = groupRepository.findOneWithNotFoundDetection(request.getId()); + final Set clientMembers = assembleSetOfClients(group.officeId(), request.getClientMembers()); + // check if any client has got group loans + checkForActiveJLGLoans(group.getId(), clientMembers); + validateForJLGSavings(group.getId(), clientMembers); + final Map actualChanges = new HashMap<>(); + final List changes = group.disassociateClients(clientMembers); + if (!changes.isEmpty()) { + actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); + } + groupRepository.saveAndFlush(group); + return GroupCommandResponse.builder().officeId(group.officeId()).groupId(group.getId()).resourceId(group.getId()) + .changes(actualChanges).build(); + } + + @Transactional + @Override + public CenterCommandResponse associateGroups(final CenterAssociateGroupsRequest request) { + final Group center = groupRepository.findOneWithNotFoundDetection(request.getId()); + final Set groupMembers = assembleSetOfChildGroups(center.officeId(), request.getGroupMembers()); + checkGroupMembersMeetingSyncWithCenterMeeting(center.getId(), groupMembers); + final Map actualChanges = new HashMap<>(); + final List changes = center.associateGroups(groupMembers); + if (!changes.isEmpty()) { + actualChanges.put(GroupingTypesApiConstants.groupMembersParamName, changes); + } + groupRepository.saveAndFlush(center); + return CenterCommandResponse.builder().officeId(center.officeId()).groupId(center.getId()).resourceId(center.getId()) + .changes(actualChanges).build(); + } + + @Transactional + @Override + public CenterCommandResponse disassociateGroups(final CenterDisassociateGroupsRequest request) { + final Group center = groupRepository.findOneWithNotFoundDetection(request.getId()); + final Set groupMembers = assembleSetOfChildGroups(center.officeId(), request.getGroupMembers()); + final Map actualChanges = new HashMap<>(); + final List changes = center.disassociateGroups(groupMembers); + if (!changes.isEmpty()) { + // legacy records centre group removals under the clientMembers key; kept for compatibility + actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); + } + groupRepository.saveAndFlush(center); + return CenterCommandResponse.builder().officeId(center.officeId()).groupId(center.getId()).resourceId(center.getId()) + .changes(actualChanges).build(); + } + + @Transactional + @Override + public GroupCommandResponse assignStaff(final GroupAssignStaffRequest request) { + context.authenticatedUser(); + final Group group = groupRepository.findOneWithNotFoundDetection(request.getId()); + final Staff staff = staffRepository.findByOfficeHierarchyWithNotFoundDetection(request.getStaffId(), + group.getOffice().getHierarchy()); + group.updateStaff(staff); + if (Boolean.TRUE.equals(request.getInheritStaffForClientAccounts())) { + final LocalDate loanOfficerReassignmentDate = DateUtils.getBusinessLocalDate(); + /* + * update loan officer for client and update loan officer for clients loans and savings + */ + final Set clients = group.getClientMembers(); + if (clients != null) { + for (final Client client : clients) { + client.updateStaff(staff); + if (loanRepositoryWrapper.doNonClosedLoanAccountsExistForClient(client.getId())) { + for (final Loan loan : loanRepositoryWrapper.findLoanByClientId(client.getId())) { + if (loan.isDisbursed() && !loan.isClosed()) { + loanOfficerService.reassignLoanOfficer(loan, staff, loanOfficerReassignmentDate); + } + } + } + if (savingsAccountRepositoryWrapper.doNonClosedSavingAccountsExistForClient(client.getId())) { + for (final SavingsAccount savingsAccount : savingsAccountRepositoryWrapper + .findSavingAccountByClientId(client.getId())) { + if (!savingsAccount.isClosed()) { + savingsAccount.reassignSavingsOfficer(staff, loanOfficerReassignmentDate); + } + } + } + } + } + } + groupRepository.saveAndFlush(group); + final Map actualChanges = new LinkedHashMap<>(1); + actualChanges.put(GroupingTypesApiConstants.staffIdParamName, request.getStaffId()); + return GroupCommandResponse.builder().officeId(group.officeId()).groupId(group.getId()).resourceId(group.getId()) + .changes(actualChanges).build(); + } + + @Transactional + @Override + public GroupCommandResponse unassignStaff(final GroupUnassignStaffRequest request) { + context.authenticatedUser(); + final Group group = groupRepository.findOneWithNotFoundDetection(request.getId()); + final Staff presentStaff = group.getStaff(); + if (presentStaff == null) { + throw new GroupHasNoStaffException(request.getId()); + } + // legacy: unassign only when the supplied staffId is not a change from the current staff + if (Objects.equals(request.getStaffId(), presentStaff.getId())) { + group.unassignStaff(); + } + groupRepository.saveAndFlush(group); + final Map actualChanges = new LinkedHashMap<>(1); + actualChanges.put(GroupingTypesApiConstants.staffIdParamName, null); + return GroupCommandResponse.builder().officeId(group.officeId()).groupId(group.getId()).resourceId(group.getId()) + .changes(actualChanges).build(); + } + + private Group activateGroupingType(final Long groupId, final String activationDateValue, final String dateFormat, final String locale) { + try { + final AppUser currentUser = context.authenticatedUser(); + final Group group = groupRepository.findOneWithNotFoundDetection(groupId); + if (group.isGroup()) { + validateGroupRulesBeforeActivation(group); } + final LocalDate activationDate = dateMapper.toLocalDate(activationDateValue, GroupingTypesApiConstants.activationDateParamName, + dateFormat, locale); + validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(group.getOffice(), group.getGroupLevel(), activationDate); + group.activate(currentUser, activationDate); + groupRepository.saveAndFlush(group); + return group; + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + throw handleGroupDataIntegrityIssues(null, null, dve.getMostSpecificCause(), dve, GroupTypes.GROUP); + } catch (final PersistenceException dve) { + throw handleGroupDataIntegrityIssues(null, null, ExceptionUtils.getRootCause(dve.getCause()), dve, GroupTypes.GROUP); + } + } - final Office groupOffice = this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId); + private CommandProcessingResult toLegacyResult(final Group group) { + return new CommandProcessingResultBuilder().withOfficeId(group.officeId()).withGroupId(group.getId()).withEntityId(group.getId()) + .build(); + } - final LocalDate activationDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName); - final GroupLevel groupLevel = this.groupLevelRepository.findById(groupingType.getId()) + private Group createGroupingType(final GroupTypes groupingType, final Long centerId, final String name, final String externalIdValue, + final Long requestedOfficeId, final Long staffId, final Boolean activeFlag, final String activationDateValue, + final String submittedOnDateValue, final List clientMemberIds, final List groupMemberIds, + final List> datatables, final String dateFormat, final String locale) { + try { + final String externalId = externalIdFactory.create(externalIdValue).getValue(); + final AppUser currentUser = context.authenticatedUser(); + Long officeId = requestedOfficeId; + Group parentGroup = null; + if (centerId != null) { + parentGroup = groupRepository.findOneWithNotFoundDetection(centerId); + officeId = parentGroup.officeId(); + } + final Office groupOffice = officeRepositoryWrapper.findOneWithNotFoundDetection(officeId); + final LocalDate activationDate = dateMapper.toLocalDate(activationDateValue, GroupingTypesApiConstants.activationDateParamName, + dateFormat, locale); + final GroupLevel groupLevel = groupLevelRepository.findById(groupingType.getId()) .orElseThrow(() -> new GroupLevelNotFoundException(groupingType.getId())); - validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(groupOffice, groupLevel, activationDate); Staff staff = null; - final Long staffId = command.longValueOfParameterNamed(GroupingTypesApiConstants.staffIdParamName); if (staffId != null) { - staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, groupOffice.getHierarchy()); + staff = staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, groupOffice.getHierarchy()); } + final Set clientMembers = assembleSetOfClients(officeId, clientMemberIds); + final Set groupMembers = assembleSetOfChildGroups(officeId, groupMemberIds); - final Set clientMembers = assembleSetOfClients(officeId, command); - - final Set groupMembers = assembleSetOfChildGroups(officeId, command); - - final boolean active = command.booleanPrimitiveValueOfParameterNamed(GroupingTypesApiConstants.activeParamName); + final boolean active = Boolean.TRUE.equals(activeFlag); LocalDate submittedOnDate = DateUtils.getBusinessLocalDate(); if (active && DateUtils.isAfter(submittedOnDate, activationDate)) { submittedOnDate = activationDate; } - if (command.hasParameter(GroupingTypesApiConstants.submittedOnDateParamName)) { - submittedOnDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.submittedOnDateParamName); + if (StringUtils.isNotBlank(submittedOnDateValue)) { + submittedOnDate = dateMapper.toLocalDate(submittedOnDateValue, GroupingTypesApiConstants.submittedOnDateParamName, + dateFormat, locale); } final Group newGroup = Group.newGroup(groupOffice, staff, parentGroup, groupLevel, name, externalId, active, activationDate, - clientMembers, groupMembers, submittedOnDate, currentUser, accountNo); + clientMembers, groupMembers, submittedOnDate, currentUser, null); - boolean rollbackTransaction = false; if (newGroup.isActive()) { - this.groupRepository.saveAndFlush(newGroup); + groupRepository.saveAndFlush(newGroup); // validate Group creation rules for Group if (newGroup.isGroup()) { validateGroupRulesBeforeActivation(newGroup); } - - if (newGroup.isCenter()) { - final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateCenter(null).build(); - rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); - } else { - final CommandWrapper commandWrapper = new CommandWrapperBuilder().activateGroup(null).build(); - rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); - } } - if (!newGroup.isCenter() && newGroup.hasActiveClients()) { - final CommandWrapper commandWrapper = new CommandWrapperBuilder().associateClientsToGroup(newGroup.getId()).build(); - rollbackTransaction = this.commandProcessingService.validateRollbackCommand(commandWrapper, currentUser); - } - - this.groupRepository.save(newGroup); + groupRepository.save(newGroup); - // Account Number generation - if (StringUtils.isBlank(accountNo)) { - generateAccountNumber(newGroup); - } + generateAccountNumber(newGroup); /* * Generate hierarchy for a new center/group and all the child groups if they exist */ newGroup.generateHierarchy(); - this.groupRepository.saveAndFlush(newGroup); + groupRepository.saveAndFlush(newGroup); newGroup.captureStaffHistoryDuringCenterCreation(staff, activationDate); if (newGroup.isGroup()) { - if (command.parameterExists(GroupingTypesApiConstants.datatables)) { - this.entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getValue(), - EntityTables.GROUP.getName(), newGroup.getId(), null, - command.arrayOfParameterNamed(GroupingTypesApiConstants.datatables)); + if (datatables != null) { + final JsonArray datatableArray = new GsonBuilder().serializeNulls().create().toJsonTree(datatables).getAsJsonArray(); + entityDatatableChecksWritePlatformService.saveDatatables(StatusEnum.CREATE.getValue(), EntityTables.GROUP.getName(), + newGroup.getId(), null, datatableArray); } - - this.entityDatatableChecksWritePlatformService.runTheCheck(newGroup.getId(), EntityTables.GROUP.getName(), + entityDatatableChecksWritePlatformService.runTheCheck(newGroup.getId(), EntityTables.GROUP.getName(), StatusEnum.CREATE.getValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable(), null); } - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(groupOffice.getId()) // - .withGroupId(newGroup.getId()) // - .withEntityId(newGroup.getId()) // - .setRollbackTransaction(rollbackTransaction) // - .build(); - + return newGroup; } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleGroupDataIntegrityIssues(command, dve.getMostSpecificCause(), dve, groupingType); - return CommandProcessingResult.empty(); + throw handleGroupDataIntegrityIssues(externalIdValue, name, dve.getMostSpecificCause(), dve, groupingType); } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleGroupDataIntegrityIssues(command, throwable, dve, groupingType); - return CommandProcessingResult.empty(); + throw handleGroupDataIntegrityIssues(externalIdValue, name, ExceptionUtils.getRootCause(dve.getCause()), dve, groupingType); } } @@ -250,368 +513,173 @@ private void generateAccountNumber(Group newGroup) { } } - @Transactional - @Override - public CommandProcessingResult createCenter(final JsonCommand command) { - - this.fromApiJsonDeserializer.validateForCreateCenter(command); - - final Long centerId = null; - - CommandProcessingResult commandProcessingResult = createGroupingType(command, GroupTypes.CENTER, centerId); - - businessEventNotifierService.notifyPostBusinessEvent(new CentersCreateBusinessEvent(commandProcessingResult)); - - return commandProcessingResult; - } - - @Transactional - @Override - public CommandProcessingResult createGroup(final Long centerId, final JsonCommand command) { - - if (centerId != null) { - this.fromApiJsonDeserializer.validateForCreateCenterGroup(command); - } else { - this.fromApiJsonDeserializer.validateForCreateGroup(command); - } - - CommandProcessingResult commandProcessingResult = createGroupingType(command, GroupTypes.GROUP, centerId); - - businessEventNotifierService.notifyPostBusinessEvent(new GroupsCreateBusinessEvent(commandProcessingResult)); - - return commandProcessingResult; - } - - @Transactional - @Override - public CommandProcessingResult activateGroupOrCenter(final Long groupId, final JsonCommand command) { - - try { - this.fromApiJsonDeserializer.validateForActivation(command, GroupingTypesApiConstants.GROUP_RESOURCE_NAME); - - final AppUser currentUser = this.context.authenticatedUser(); - - final Group group = this.groupRepository.findOneWithNotFoundDetection(groupId); - - if (group.isGroup()) { - validateGroupRulesBeforeActivation(group); + private Set assembleSetOfClients(final Long groupOfficeId, final List clientIds) { + final Set clientMembers = new HashSet<>(); + if (clientIds != null) { + for (final Long id : clientIds) { + final Client client = clientRepositoryWrapper.findOneWithNotFoundDetection(id); + if (!client.isOfficeIdentifiedBy(groupOfficeId)) { + throw new InvalidOfficeException("client", "attach.to.group", + "Client with identifier " + id + " must have the same office as group.", id.toString(), groupOfficeId); + } + clientMembers.add(client); } - - final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate"); - - validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(group.getOffice(), group.getGroupLevel(), activationDate); - - group.activate(currentUser, activationDate); - - this.groupRepository.saveAndFlush(group); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(group.officeId()) // - .withGroupId(groupId) // - .withEntityId(groupId) // - .build(); - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleGroupDataIntegrityIssues(command, dve.getMostSpecificCause(), dve, GroupTypes.GROUP); - return CommandProcessingResult.empty(); - } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleGroupDataIntegrityIssues(command, throwable, dve, GroupTypes.GROUP); - return CommandProcessingResult.empty(); - } - } - - private void validateGroupRulesBeforeActivation(final Group group) { - Integer minClients = configurationDomainService.retrieveMinAllowedClientsInGroup(); - Integer maxClients = configurationDomainService.retrieveMaxAllowedClientsInGroup(); - boolean isGroupClientCountValid = group.isGroupsClientCountWithinMinMaxRange(minClients, maxClients); - if (!isGroupClientCountValid) { - throw new GroupMemberCountNotInPermissibleRangeException(group.getId(), minClients, maxClients); } - entityDatatableChecksWritePlatformService.runTheCheck(group.getId(), EntityTables.GROUP.getName(), StatusEnum.ACTIVATE.getValue(), - EntityTables.GROUP.getForeignKeyColumnNameOnDatatable(), null); + return clientMembers; } - public void validateGroupRulesBeforeClientAssociation(final Group group) { - Integer minClients = configurationDomainService.retrieveMinAllowedClientsInGroup(); - Integer maxClients = configurationDomainService.retrieveMaxAllowedClientsInGroup(); - boolean isGroupClientCountValid = group.isGroupsClientCountWithinMaxRange(maxClients); - if (!isGroupClientCountValid) { - throw new GroupMemberCountNotInPermissibleRangeException(group.getId(), minClients, maxClients); + private Set assembleSetOfChildGroups(final Long officeId, final List groupIds) { + final Set childGroups = new HashSet<>(); + if (groupIds != null) { + for (final Long id : groupIds) { + final Group group = groupRepository.findOneWithNotFoundDetection(id); + if (!group.isOfficeIdentifiedBy(officeId)) { + throw new InvalidOfficeException("group", "attach.to.parent.group", + "Group and child groups must have the same office."); + } + childGroups.add(group); + } } + return childGroups; } - @Transactional - @Override - public CommandProcessingResult updateCenter(final Long centerId, final JsonCommand command) { - - this.fromApiJsonDeserializer.validateForUpdateCenter(command, centerId); - - return updateGroupingType(centerId, command, GroupTypes.CENTER); - } - - @Transactional - @Override - public CommandProcessingResult updateGroup(final Long groupId, final JsonCommand command) { - - this.fromApiJsonDeserializer.validateForUpdateGroup(command, groupId); - - return updateGroupingType(groupId, command, GroupTypes.GROUP); - } - - private CommandProcessingResult updateGroupingType(final Long groupId, final JsonCommand command, final GroupTypes groupingType) { - + private Updated updateGroupingType(final Long groupId, final String name, final String externalId, final Long officeId, + final Long staffId, final Long centerId, final String activationDateValue, final String submittedOnDateValue, + final String dateFormat, final String locale, final GroupTypes groupingType) { try { - this.context.authenticatedUser(); - final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId); - final Long officeId = groupForUpdate.officeId(); + context.authenticatedUser(); + final Group groupForUpdate = groupRepository.findOneWithNotFoundDetection(groupId); final Office groupOffice = groupForUpdate.getOffice(); final String groupHierarchy = groupOffice.getHierarchy(); + context.validateAccessRights(groupHierarchy); - this.context.validateAccessRights(groupHierarchy); - - final LocalDate activationDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.activationDateParamName); - + final LocalDate activationDate = dateMapper.toLocalDate(activationDateValue, GroupingTypesApiConstants.activationDateParamName, + dateFormat, locale); + final LocalDate submittedOnDate = dateMapper.toLocalDate(submittedOnDateValue, + GroupingTypesApiConstants.submittedOnDateParamName, dateFormat, locale); + validateActivationDateNotBeforeSubmittedOnDate(groupingType, activationDate, submittedOnDate); validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(groupOffice, groupForUpdate.getGroupLevel(), activationDate); - final Map actualChanges = groupForUpdate.update(command); - - if (actualChanges.containsKey(GroupingTypesApiConstants.staffIdParamName)) { - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.staffIdParamName); - - Staff newStaff = null; - if (newValue != null) { - newStaff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(newValue, groupHierarchy); - } - groupForUpdate.updateStaff(newStaff); + final Map actualChanges = new LinkedHashMap<>(9); + if (externalId != null && !externalId.equals(groupForUpdate.getExternalId())) { + actualChanges.put(GroupingTypesApiConstants.externalIdParamName, externalId); + groupForUpdate.setExternalId(StringUtils.defaultIfEmpty(externalId, null)); + } + if (officeId != null && !officeId.equals(groupForUpdate.officeId())) { + actualChanges.put(GroupingTypesApiConstants.officeIdParamName, officeId); // recorded, not applied + } + final Long currentStaffId = groupForUpdate.getStaff() == null ? null : groupForUpdate.getStaff().getId(); + if (staffId != null && !staffId.equals(currentStaffId)) { + actualChanges.put(GroupingTypesApiConstants.staffIdParamName, staffId); + groupForUpdate.updateStaff(staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, groupHierarchy)); + } + if (name != null && !name.equals(groupForUpdate.getName())) { + actualChanges.put(GroupingTypesApiConstants.nameParamName, name); + groupForUpdate.setName(StringUtils.defaultIfEmpty(name, null)); + } + if (activationDate != null && !activationDate.equals(groupForUpdate.getActivationDate())) { + actualChanges.put(GroupingTypesApiConstants.activationDateParamName, activationDateValue); + actualChanges.put(GroupingTypesApiConstants.dateFormatParamName, dateFormat); + actualChanges.put(GroupingTypesApiConstants.localeParamName, locale); + groupForUpdate.setActivationDate(activationDate); + } + if (submittedOnDate != null && !submittedOnDate.equals(groupForUpdate.getSubmittedOnDate())) { + actualChanges.put(GroupingTypesApiConstants.submittedOnDateParamName, submittedOnDateValue); + actualChanges.put(GroupingTypesApiConstants.dateFormatParamName, dateFormat); + actualChanges.put(GroupingTypesApiConstants.localeParamName, locale); + groupForUpdate.setSubmittedOnDate(submittedOnDate); } - final GroupLevel groupLevel = this.groupLevelRepository.findById(groupForUpdate.getGroupLevel().getId()) + final GroupLevel groupLevel = groupLevelRepository.findById(groupForUpdate.getGroupLevel().getId()) .orElseThrow(() -> new GroupLevelNotFoundException(groupForUpdate.getGroupLevel().getId())); /* * Ignoring parentId param, if group for update is super parent. TODO Need to check: Ignoring is correct or * need throw unsupported param */ - if (!groupLevel.isSuperParent()) { - - Long parentId = null; - final Group presentParentGroup = groupForUpdate.getParent(); - - if (presentParentGroup != null) { - parentId = presentParentGroup.getId(); - } - - if (command.isChangeInLongParameterNamed(GroupingTypesApiConstants.centerIdParamName, parentId)) { - - final Long newValue = command.longValueOfParameterNamed(GroupingTypesApiConstants.centerIdParamName); - actualChanges.put(GroupingTypesApiConstants.centerIdParamName, newValue); - Group newParentGroup = null; - if (newValue != null) { - newParentGroup = this.groupRepository.findOneWithNotFoundDetection(newValue); - - if (!newParentGroup.isOfficeIdentifiedBy(officeId)) { - final String errorMessage = "Group and parent group must have the same office"; - throw new InvalidOfficeException("group", "attach.to.parent.group", errorMessage); - } - /* - * If Group is not super parent then validate group level's parent level is same as group - * parent's level this check makes sure new group is added at immediate next level in hierarchy - */ - - if (!groupForUpdate.getGroupLevel().isIdentifiedByParentId(newParentGroup.getGroupLevel().getId())) { - final String errorMessage = "Parent group's level is not equal to child level's parent level "; - throw new InvalidGroupLevelException("add", "invalid.level", errorMessage); - } + if (!groupLevel.isSuperParent() && centerId != null) { + final Long presentParentId = groupForUpdate.getParent() == null ? null : groupForUpdate.getParent().getId(); + if (!centerId.equals(presentParentId)) { + actualChanges.put(GroupingTypesApiConstants.centerIdParamName, centerId); + final Group newParentGroup = groupRepository.findOneWithNotFoundDetection(centerId); + if (!newParentGroup.isOfficeIdentifiedBy(groupForUpdate.officeId())) { + throw new InvalidOfficeException("group", "attach.to.parent.group", + "Group and parent group must have the same office"); + } + if (!groupForUpdate.getGroupLevel().isIdentifiedByParentId(newParentGroup.getGroupLevel().getId())) { + throw new InvalidGroupLevelException("add", "invalid.level", + "Parent group's level is not equal to child level's parent level "); } - groupForUpdate.setParent(newParentGroup); - - // Parent has changed, re-generate 'Hierarchy' as parent is - // changed groupForUpdate.generateHierarchy(); - } } - /* - * final Set clientMembers = assembleSetOfClients(officeId, command); List changes = - * groupForUpdate.updateClientMembersIfDifferent(clientMembers); if (!changes.isEmpty()) { - * actualChanges.put(GroupingTypesApiConstants .clientMembersParamName, changes); } - */ - - this.groupRepository.saveAndFlush(groupForUpdate); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(groupForUpdate.officeId()) // - .withGroupId(groupForUpdate.getId()) // - .withEntityId(groupForUpdate.getId()) // - .with(actualChanges) // - .build(); - + groupRepository.saveAndFlush(groupForUpdate); + return new Updated(groupForUpdate, actualChanges); } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleGroupDataIntegrityIssues(command, dve.getMostSpecificCause(), dve, groupingType); - return CommandProcessingResult.empty(); + throw handleGroupDataIntegrityIssues(externalId, name, dve.getMostSpecificCause(), dve, groupingType); } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleGroupDataIntegrityIssues(command, throwable, dve, groupingType); - return CommandProcessingResult.empty(); - } - } - - @Transactional - @Override - public CommandProcessingResult unassignGroupOrCenterStaff(final Long grouptId, final JsonCommand command) { - - this.context.authenticatedUser(); - - final Map actualChanges = new LinkedHashMap<>(9); - - this.fromApiJsonDeserializer.validateForUnassignStaff(command.json()); - final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(grouptId); - final Staff presentStaff = groupForUpdate.getStaff(); - Long presentStaffId = null; - if (presentStaff == null) { - throw new GroupHasNoStaffException(grouptId); - } - presentStaffId = presentStaff.getId(); - final String staffIdParamName = "staffId"; - if (!command.isChangeInLongParameterNamed(staffIdParamName, presentStaffId)) { - groupForUpdate.unassignStaff(); + throw handleGroupDataIntegrityIssues(externalId, name, ExceptionUtils.getRootCause(dve.getCause()), dve, groupingType); } - this.groupRepository.saveAndFlush(groupForUpdate); - - actualChanges.put(staffIdParamName, null); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(groupForUpdate.getId()) // - .withGroupId(groupForUpdate.officeId()) // - .withEntityId(groupForUpdate.getId()) // - .with(actualChanges) // - .build(); - } - @Override - public CommandProcessingResult assignGroupOrCenterStaff(final Long groupId, final JsonCommand command) { - - this.context.authenticatedUser(); - - final Map actualChanges = new LinkedHashMap<>(5); - - this.fromApiJsonDeserializer.validateForAssignStaff(command.json()); - - final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId); - - Staff staff = null; - final Long staffId = command.longValueOfParameterNamed(GroupingTypesApiConstants.staffIdParamName); - final boolean inheritStaffForClientAccounts = command - .booleanPrimitiveValueOfParameterNamed(GroupingTypesApiConstants.inheritStaffForClientAccounts); - staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, groupForUpdate.getOffice().getHierarchy()); - groupForUpdate.updateStaff(staff); - - if (inheritStaffForClientAccounts) { - LocalDate loanOfficerReassignmentDate = DateUtils.getBusinessLocalDate(); - /* - * update loan officer for client and update loan officer for clients loans and savings - */ - Set clients = groupForUpdate.getClientMembers(); - if (clients != null) { - for (Client client : clients) { - client.updateStaff(staff); - if (this.loanRepositoryWrapper.doNonClosedLoanAccountsExistForClient(client.getId())) { - for (final Loan loan : this.loanRepositoryWrapper.findLoanByClientId(client.getId())) { - if (loan.isDisbursed() && !loan.isClosed()) { - loanOfficerService.reassignLoanOfficer(loan, staff, loanOfficerReassignmentDate); - } - } - } - if (this.savingsAccountRepositoryWrapper.doNonClosedSavingAccountsExistForClient(client.getId())) { - for (final SavingsAccount savingsAccount : this.savingsAccountRepositoryWrapper - .findSavingAccountByClientId(client.getId())) { - if (!savingsAccount.isClosed()) { - savingsAccount.reassignSavingsOfficer(staff, loanOfficerReassignmentDate); - } - } - } - } - } - } - this.groupRepository.saveAndFlush(groupForUpdate); - - actualChanges.put(GroupingTypesApiConstants.staffIdParamName, staffId); - - return new CommandProcessingResultBuilder() // - .withOfficeId(groupForUpdate.officeId()) // - .withEntityId(groupForUpdate.getId()) // - .withGroupId(groupId) // - .with(actualChanges) // - .build(); - } - - @Transactional - @Override - public CommandProcessingResult deleteGroup(final Long groupId) { + private Group deleteGroupingType(final Long groupId) { try { - - final Group groupForDelete = this.groupRepository.findOneWithNotFoundDetection(groupId); - + final Group groupForDelete = groupRepository.findOneWithNotFoundDetection(groupId); if (groupForDelete.isNotPending()) { throw new GroupMustBePendingToBeDeletedException(groupId); } - - final List relatedNotes = this.noteRepository.findByGroup(groupForDelete); - this.noteRepository.deleteAllInBatch(relatedNotes); - - this.groupRepository.delete(groupForDelete); - this.groupRepository.flush(); - return new CommandProcessingResultBuilder() // - .withOfficeId(groupForDelete.getId()) // - .withGroupId(groupForDelete.officeId()) // - .withEntityId(groupForDelete.getId()) // - .build(); + final List relatedNotes = noteRepository.findByGroup(groupForDelete); + noteRepository.deleteAllInBatch(relatedNotes); + groupRepository.delete(groupForDelete); + groupRepository.flush(); + return groupForDelete; } catch (final JpaSystemException | DataIntegrityViolationException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - log.error("Error occurred.", throwable); + log.error("Error occurred.", ExceptionUtils.getRootCause(dve.getCause())); throw ErrorHandler.getMappable(dve, "error.msg.group.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); } } - @Override - public CommandProcessingResult closeGroup(final Long groupId, final JsonCommand command) { - this.fromApiJsonDeserializer.validateForGroupClose(command); - final Group group = this.groupRepository.findOneWithNotFoundDetection(groupId); - final LocalDate closureDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.closureDateParamName); - final Long closureReasonId = command.longValueOfParameterNamed(GroupingTypesApiConstants.closureReasonIdParamName); - - final AppUser currentUser = this.context.authenticatedUser(); - - final CodeValue closureReason = this.codeValueRepository - .findOneByCodeNameAndIdWithNotFoundDetection(GroupingTypesApiConstants.GROUP_CLOSURE_REASON, closureReasonId); - - if (group.hasActiveClients()) { - final String errorMessage = group.getGroupLevel().getLevelName() - + " cannot be closed because of active clients associated with it."; - throw new InvalidGroupStateTransitionException(group.getGroupLevel().getLevelName(), "close", "active.clients.exist", - errorMessage); + private RuntimeException handleGroupDataIntegrityIssues(final String externalId, final String name, final Throwable realCause, + final Exception dve, final GroupTypes groupLevel) { + final String levelName = switch (groupLevel) { + case CENTER -> "Center"; + case GROUP -> "Group"; + default -> "Invalid"; + }; + final String message = realCause == null || realCause.getMessage() == null ? "" : realCause.getMessage(); + if (message.contains("'external_id'")) { + return new PlatformDataIntegrityException("error.msg." + levelName.toLowerCase() + ".duplicate.externalId", + levelName + " with externalId `" + externalId + "` already exists.", GroupingTypesApiConstants.externalIdParamName, + externalId); + } else if (message.contains("'name'")) { + return new PlatformDataIntegrityException("error.msg." + levelName.toLowerCase() + ".duplicate.name", + levelName + " with name `" + name + "` already exists.", GroupingTypesApiConstants.nameParamName, name); } + log.error("Error occurred.", dve); + return ErrorHandler.getMappable(dve, "error.msg.group.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); + } - validateLoansAndSavingsForGroupOrCenterClose(group, closureDate); - - entityDatatableChecksWritePlatformService.runTheCheck(groupId, EntityTables.GROUP.getName(), StatusEnum.CLOSE.getValue(), + private void validateGroupRulesBeforeActivation(final Group group) { + Integer minClients = configurationDomainService.retrieveMinAllowedClientsInGroup(); + Integer maxClients = configurationDomainService.retrieveMaxAllowedClientsInGroup(); + boolean isGroupClientCountValid = group.isGroupsClientCountWithinMinMaxRange(minClients, maxClients); + if (!isGroupClientCountValid) { + throw new GroupMemberCountNotInPermissibleRangeException(group.getId(), minClients, maxClients); + } + entityDatatableChecksWritePlatformService.runTheCheck(group.getId(), EntityTables.GROUP.getName(), StatusEnum.ACTIVATE.getValue(), EntityTables.GROUP.getForeignKeyColumnNameOnDatatable(), null); + } - group.close(currentUser, closureReason, closureDate); - - this.groupRepository.saveAndFlush(group); - - return new CommandProcessingResultBuilder() // - .withGroupId(groupId) // - .withEntityId(groupId) // - .build(); + private void validateGroupRulesBeforeClientAssociation(final Group group) { + Integer minClients = configurationDomainService.retrieveMinAllowedClientsInGroup(); + Integer maxClients = configurationDomainService.retrieveMaxAllowedClientsInGroup(); + boolean isGroupClientCountValid = group.isGroupsClientCountWithinMaxRange(maxClients); + if (!isGroupClientCountValid) { + throw new GroupMemberCountNotInPermissibleRangeException(group.getId(), minClients, maxClients); + } } private void validateLoansAndSavingsForGroupOrCenterClose(final Group groupOrCenter, final LocalDate closureDate) { @@ -655,231 +723,6 @@ private void validateLoansAndSavingsForGroupOrCenterClose(final Group groupOrCen } } - @Override - public CommandProcessingResult closeCenter(final Long centerId, final JsonCommand command) { - this.fromApiJsonDeserializer.validateForCenterClose(command); - final Group center = this.groupRepository.findOneWithNotFoundDetection(centerId); - final LocalDate closureDate = command.localDateValueOfParameterNamed(GroupingTypesApiConstants.closureDateParamName); - final Long closureReasonId = command.longValueOfParameterNamed(GroupingTypesApiConstants.closureReasonIdParamName); - - final CodeValue closureReason = this.codeValueRepository - .findOneByCodeNameAndIdWithNotFoundDetection(GroupingTypesApiConstants.CENTER_CLOSURE_REASON, closureReasonId); - - final AppUser currentUser = this.context.authenticatedUser(); - - if (center.hasActiveGroups()) { - final String errorMessage = center.getGroupLevel().getLevelName() - + " cannot be closed because of active groups associated with it."; - throw new InvalidGroupStateTransitionException(center.getGroupLevel().getLevelName(), "close", "active.groups.exist", - errorMessage); - } - - validateLoansAndSavingsForGroupOrCenterClose(center, closureDate); - - entityDatatableChecksWritePlatformService.runTheCheck(centerId, EntityTables.GROUP.getName(), StatusEnum.ACTIVATE.getValue(), - EntityTables.GROUP.getForeignKeyColumnNameOnDatatable(), null); - - center.close(currentUser, closureReason, closureDate); - - this.groupRepository.saveAndFlush(center); - - return new CommandProcessingResultBuilder() // - .withEntityId(centerId) // - .build(); - } - - private Set assembleSetOfClients(final Long groupOfficeId, final JsonCommand command) { - - final Set clientMembers = new HashSet<>(); - final String[] clientMembersArray = command.arrayValueOfParameterNamed(GroupingTypesApiConstants.clientMembersParamName); - - if (!ObjectUtils.isEmpty(clientMembersArray)) { - for (final String clientId : clientMembersArray) { - final Long id = Long.valueOf(clientId); - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(id); - if (!client.isOfficeIdentifiedBy(groupOfficeId)) { - final String errorMessage = "Client with identifier " + clientId + " must have the same office as group."; - throw new InvalidOfficeException("client", "attach.to.group", errorMessage, clientId, groupOfficeId); - } - clientMembers.add(client); - } - } - - return clientMembers; - } - - private Set assembleSetOfChildGroups(final Long officeId, final JsonCommand command) { - - final Set childGroups = new HashSet<>(); - final String[] childGroupsArray = command.arrayValueOfParameterNamed(GroupingTypesApiConstants.groupMembersParamName); - - if (!ObjectUtils.isEmpty(childGroupsArray)) { - for (final String groupId : childGroupsArray) { - final Long id = Long.valueOf(groupId); - final Group group = this.groupRepository.findOneWithNotFoundDetection(id); - - if (!group.isOfficeIdentifiedBy(officeId)) { - final String errorMessage = "Group and child groups must have the same office."; - throw new InvalidOfficeException("group", "attach.to.parent.group", errorMessage); - } - - childGroups.add(group); - } - } - - return childGroups; - } - - /* - * Guaranteed to throw an exception no matter what the data integrity issue is. - */ - private void handleGroupDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve, - final GroupTypes groupLevel) { - String levelName = "Invalid"; - switch (groupLevel) { - case CENTER: - levelName = "Center"; - break; - case GROUP: - levelName = "Group"; - break; - case INVALID: - break; - } - - String errorMessageForUser = null; - String errorMessageForMachine = null; - if (realCause.getMessage().contains("'external_id'")) { - final String externalId = command.stringValueOfParameterNamed(GroupingTypesApiConstants.externalIdParamName); - errorMessageForUser = levelName + " with externalId `" + externalId + "` already exists."; - errorMessageForMachine = "error.msg." + levelName.toLowerCase() + ".duplicate.externalId"; - throw new PlatformDataIntegrityException(errorMessageForMachine, errorMessageForUser, - GroupingTypesApiConstants.externalIdParamName, externalId); - } else if (realCause.getMessage().contains("'name'")) { - final String name = command.stringValueOfParameterNamed(GroupingTypesApiConstants.nameParamName); - errorMessageForUser = levelName + " with name `" + name + "` already exists."; - errorMessageForMachine = "error.msg." + levelName.toLowerCase() + ".duplicate.name"; - throw new PlatformDataIntegrityException(errorMessageForMachine, errorMessageForUser, GroupingTypesApiConstants.nameParamName, - name); - } - - log.error("Error occurred.", dve); - throw ErrorHandler.getMappable(dve, "error.msg.group.unknown.data.integrity.issue", "Unknown data integrity issue with resource."); - } - - @Override - public CommandProcessingResult associateClientsToGroup(final Long groupId, final JsonCommand command) { - - this.fromApiJsonDeserializer.validateForAssociateClients(command.json()); - - final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId); - final Set clientMembers = assembleSetOfClients(groupForUpdate.officeId(), command); - final Map actualChanges = new HashMap<>(); - - final List changes = groupForUpdate.associateClients(clientMembers); - - if (groupForUpdate.isGroup()) { - validateGroupRulesBeforeClientAssociation(groupForUpdate); - } - if (!changes.isEmpty()) { - actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); - } - - this.groupRepository.saveAndFlush(groupForUpdate); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(groupForUpdate.officeId()) // - .withGroupId(groupForUpdate.getId()) // - .withEntityId(groupForUpdate.getId()) // - .with(actualChanges) // - .build(); - } - - @Transactional - @Override - public CommandProcessingResult disassociateClientsFromGroup(final Long groupId, final JsonCommand command) { - this.fromApiJsonDeserializer.validateForDisassociateClients(command.json()); - - final Group groupForUpdate = this.groupRepository.findOneWithNotFoundDetection(groupId); - final Set clientMembers = assembleSetOfClients(groupForUpdate.officeId(), command); - - // check if any client has got group loans - checkForActiveJLGLoans(groupForUpdate.getId(), clientMembers); - validateForJLGSavings(groupForUpdate.getId(), clientMembers); - final Map actualChanges = new HashMap<>(); - - final List changes = groupForUpdate.disassociateClients(clientMembers); - if (!changes.isEmpty()) { - actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); - } - - this.groupRepository.saveAndFlush(groupForUpdate); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(groupForUpdate.officeId()) // - .withGroupId(groupForUpdate.getId()) // - .withEntityId(groupForUpdate.getId()) // - .with(actualChanges) // - .build(); - } - - @Transactional - @Override - public CommandProcessingResult associateGroupsToCenter(final Long centerId, final JsonCommand command) { - - this.fromApiJsonDeserializer.validateForAssociateGroups(command.json()); - final Group centerForUpdate = this.groupRepository.findOneWithNotFoundDetection(centerId); - final Set groupMembers = assembleSetOfChildGroups(centerForUpdate.officeId(), command); - checkGroupMembersMeetingSyncWithCenterMeeting(centerId, groupMembers); - - final Map actualChanges = new HashMap<>(); - - final List changes = centerForUpdate.associateGroups(groupMembers); - if (!changes.isEmpty()) { - actualChanges.put(GroupingTypesApiConstants.groupMembersParamName, changes); - } - - this.groupRepository.saveAndFlush(centerForUpdate); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(centerForUpdate.officeId()) // - .withGroupId(centerForUpdate.getId()) // - .withEntityId(centerForUpdate.getId()) // - .with(actualChanges) // - .build(); - } - - @Transactional - @Override - public CommandProcessingResult disassociateGroupsToCenter(final Long centerId, final JsonCommand command) { - this.fromApiJsonDeserializer.validateForDisassociateGroups(command.json()); - - final Group centerForUpdate = this.groupRepository.findOneWithNotFoundDetection(centerId); - final Set groupMembers = assembleSetOfChildGroups(centerForUpdate.officeId(), command); - - final Map actualChanges = new HashMap<>(); - - final List changes = centerForUpdate.disassociateGroups(groupMembers); - if (!changes.isEmpty()) { - actualChanges.put(GroupingTypesApiConstants.clientMembersParamName, changes); - } - - this.groupRepository.saveAndFlush(centerForUpdate); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withOfficeId(centerForUpdate.officeId()) // - .withGroupId(centerForUpdate.getId()) // - .withEntityId(centerForUpdate.getId()) // - .with(actualChanges) // - .build(); - - } - - @Transactional private void checkForActiveJLGLoans(final Long groupId, final Set clientMembers) { for (final Client client : clientMembers) { final Collection loans = this.loanRepositoryWrapper.findActiveLoansByLoanIdAndGroupId(client.getId(), groupId); @@ -891,7 +734,6 @@ private void checkForActiveJLGLoans(final Long groupId, final Set client } } - @Transactional private void validateForJLGSavings(final Long groupId, final Set clientMembers) { for (final Client client : clientMembers) { final Collection savings = this.savingsAccountRepositoryWrapper.findByClientIdAndGroupId(client.getId(), @@ -905,7 +747,20 @@ private void validateForJLGSavings(final Long groupId, final Set clientM } } - public void validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(final Office groupOffice, final GroupLevel groupLevel, + // legacy update validation: when both dates are supplied, activation may not precede submission + private static void validateActivationDateNotBeforeSubmittedOnDate(final GroupTypes groupingType, final LocalDate activationDate, + final LocalDate submittedOnDate) { + final List errors = new ArrayList<>(); + new DataValidatorBuilder(errors) + .resource(groupingType == GroupTypes.CENTER ? GroupingTypesApiConstants.CENTER_RESOURCE_NAME + : GroupingTypesApiConstants.GROUP_RESOURCE_NAME) + .parameter(GroupingTypesApiConstants.activationDateParamName).value(activationDate).validateDateAfter(submittedOnDate); + if (!errors.isEmpty()) { + throw new PlatformApiDataValidationException(errors); + } + } + + private void validateOfficeOpeningDateisAfterGroupOrCenterOpeningDate(final Office groupOffice, final GroupLevel groupLevel, final LocalDate activationDate) { if (activationDate != null && DateUtils.isAfter(groupOffice.getOpeningLocalDate(), activationDate)) { final String levelName = groupLevel.getLevelName(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/starter/GroupConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/starter/GroupConfiguration.java index 33f77d463d3..0562ed2e026 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/starter/GroupConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/starter/GroupConfiguration.java @@ -19,7 +19,6 @@ package org.apache.fineract.portfolio.group.starter; -import org.apache.fineract.commands.service.CommandProcessingService; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; @@ -44,8 +43,7 @@ import org.apache.fineract.portfolio.group.domain.GroupLevelRepository; import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; import org.apache.fineract.portfolio.group.domain.GroupRoleRepositoryWrapper; -import org.apache.fineract.portfolio.group.serialization.GroupRolesDataValidator; -import org.apache.fineract.portfolio.group.serialization.GroupingTypesDataValidator; +import org.apache.fineract.portfolio.group.mapping.GroupDateMapper; import org.apache.fineract.portfolio.group.service.CenterReadPlatformService; import org.apache.fineract.portfolio.group.service.CenterReadPlatformServiceImpl; import org.apache.fineract.portfolio.group.service.GroupLevelReadPlatformService; @@ -54,10 +52,10 @@ import org.apache.fineract.portfolio.group.service.GroupReadPlatformServiceImpl; import org.apache.fineract.portfolio.group.service.GroupRolesReadPlatformService; import org.apache.fineract.portfolio.group.service.GroupRolesReadPlatformServiceImpl; -import org.apache.fineract.portfolio.group.service.GroupRolesWritePlatformService; -import org.apache.fineract.portfolio.group.service.GroupRolesWritePlatformServiceJpaRepositoryImpl; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformService; -import org.apache.fineract.portfolio.group.service.GroupingTypesWritePlatformServiceJpaRepositoryImpl; +import org.apache.fineract.portfolio.group.service.GroupRolesWriteService; +import org.apache.fineract.portfolio.group.service.GroupRolesWriteServiceImpl; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteServiceImpl; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService; import org.apache.fineract.portfolio.note.domain.NoteRepository; @@ -82,30 +80,6 @@ public CenterReadPlatformService centerReadPlatformService(JdbcTemplate jdbcTemp sqlGenerator, paginationParametersDataValidator); } - @Bean - @ConditionalOnMissingBean(GroupingTypesWritePlatformService.class) - public GroupingTypesWritePlatformService groupingTypesWritePlatformService(PlatformSecurityContext context, - GroupRepositoryWrapper groupRepository, ClientRepositoryWrapper clientRepositoryWrapper, - OfficeRepositoryWrapper officeRepositoryWrapper, StaffRepositoryWrapper staffRepository, NoteRepository noteRepository, - GroupLevelRepository groupLevelRepository, GroupingTypesDataValidator fromApiJsonDeserializer, - LoanRepositoryWrapper loanRepositoryWrapper, CodeValueRepositoryWrapper codeValueRepository, - CommandProcessingService commandProcessingService, CalendarInstanceRepository calendarInstanceRepository, - ConfigurationDomainService configurationDomainService, SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper, - AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, AccountNumberGenerator accountNumberGenerator, - EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, - BusinessEventNotifierService businessEventNotifierService, LoanOfficerService loanOfficerService, - ExternalIdFactory externalIdFactory - - ) { - return new GroupingTypesWritePlatformServiceJpaRepositoryImpl(context, groupRepository, clientRepositoryWrapper, - officeRepositoryWrapper, staffRepository, noteRepository, groupLevelRepository, fromApiJsonDeserializer, - loanRepositoryWrapper, codeValueRepository, commandProcessingService, calendarInstanceRepository, - configurationDomainService, savingsAccountRepositoryWrapper, accountNumberFormatRepository, accountNumberGenerator, - entityDatatableChecksWritePlatformService, businessEventNotifierService, loanOfficerService, externalIdFactory - - ); - } - @Bean @ConditionalOnMissingBean(GroupLevelReadPlatformService.class) public GroupLevelReadPlatformService groupLevelReadPlatformService(PlatformSecurityContext context, JdbcTemplate jdbcTemplate) { @@ -132,12 +106,29 @@ public GroupRolesReadPlatformService groupRolesReadPlatformService(JdbcTemplate } @Bean - @ConditionalOnMissingBean(GroupRolesWritePlatformService.class) - public GroupRolesWritePlatformService groupRolesWritePlatformService(PlatformSecurityContext context, - GroupRepositoryWrapper groupRepository, GroupRolesDataValidator fromApiJsonDeserializer, + @ConditionalOnMissingBean(GroupingTypesWriteService.class) + public GroupingTypesWriteService groupingTypesWriteService(PlatformSecurityContext context, GroupRepositoryWrapper groupRepository, + ClientRepositoryWrapper clientRepositoryWrapper, OfficeRepositoryWrapper officeRepositoryWrapper, + StaffRepositoryWrapper staffRepository, NoteRepository noteRepository, GroupLevelRepository groupLevelRepository, + LoanRepositoryWrapper loanRepositoryWrapper, CodeValueRepositoryWrapper codeValueRepository, + CalendarInstanceRepository calendarInstanceRepository, ConfigurationDomainService configurationDomainService, + SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper, + AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, AccountNumberGenerator accountNumberGenerator, + EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService, + BusinessEventNotifierService businessEventNotifierService, LoanOfficerService loanOfficerService, + ExternalIdFactory externalIdFactory, GroupDateMapper groupDateMapper) { + return new GroupingTypesWriteServiceImpl(context, groupRepository, clientRepositoryWrapper, officeRepositoryWrapper, + staffRepository, noteRepository, groupLevelRepository, loanRepositoryWrapper, codeValueRepository, + calendarInstanceRepository, configurationDomainService, savingsAccountRepositoryWrapper, accountNumberFormatRepository, + accountNumberGenerator, entityDatatableChecksWritePlatformService, businessEventNotifierService, loanOfficerService, + externalIdFactory, groupDateMapper); + } + + @Bean + @ConditionalOnMissingBean(GroupRolesWriteService.class) + public GroupRolesWriteService groupRolesWriteService(PlatformSecurityContext context, GroupRepositoryWrapper groupRepository, CodeValueRepositoryWrapper codeValueRepository, ClientRepositoryWrapper clientRepository, GroupRoleRepositoryWrapper groupRoleRepository) { - return new GroupRolesWritePlatformServiceJpaRepositoryImpl(context, groupRepository, fromApiJsonDeserializer, codeValueRepository, - clientRepository, groupRoleRepository); + return new GroupRolesWriteServiceImpl(context, groupRepository, codeValueRepository, clientRepository, groupRoleRepository); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/ActivationDateRequiredWhenActive.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/ActivationDateRequiredWhenActive.java new file mode 100644 index 00000000000..36acfdcb49a --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/ActivationDateRequiredWhenActive.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Constraint(validatedBy = ActivationDateRequiredWhenActiveValidator.class) +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ActivationDateRequiredWhenActive { + + String message() default "{org.apache.fineract.portfolio.group.activation-date.not-null}"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/ActivationDateRequiredWhenActiveValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/ActivationDateRequiredWhenActiveValidator.java new file mode 100644 index 00000000000..b4b7ccc9dfe --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/ActivationDateRequiredWhenActiveValidator.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +public class ActivationDateRequiredWhenActiveValidator implements ConstraintValidator { + + @Override + public boolean isValid(HasActivation value, ConstraintValidatorContext context) { + if (value == null || !Boolean.TRUE.equals(value.getActive()) || value.getActivationDate() != null) { + return true; + } + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addPropertyNode("activationDate") + .addConstraintViolation(); + return false; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/HasActivation.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/HasActivation.java new file mode 100644 index 00000000000..c9ba0089623 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/HasActivation.java @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.validation; + +public interface HasActivation { + + Boolean getActive(); + + String getActivationDate(); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/OfficeIdRequiredUnlessCenter.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/OfficeIdRequiredUnlessCenter.java new file mode 100644 index 00000000000..70c4c657586 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/OfficeIdRequiredUnlessCenter.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Documented +@Constraint(validatedBy = OfficeIdRequiredUnlessCenterValidator.class) +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface OfficeIdRequiredUnlessCenter { + + String message() default "{org.apache.fineract.portfolio.group.office-id.not-null}"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/OfficeIdRequiredUnlessCenterValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/OfficeIdRequiredUnlessCenterValidator.java new file mode 100644 index 00000000000..6b45e6bed80 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/group/validation/OfficeIdRequiredUnlessCenterValidator.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; + +public class OfficeIdRequiredUnlessCenterValidator implements ConstraintValidator { + + @Override + public boolean isValid(GroupCreateRequest value, ConstraintValidatorContext context) { + if (value == null || value.getCenterId() != null || value.getOfficeId() != null) { + return true; + } + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addPropertyNode("officeId") + .addConstraintViolation(); + return false; + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformService.java index 9d418e5adf6..86ec7254ae7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformService.java @@ -20,6 +20,8 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; public interface TransferWritePlatformService { @@ -35,4 +37,6 @@ public interface TransferWritePlatformService { CommandProcessingResult proposeAndAcceptClientTransfer(Long clientId, JsonCommand jsonCommand); + GroupCommandResponse transferClientsBetweenGroups(GroupTransferClientsRequest request); + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java index f322fab2495..3339f3664f0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/transfer/service/TransferWritePlatformServiceJpaRepositoryImpl.java @@ -49,6 +49,9 @@ import org.apache.fineract.portfolio.client.domain.ClientTransferDetails; import org.apache.fineract.portfolio.client.domain.ClientTransferDetailsRepositoryWrapper; import org.apache.fineract.portfolio.client.exception.ClientHasBeenClosedException; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupTransferClientItem; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; import org.apache.fineract.portfolio.group.domain.Group; import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException; @@ -519,4 +522,39 @@ private void validateClientAwaitingTransferAcceptanceOnHold(final Client client) * } **/ + @Transactional + @Override + public GroupCommandResponse transferClientsBetweenGroups(final GroupTransferClientsRequest request) { + final Long sourceGroupId = request.getId(); + final Group sourceGroup = groupRepository.findOneWithNotFoundDetection(sourceGroupId); + final Long destinationGroupId = request.getDestinationGroupId(); + final Group destinationGroup = groupRepository.findOneWithNotFoundDetection(destinationGroupId); + final Office sourceOffice = sourceGroup.getOffice(); + Staff staff = null; + if (request.getStaffId() != null) { + staff = staffRepositoryWrapper.findByOfficeHierarchyWithNotFoundDetection(request.getStaffId(), sourceOffice.getHierarchy()); + } + final List clients = new ArrayList<>(); + final List requestedClients = request.getClients(); + if (requestedClients != null) { + for (final GroupTransferClientItem item : requestedClients) { + if (item.getId() != null) { + clients.add(clientRepositoryWrapper.findOneWithNotFoundDetection(item.getId())); + } + } + } + if (sourceGroupId.equals(destinationGroupId)) { + throw new TransferNotSupportedException(TransferNotSupportedReason.SOURCE_AND_DESTINATION_GROUP_CANNOT_BE_SAME, sourceGroupId, + destinationGroupId); + } + if (!sourceOffice.getId().equals(destinationGroup.getOffice().getId())) { + throw new TransferNotSupportedException(TransferNotSupportedReason.BULK_CLIENT_TRANSFER_ACROSS_BRANCHES, sourceGroupId, + destinationGroupId); + } + for (final Client client : clients) { + transferClientBetweenGroups(sourceGroup, client, destinationGroup, request.getInheritDestinationGroupLoanOfficer(), staff); + } + return GroupCommandResponse.builder().groupId(sourceGroupId).resourceId(sourceGroupId).build(); + } + } diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index d314b7a451b..20d42c48630 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -876,6 +876,154 @@ resilience4j.retry.instances.commandLoanCollateralDelete.enable-exponential-back resilience4j.retry.instances.commandLoanCollateralDelete.exponential-backoff-multiplier=${FINERACT_COMMAND_LOAN_COLLATERAL_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} resilience4j.retry.instances.commandLoanCollateralDelete.retryExceptions=${FINERACT_COMMAND_LOAN_COLLATERAL_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} +# group + +resilience4j.retry.instances.commandGroupActivate.max-attempts=${FINERACT_COMMAND_GROUP_ACTIVATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupActivate.wait-duration=${FINERACT_COMMAND_GROUP_ACTIVATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupActivate.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_ACTIVATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupActivate.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_ACTIVATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupActivate.retryExceptions=${FINERACT_COMMAND_GROUP_ACTIVATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupAssignRole.max-attempts=${FINERACT_COMMAND_GROUP_ASSIGN_ROLE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupAssignRole.wait-duration=${FINERACT_COMMAND_GROUP_ASSIGN_ROLE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupAssignRole.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_ASSIGN_ROLE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupAssignRole.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_ASSIGN_ROLE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupAssignRole.retryExceptions=${FINERACT_COMMAND_GROUP_ASSIGN_ROLE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupAssignStaff.max-attempts=${FINERACT_COMMAND_GROUP_ASSIGN_STAFF_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupAssignStaff.wait-duration=${FINERACT_COMMAND_GROUP_ASSIGN_STAFF_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupAssignStaff.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_ASSIGN_STAFF_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupAssignStaff.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_ASSIGN_STAFF_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupAssignStaff.retryExceptions=${FINERACT_COMMAND_GROUP_ASSIGN_STAFF_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupAssociateClients.max-attempts=${FINERACT_COMMAND_GROUP_ASSOCIATE_CLIENTS_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupAssociateClients.wait-duration=${FINERACT_COMMAND_GROUP_ASSOCIATE_CLIENTS_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupAssociateClients.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_ASSOCIATE_CLIENTS_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupAssociateClients.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_ASSOCIATE_CLIENTS_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupAssociateClients.retryExceptions=${FINERACT_COMMAND_GROUP_ASSOCIATE_CLIENTS_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupClose.max-attempts=${FINERACT_COMMAND_GROUP_CLOSE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupClose.wait-duration=${FINERACT_COMMAND_GROUP_CLOSE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupClose.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_CLOSE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupClose.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_CLOSE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupClose.retryExceptions=${FINERACT_COMMAND_GROUP_CLOSE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupCreate.max-attempts=${FINERACT_COMMAND_GROUP_CREATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupCreate.wait-duration=${FINERACT_COMMAND_GROUP_CREATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupCreate.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupCreate.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupCreate.retryExceptions=${FINERACT_COMMAND_GROUP_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupDelete.max-attempts=${FINERACT_COMMAND_GROUP_DELETE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupDelete.wait-duration=${FINERACT_COMMAND_GROUP_DELETE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupDelete.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupDelete.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupDelete.retryExceptions=${FINERACT_COMMAND_GROUP_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupDisassociateClients.max-attempts=${FINERACT_COMMAND_GROUP_DISASSOCIATE_CLIENTS_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupDisassociateClients.wait-duration=${FINERACT_COMMAND_GROUP_DISASSOCIATE_CLIENTS_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupDisassociateClients.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_DISASSOCIATE_CLIENTS_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupDisassociateClients.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_DISASSOCIATE_CLIENTS_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupDisassociateClients.retryExceptions=${FINERACT_COMMAND_GROUP_DISASSOCIATE_CLIENTS_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupSaveCollectionSheet.max-attempts=${FINERACT_COMMAND_GROUP_SAVE_COLLECTION_SHEET_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupSaveCollectionSheet.wait-duration=${FINERACT_COMMAND_GROUP_SAVE_COLLECTION_SHEET_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupSaveCollectionSheet.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_SAVE_COLLECTION_SHEET_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupSaveCollectionSheet.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_SAVE_COLLECTION_SHEET_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupSaveCollectionSheet.retryExceptions=${FINERACT_COMMAND_GROUP_SAVE_COLLECTION_SHEET_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupTransferClients.max-attempts=${FINERACT_COMMAND_GROUP_TRANSFER_CLIENTS_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupTransferClients.wait-duration=${FINERACT_COMMAND_GROUP_TRANSFER_CLIENTS_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupTransferClients.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_TRANSFER_CLIENTS_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupTransferClients.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_TRANSFER_CLIENTS_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupTransferClients.retryExceptions=${FINERACT_COMMAND_GROUP_TRANSFER_CLIENTS_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupUnassignRole.max-attempts=${FINERACT_COMMAND_GROUP_UNASSIGN_ROLE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupUnassignRole.wait-duration=${FINERACT_COMMAND_GROUP_UNASSIGN_ROLE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupUnassignRole.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_UNASSIGN_ROLE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupUnassignRole.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_UNASSIGN_ROLE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupUnassignRole.retryExceptions=${FINERACT_COMMAND_GROUP_UNASSIGN_ROLE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupUnassignStaff.max-attempts=${FINERACT_COMMAND_GROUP_UNASSIGN_STAFF_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupUnassignStaff.wait-duration=${FINERACT_COMMAND_GROUP_UNASSIGN_STAFF_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupUnassignStaff.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_UNASSIGN_STAFF_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupUnassignStaff.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_UNASSIGN_STAFF_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupUnassignStaff.retryExceptions=${FINERACT_COMMAND_GROUP_UNASSIGN_STAFF_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupUpdate.max-attempts=${FINERACT_COMMAND_GROUP_UPDATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupUpdate.wait-duration=${FINERACT_COMMAND_GROUP_UPDATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupUpdate.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupUpdate.retryExceptions=${FINERACT_COMMAND_GROUP_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupUpdateRole.max-attempts=${FINERACT_COMMAND_GROUP_UPDATE_ROLE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupUpdateRole.wait-duration=${FINERACT_COMMAND_GROUP_UPDATE_ROLE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupUpdateRole.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_UPDATE_ROLE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupUpdateRole.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_UPDATE_ROLE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupUpdateRole.retryExceptions=${FINERACT_COMMAND_GROUP_UPDATE_ROLE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandGroupUpload.max-attempts=${FINERACT_COMMAND_GROUP_UPLOAD_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandGroupUpload.wait-duration=${FINERACT_COMMAND_GROUP_UPLOAD_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandGroupUpload.enable-exponential-backoff=${FINERACT_COMMAND_GROUP_UPLOAD_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandGroupUpload.exponential-backoff-multiplier=${FINERACT_COMMAND_GROUP_UPLOAD_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandGroupUpload.retryExceptions=${FINERACT_COMMAND_GROUP_UPLOAD_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +# center + +resilience4j.retry.instances.commandCenterActivate.max-attempts=${FINERACT_COMMAND_CENTER_ACTIVATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterActivate.wait-duration=${FINERACT_COMMAND_CENTER_ACTIVATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterActivate.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_ACTIVATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterActivate.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_ACTIVATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterActivate.retryExceptions=${FINERACT_COMMAND_CENTER_ACTIVATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterAssociateGroups.max-attempts=${FINERACT_COMMAND_CENTER_ASSOCIATE_GROUPS_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterAssociateGroups.wait-duration=${FINERACT_COMMAND_CENTER_ASSOCIATE_GROUPS_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterAssociateGroups.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_ASSOCIATE_GROUPS_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterAssociateGroups.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_ASSOCIATE_GROUPS_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterAssociateGroups.retryExceptions=${FINERACT_COMMAND_CENTER_ASSOCIATE_GROUPS_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterClose.max-attempts=${FINERACT_COMMAND_CENTER_CLOSE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterClose.wait-duration=${FINERACT_COMMAND_CENTER_CLOSE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterClose.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_CLOSE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterClose.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_CLOSE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterClose.retryExceptions=${FINERACT_COMMAND_CENTER_CLOSE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterCreate.max-attempts=${FINERACT_COMMAND_CENTER_CREATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterCreate.wait-duration=${FINERACT_COMMAND_CENTER_CREATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterCreate.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_CREATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterCreate.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_CREATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterCreate.retryExceptions=${FINERACT_COMMAND_CENTER_CREATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterDelete.max-attempts=${FINERACT_COMMAND_CENTER_DELETE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterDelete.wait-duration=${FINERACT_COMMAND_CENTER_DELETE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterDelete.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_DELETE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterDelete.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_DELETE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterDelete.retryExceptions=${FINERACT_COMMAND_CENTER_DELETE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterDisassociateGroups.max-attempts=${FINERACT_COMMAND_CENTER_DISASSOCIATE_GROUPS_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterDisassociateGroups.wait-duration=${FINERACT_COMMAND_CENTER_DISASSOCIATE_GROUPS_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterDisassociateGroups.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_DISASSOCIATE_GROUPS_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterDisassociateGroups.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_DISASSOCIATE_GROUPS_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterDisassociateGroups.retryExceptions=${FINERACT_COMMAND_CENTER_DISASSOCIATE_GROUPS_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterSaveCollectionSheet.max-attempts=${FINERACT_COMMAND_CENTER_SAVE_COLLECTION_SHEET_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterSaveCollectionSheet.wait-duration=${FINERACT_COMMAND_CENTER_SAVE_COLLECTION_SHEET_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterSaveCollectionSheet.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_SAVE_COLLECTION_SHEET_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterSaveCollectionSheet.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_SAVE_COLLECTION_SHEET_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterSaveCollectionSheet.retryExceptions=${FINERACT_COMMAND_CENTER_SAVE_COLLECTION_SHEET_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterUpdate.max-attempts=${FINERACT_COMMAND_CENTER_UPDATE_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterUpdate.wait-duration=${FINERACT_COMMAND_CENTER_UPDATE_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterUpdate.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_UPDATE_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterUpdate.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_UPDATE_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterUpdate.retryExceptions=${FINERACT_COMMAND_CENTER_UPDATE_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + +resilience4j.retry.instances.commandCenterUpload.max-attempts=${FINERACT_COMMAND_CENTER_UPLOAD_RETRY_MAX_ATTEMPTS:3} +resilience4j.retry.instances.commandCenterUpload.wait-duration=${FINERACT_COMMAND_CENTER_UPLOAD_RETRY_WAIT_DURATION:1s} +resilience4j.retry.instances.commandCenterUpload.enable-exponential-backoff=${FINERACT_COMMAND_CENTER_UPLOAD_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true} +resilience4j.retry.instances.commandCenterUpload.exponential-backoff-multiplier=${FINERACT_COMMAND_CENTER_UPLOAD_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2} +resilience4j.retry.instances.commandCenterUpload.retryExceptions=${FINERACT_COMMAND_CENTER_UPLOAD_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException} + # command fineract.command.enabled=true diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/config/CommandRequestMatcherTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/config/CommandRequestMatcherTest.java new file mode 100644 index 00000000000..d76305ca2a2 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/config/CommandRequestMatcherTest.java @@ -0,0 +1,85 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.core.config; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpMethod; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.web.util.matcher.RequestMatcher; + +class CommandRequestMatcherTest { + + private final RequestMatcher matcher = SecurityConfig.commandMatcher(HttpMethod.POST, "/api/*/groups/*", "activate"); + + private static MockHttpServletRequest post(String uri, String command) { + return request("POST", uri, command); + } + + private static MockHttpServletRequest request(String method, String uri, String command) { + MockHttpServletRequest request = new MockHttpServletRequest(method, uri); + request.setServletPath(uri); + if (command != null) { + request.setParameter("command", command); + } + return request; + } + + @Test + void matchesCommandCaseInsensitively() { + assertTrue(matcher.matches(post("/api/v1/groups/12", "activate"))); + assertTrue(matcher.matches(post("/api/v1/groups/12", "Activate"))); + } + + @Test + void matchesCommandWithSurroundingWhitespace() { + assertTrue(matcher.matches(post("/api/v1/groups/12", " activate"))); + assertTrue(matcher.matches(post("/api/v1/groups/12", "activate "))); + } + + @Test + void matchesPathWithTrailingSlash() { + assertTrue(matcher.matches(post("/api/v1/groups/12/", "activate"))); + } + + @Test + void rejectsOtherCommandsAbsentCommandAndOtherPaths() { + assertFalse(matcher.matches(post("/api/v1/groups/12", "close"))); + assertFalse(matcher.matches(post("/api/v1/groups/12", null))); + assertFalse(matcher.matches(post("/api/v1/centers/12", "activate"))); + assertFalse(matcher.matches(post("/api/v1/groups/12/accounts", "activate"))); + } + + @Test + void rejectsOtherHttpMethods() { + assertFalse(matcher.matches(request("PUT", "/api/v1/groups/12", "activate"))); + assertFalse(matcher.matches(request("GET", "/api/v1/groups/12", "activate"))); + } + + @Test + void pathMatcherAcceptsOptionalTrailingSlashOnly() { + RequestMatcher get = SecurityConfig.pathMatcher(HttpMethod.GET, "/api/*/groups/*"); + assertTrue(get.matches(request("GET", "/api/v1/groups/12", null))); + assertTrue(get.matches(request("GET", "/api/v1/groups/12/", null))); + assertFalse(get.matches(request("GET", "/api/v1/groups/12/accounts", null))); + assertFalse(get.matches(request("POST", "/api/v1/groups/12", null))); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetTypedAdapterTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetTypedAdapterTest.java new file mode 100644 index 00000000000..ac83e7b084e --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/collectionsheet/service/CollectionSheetTypedAdapterTest.java @@ -0,0 +1,86 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.collectionsheet.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.google.gson.JsonObject; +import java.math.BigDecimal; +import java.util.List; +import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; +import org.apache.fineract.portfolio.group.data.CollectionSheetLoanTransactionItem; +import org.apache.fineract.portfolio.group.data.CollectionSheetSavingsTransactionItem; +import org.apache.fineract.portfolio.group.data.GroupSaveCollectionSheetRequest; +import org.junit.jupiter.api.Test; + +class CollectionSheetTypedAdapterTest { + + @Test + void bridgeSerialisesOnlyLegacyKeysAndDropsId() { + GroupSaveCollectionSheetRequest request = GroupSaveCollectionSheetRequest.builder().id(5L).calendarId(7L) + .transactionDate("01 January 2024").dateFormat("dd MMMM yyyy").locale("en") + .bulkRepaymentTransactions( + List.of(CollectionSheetLoanTransactionItem.builder().loanId(1L).transactionAmount(new BigDecimal("10")).build())) + .isTransactionDateOnNonMeetingDate(true).build(); + + JsonObject json = CollectionSheetWritePlatformServiceJpaRepositoryImpl.toLegacyJson(request, new FromJsonHelper()) + .getAsJsonObject(); + + assertFalse(json.has("id")); + assertEquals(7L, json.get("calendarId").getAsLong()); + assertEquals("01 January 2024", json.get("transactionDate").getAsString()); + assertTrue(json.get("isTransactionDateOnNonMeetingDate").getAsBoolean()); + assertEquals(1L, json.getAsJsonArray("bulkRepaymentTransactions").get(0).getAsJsonObject().get("loanId").getAsLong()); + assertFalse(json.has("note")); + } + + @Test + void bridgeKeepsPerTransactionExternalIdAndPaymentDetail() { + GroupSaveCollectionSheetRequest request = GroupSaveCollectionSheetRequest.builder().id(5L).transactionDate("01 January 2024") + .dateFormat("dd MMMM yyyy").locale("en") + .bulkRepaymentTransactions(List.of(CollectionSheetLoanTransactionItem.builder().loanId(1L) + .transactionAmount(new BigDecimal("10")).externalId("ext-1").paymentTypeId(3L).accountNumber("acc") + .checkNumber("chk").routingCode("rt").receiptNumber("rcpt").bankNumber("bank").build())) + .bulkSavingsDueTransactions(List.of(CollectionSheetSavingsTransactionItem.builder().savingsId(2L) + .transactionAmount(new BigDecimal("5")).paymentTypeId(4).accountNumber("sacc").checkNumber("schk") + .routingCode("srt").receiptNumber("srcpt").bankNumber("sbank").build())) + .build(); + + JsonObject json = CollectionSheetWritePlatformServiceJpaRepositoryImpl.toLegacyJson(request, new FromJsonHelper()) + .getAsJsonObject(); + + JsonObject repayment = json.getAsJsonArray("bulkRepaymentTransactions").get(0).getAsJsonObject(); + assertEquals("ext-1", repayment.get("externalId").getAsString()); + assertEquals(3L, repayment.get("paymentTypeId").getAsLong()); + assertEquals("acc", repayment.get("accountNumber").getAsString()); + assertEquals("chk", repayment.get("checkNumber").getAsString()); + assertEquals("rt", repayment.get("routingCode").getAsString()); + assertEquals("rcpt", repayment.get("receiptNumber").getAsString()); + assertEquals("bank", repayment.get("bankNumber").getAsString()); + JsonObject savings = json.getAsJsonArray("bulkSavingsDueTransactions").get(0).getAsJsonObject(); + assertEquals(4, savings.get("paymentTypeId").getAsInt()); + assertEquals("sacc", savings.get("accountNumber").getAsString()); + assertEquals("schk", savings.get("checkNumber").getAsString()); + assertEquals("srt", savings.get("routingCode").getAsString()); + assertEquals("srcpt", savings.get("receiptNumber").getAsString()); + assertEquals("sbank", savings.get("bankNumber").getAsString()); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/api/CentersApiResourceCommandsTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/api/CentersApiResourceCommandsTest.java new file mode 100644 index 00000000000..0849ac92afd --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/api/CentersApiResourceCommandsTest.java @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.api; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import java.util.List; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandDispatcher; +import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; +import org.apache.fineract.portfolio.group.command.CenterAssociateGroupsCommand; +import org.apache.fineract.portfolio.group.data.CenterAssociateGroupsRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandRequest; +import org.apache.fineract.portfolio.group.data.CenterCommandResponse; +import org.apache.fineract.portfolio.group.mapping.CenterCommandRequestMapper; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; +import org.mockito.ArgumentCaptor; + +class CentersApiResourceCommandsTest { + + private final CommandDispatcher dispatcher = mock(CommandDispatcher.class); + + private CentersApiResource resource() { + return new CentersApiResource(null, null, null, null, null, null, null, null, null, null, null, null, null, dispatcher, + Validation.buildDefaultValidatorFactory().getValidator(), Mappers.getMapper(CenterCommandRequestMapper.class)); + } + + @Test + void associateGroupsDispatchesWithPathId() { + CenterCommandResponse expected = CenterCommandResponse.builder().resourceId(3L).build(); + when(dispatcher.dispatch(any())).thenReturn(() -> expected); + + Object result = resource().activate(3L, "associateGroups", CenterCommandRequest.builder().groupMembers(List.of(8L)).build(), null); + + ArgumentCaptor> captor = ArgumentCaptor.forClass(Command.class); + verify(dispatcher).dispatch(captor.capture()); + assertTrue(captor.getValue() instanceof CenterAssociateGroupsCommand); + assertEquals(3L, captor.getValue().getPayload().getId()); + assertEquals(List.of(8L), captor.getValue().getPayload().getGroupMembers()); + assertEquals(expected, result); + } + + @Test + void associateGroupsWithoutMembersIsRejected() { + ConstraintViolationException ex = assertThrows(ConstraintViolationException.class, + () -> resource().activate(3L, "associateGroups", CenterCommandRequest.builder().build(), null)); + assertEquals("groupMembers", ex.getConstraintViolations().iterator().next().getPropertyPath().toString()); + verifyNoInteractions(dispatcher); + } + + @Test + void unknownCommandIsRejected() { + assertThrows(UnrecognizedQueryParamException.class, + () -> resource().activate(3L, "nope", CenterCommandRequest.builder().build(), null)); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/api/GroupsApiResourceCommandsTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/api/GroupsApiResourceCommandsTest.java new file mode 100644 index 00000000000..7a7ef64339d --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/api/GroupsApiResourceCommandsTest.java @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.api; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import jakarta.validation.ConstraintViolationException; +import jakarta.validation.Validation; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandDispatcher; +import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException; +import org.apache.fineract.portfolio.group.command.GroupActivateCommand; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.mapping.GroupCommandRequestMapper; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; +import org.mockito.ArgumentCaptor; + +class GroupsApiResourceCommandsTest { + + private final CommandDispatcher dispatcher = mock(CommandDispatcher.class); + + private GroupsApiResource resource() { + return new GroupsApiResource(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, dispatcher, Validation.buildDefaultValidatorFactory().getValidator(), + Mappers.getMapper(GroupCommandRequestMapper.class)); + } + + @Test + void activateDispatchesActivateCommandWithPathId() { + GroupCommandResponse expected = GroupCommandResponse.builder().groupId(5L).build(); + when(dispatcher.dispatch(any())).thenReturn(() -> expected); + GroupCommandRequest body = GroupCommandRequest.builder().activationDate("01 January 2024").dateFormat("dd MMMM yyyy").locale("en") + .build(); + + Object result = resource().activateOrGenerateCollectionSheet(5L, "ACTIVATE", null, body, null); + + ArgumentCaptor> captor = ArgumentCaptor.forClass(Command.class); + org.mockito.Mockito.verify(dispatcher).dispatch(captor.capture()); + assertTrue(captor.getValue() instanceof GroupActivateCommand); + assertEquals(5L, captor.getValue().getPayload().getId()); + assertEquals(expected, result); + } + + @Test + void activateWithoutDateIsRejectedBeforeDispatch() { + ConstraintViolationException ex = assertThrows(ConstraintViolationException.class, + () -> resource().activateOrGenerateCollectionSheet(5L, "activate", null, GroupCommandRequest.builder().build(), null)); + assertEquals("activationDate", ex.getConstraintViolations().iterator().next().getPropertyPath().toString()); + verifyNoInteractions(dispatcher); + } + + @Test + void unknownCommandIsRejected() { + assertThrows(UnrecognizedQueryParamException.class, + () -> resource().activateOrGenerateCollectionSheet(5L, "explode", null, GroupCommandRequest.builder().build(), null)); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/data/CenterRequestValidationTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/data/CenterRequestValidationTest.java new file mode 100644 index 00000000000..ebbaf80f9fc --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/data/CenterRequestValidationTest.java @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class CenterRequestValidationTest { + + private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + private static Set paths(Set> violations) { + return violations.stream().map(v -> v.getPropertyPath().toString()).collect(Collectors.toSet()); + } + + @Test + void createRequiresNameAndOfficeId() { + assertEquals(Set.of("name", "officeId"), paths(validator.validate(CenterCreateRequest.builder().build()))); + } + + @Test + void createRequiresActivationDateWhenActive() { + CenterCreateRequest request = CenterCreateRequest.builder().name("c").officeId(1L).active(true).build(); + assertEquals(Set.of("activationDate"), paths(validator.validate(request))); + } + + @Test + void associateGroupsRequiresMembers() { + assertEquals(Set.of("groupMembers"), + paths(validator.validate(CenterAssociateGroupsRequest.builder().id(1L).groupMembers(List.of()).build()))); + } + + @Test + void pageResponseExposesPageItemsAndTotal() { + GroupsPageResponse page = new GroupsPageResponse(List.of(), 0); + assertEquals(0, page.getTotalFilteredRecords()); + assertEquals(0, page.getPageItems().size()); + } + + @Test + void updateRequiresName() { + assertEquals(Set.of("name"), paths(validator.validate(CenterUpdateRequest.builder().id(1L).build()))); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/data/GroupRequestValidationTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/data/GroupRequestValidationTest.java new file mode 100644 index 00000000000..b87b9730901 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/data/GroupRequestValidationTest.java @@ -0,0 +1,101 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class GroupRequestValidationTest { + + private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); + + private static Set paths(Set> violations) { + return violations.stream().map(v -> v.getPropertyPath().toString()).collect(Collectors.toSet()); + } + + @Test + void createRequiresNameAndOfficeIdWhenNoCenter() { + Set> violations = validator.validate(GroupCreateRequest.builder().build()); + assertEquals(Set.of("name", "officeId"), paths(violations)); + } + + @Test + void createAcceptsCenterIdInsteadOfOfficeId() { + GroupCreateRequest request = GroupCreateRequest.builder().name("g").centerId(3L).build(); + assertTrue(validator.validate(request).isEmpty()); + } + + @Test + void createRequiresActivationDateWhenActive() { + GroupCreateRequest request = GroupCreateRequest.builder().name("g").officeId(1L).active(true).build(); + assertEquals(Set.of("activationDate"), paths(validator.validate(request))); + } + + @Test + void createRejectsNameOver100Chars() { + GroupCreateRequest request = GroupCreateRequest.builder().name("x".repeat(101)).officeId(1L).build(); + assertEquals(Set.of("name"), paths(validator.validate(request))); + } + + @Test + void activateRequiresActivationDate() { + assertEquals(Set.of("activationDate"), paths(validator.validate(GroupActivateRequest.builder().id(1L).build()))); + } + + @Test + void closeRequiresDateAndReason() { + assertEquals(Set.of("closureDate", "closureReasonId"), paths(validator.validate(GroupCloseRequest.builder().id(1L).build()))); + } + + @Test + void associateClientsRequiresNonEmptyMembers() { + assertEquals(Set.of("clientMembers"), + paths(validator.validate(GroupAssociateClientsRequest.builder().id(1L).clientMembers(List.of()).build()))); + } + + @Test + void assignRoleRequiresClientAndRole() { + assertEquals(Set.of("clientId", "role"), paths(validator.validate(GroupAssignRoleRequest.builder().groupId(1L).build()))); + } + + @Test + void transferRequiresDestinationAndClients() { + assertEquals(Set.of("destinationGroupId", "clients"), + paths(validator.validate(GroupTransferClientsRequest.builder().id(1L).build()))); + } + + @Test + void saveCollectionSheetRequiresCalendarAndTransactionDate() { + assertEquals(Set.of("calendarId", "transactionDate"), + paths(validator.validate(GroupSaveCollectionSheetRequest.builder().id(1L).build()))); + } + + @Test + void updateRequiresName() { + assertEquals(Set.of("name"), paths(validator.validate(GroupUpdateRequest.builder().id(1L).build()))); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/handler/GroupCommandHandlersTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/handler/GroupCommandHandlersTest.java new file mode 100644 index 00000000000..9d8233b5930 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/handler/GroupCommandHandlersTest.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.handler; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.portfolio.group.command.GroupActivateCommand; +import org.apache.fineract.portfolio.group.command.GroupCreateCommand; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; +import org.apache.fineract.portfolio.group.service.GroupingTypesWriteService; +import org.junit.jupiter.api.Test; + +class GroupCommandHandlersTest { + + private final GroupingTypesWriteService service = mock(GroupingTypesWriteService.class); + + @Test + void createHandlerDelegatesToService() { + GroupCreateRequest request = GroupCreateRequest.builder().name("g").officeId(1L).build(); + GroupCreateResponse expected = GroupCreateResponse.builder().resourceId(1L).build(); + when(service.createGroup(request)).thenReturn(expected); + GroupCreateCommand command = new GroupCreateCommand(); + command.setPayload(request); + + assertSame(expected, new GroupCreateCommandHandler(service).handle(command)); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + void handlersMatchOnlyTheirOwnPayloadType() { + GroupCreateCommand create = new GroupCreateCommand(); + create.setPayload(GroupCreateRequest.builder().build()); + GroupActivateCommand activate = new GroupActivateCommand(); + activate.setPayload(GroupActivateRequest.builder().build()); + + CommandHandler createHandler = new GroupCreateCommandHandler(service); + CommandHandler activateHandler = new GroupActivateCommandHandler(service); + + assertTrue(createHandler.matches(create)); + assertTrue(!createHandler.matches(activate)); + assertTrue(activateHandler.matches(activate)); + } + + @Test + void activateHandlerDelegatesToService() { + GroupActivateRequest request = GroupActivateRequest.builder().id(1L).activationDate("x").build(); + GroupCommandResponse expected = GroupCommandResponse.builder().groupId(1L).build(); + when(service.activateGroup(request)).thenReturn(expected); + GroupActivateCommand command = new GroupActivateCommand(); + command.setPayload(request); + + assertSame(expected, new GroupActivateCommandHandler(service).handle(command)); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/mapping/GroupCommandRequestMapperTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/mapping/GroupCommandRequestMapperTest.java new file mode 100644 index 00000000000..c6b4436310b --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/mapping/GroupCommandRequestMapperTest.java @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.util.List; +import org.apache.fineract.portfolio.group.data.GroupActivateRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandRequest; +import org.apache.fineract.portfolio.group.data.GroupTransferClientItem; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupUnassignRoleRequest; +import org.junit.jupiter.api.Test; +import org.mapstruct.factory.Mappers; + +class GroupCommandRequestMapperTest { + + private final GroupCommandRequestMapper mapper = Mappers.getMapper(GroupCommandRequestMapper.class); + + @Test + void activateTakesIdFromPathAndDateFieldsFromBody() { + GroupCommandRequest body = GroupCommandRequest.builder().activationDate("01 January 2024").dateFormat("dd MMMM yyyy").locale("en") + .staffId(99L).build(); + GroupActivateRequest out = mapper.toActivate(body, 5L); + assertEquals(5L, out.getId()); + assertEquals("01 January 2024", out.getActivationDate()); + assertEquals("dd MMMM yyyy", out.getDateFormat()); + assertEquals("en", out.getLocale()); + } + + @Test + void transferCopiesNestedClients() { + GroupCommandRequest body = GroupCommandRequest.builder().destinationGroupId(8L) + .clients(List.of(GroupTransferClientItem.builder().id(3L).build())).transferActiveLoans(false).build(); + GroupTransferClientsRequest out = mapper.toTransferClients(body, 5L); + assertEquals(5L, out.getId()); + assertEquals(8L, out.getDestinationGroupId()); + assertEquals(3L, out.getClients().get(0).getId()); + assertEquals(false, out.getTransferActiveLoans()); + assertNull(out.getStaffId()); + } + + @Test + void unassignRoleTakesBothIdsFromQuery() { + GroupUnassignRoleRequest out = mapper.toUnassignRole(GroupCommandRequest.builder().build(), 5L, 12L); + assertEquals(5L, out.getGroupId()); + assertEquals(12L, out.getRoleId()); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/mapping/GroupDateMapperTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/mapping/GroupDateMapperTest.java new file mode 100644 index 00000000000..0e6bfa6cb4d --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/mapping/GroupDateMapperTest.java @@ -0,0 +1,60 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.mapping; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.time.LocalDate; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.junit.jupiter.api.Test; + +class GroupDateMapperTest { + + private final GroupDateMapper mapper = new GroupDateMapper(); + + @Test + void parsesLegacyFormatWithLocale() { + assertEquals(LocalDate.of(2024, 1, 5), mapper.toLocalDate("05 January 2024", "activationDate", "dd MMMM yyyy", "en")); + } + + @Test + void parsesNonEnglishLocale() { + assertEquals(LocalDate.of(2024, 1, 5), mapper.toLocalDate("05 janvier 2024", "activationDate", "dd MMMM yyyy", "fr")); + } + + @Test + void blankIsNull() { + assertNull(mapper.toLocalDate(" ", "activationDate", "dd MMMM yyyy", "en")); + assertNull(mapper.toLocalDate(null, "activationDate", "dd MMMM yyyy", "en")); + } + + @Test + void unparsableThrowsLegacyValidationException() { + PlatformApiDataValidationException ex = assertThrows(PlatformApiDataValidationException.class, + () -> mapper.toLocalDate("2024-01-05", "activationDate", "dd MMMM yyyy", "en")); + assertEquals("activationDate", ex.getErrors().get(0).getParameterName()); + } + + @Test + void missingDateFormatThrowsLegacyValidationException() { + assertThrows(PlatformApiDataValidationException.class, () -> mapper.toLocalDate("05 January 2024", "activationDate", null, "en")); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteServiceImplTest.java new file mode 100644 index 00000000000..5725ff35e5e --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupRolesWriteServiceImplTest.java @@ -0,0 +1,86 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.apache.fineract.infrastructure.codes.domain.CodeValue; +import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; +import org.apache.fineract.portfolio.group.data.GroupAssignRoleRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.domain.Group; +import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; +import org.apache.fineract.portfolio.group.domain.GroupRole; +import org.apache.fineract.portfolio.group.domain.GroupRoleRepositoryWrapper; +import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +class GroupRolesWriteServiceImplTest { + + private final GroupRepositoryWrapper groupRepository = mock(GroupRepositoryWrapper.class); + private final CodeValueRepositoryWrapper codeValues = mock(CodeValueRepositoryWrapper.class); + private final ClientRepositoryWrapper clients = mock(ClientRepositoryWrapper.class); + private final GroupRoleRepositoryWrapper groupRoles = mock(GroupRoleRepositoryWrapper.class); + private final GroupRolesWriteServiceImpl service = new GroupRolesWriteServiceImpl(mock(PlatformSecurityContext.class), groupRepository, + codeValues, clients, groupRoles); + + @Test + void assignRoleRejectsClientOutsideGroup() { + Group group = mock(Group.class); + when(group.hasClientAsMember(any())).thenReturn(false); + when(groupRepository.findOneWithNotFoundDetection(1L)).thenReturn(group); + when(clients.findOneWithNotFoundDetection(2L)).thenReturn(mock(Client.class)); + when(codeValues.findOneWithNotFoundDetection(3L)).thenReturn(mock(CodeValue.class)); + + assertThrows(ClientNotInGroupException.class, + () -> service.assignRole(GroupAssignRoleRequest.builder().groupId(1L).clientId(2L).role(3L).build())); + } + + @Test + void assignRoleReturnsIds() { + Group group = mock(Group.class); + Client client = mock(Client.class); + when(client.getId()).thenReturn(2L); + when(group.getId()).thenReturn(1L); + when(group.hasClientAsMember(client)).thenReturn(true); + when(groupRepository.findOneWithNotFoundDetection(1L)).thenReturn(group); + when(clients.findOneWithNotFoundDetection(2L)).thenReturn(client); + when(codeValues.findOneWithNotFoundDetection(3L)).thenReturn(mock(CodeValue.class)); + doAnswer(inv -> { + GroupRole r = inv.getArgument(0); + ReflectionTestUtils.setField(r, "id", 99L); + return null; + }).when(groupRoles).saveAndFlush(any(GroupRole.class)); + + GroupCommandResponse response = service.assignRole(GroupAssignRoleRequest.builder().groupId(1L).clientId(2L).role(3L).build()); + + assertEquals(1L, response.getGroupId()); + assertEquals(2L, response.getClientId()); + assertEquals(99L, response.getResourceId()); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImplTest.java deleted file mode 100644 index e75046d9e44..00000000000 --- a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupingTypesWritePlatformServiceJpaRepositoryImplTest.java +++ /dev/null @@ -1,137 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.fineract.portfolio.group.service; - -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import java.util.Optional; -import org.apache.fineract.commands.service.CommandProcessingService; -import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; -import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; -import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; -import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; -import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.organisation.office.domain.Office; -import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; -import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; -import org.apache.fineract.portfolio.account.service.AccountNumberGenerator; -import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; -import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; -import org.apache.fineract.portfolio.group.domain.Group; -import org.apache.fineract.portfolio.group.domain.GroupLevel; -import org.apache.fineract.portfolio.group.domain.GroupLevelRepository; -import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; -import org.apache.fineract.portfolio.group.exception.GroupLevelNotFoundException; -import org.apache.fineract.portfolio.group.serialization.GroupingTypesDataValidator; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; -import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService; -import org.apache.fineract.portfolio.note.domain.NoteRepository; -import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.junit.jupiter.MockitoSettings; -import org.mockito.quality.Strictness; - -@ExtendWith(MockitoExtension.class) -@MockitoSettings(strictness = Strictness.LENIENT) -class GroupingTypesWritePlatformServiceJpaRepositoryImplTest { - - @Mock - private PlatformSecurityContext context; - @Mock - private GroupRepositoryWrapper groupRepository; - @Mock - private ClientRepositoryWrapper clientRepositoryWrapper; - @Mock - private OfficeRepositoryWrapper officeRepositoryWrapper; - @Mock - private StaffRepositoryWrapper staffRepository; - @Mock - private NoteRepository noteRepository; - @Mock - private GroupLevelRepository groupLevelRepository; - @Mock - private GroupingTypesDataValidator fromApiJsonDeserializer; - @Mock - private LoanRepositoryWrapper loanRepositoryWrapper; - @Mock - private CodeValueRepositoryWrapper codeValueRepository; - @Mock - private CommandProcessingService commandProcessingService; - @Mock - private CalendarInstanceRepository calendarInstanceRepository; - @Mock - private ConfigurationDomainService configurationDomainService; - @Mock - private SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper; - @Mock - private AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; - @Mock - private AccountNumberGenerator accountNumberGenerator; - @Mock - private EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService; - @Mock - private BusinessEventNotifierService businessEventNotifierService; - @Mock - private LoanOfficerService loanOfficerService; - @Mock - private ExternalIdFactory externalIdFactory; - - @Mock - private Group group; - @Mock - private Office office; - @Mock - private GroupLevel groupLevel; - @Mock - private JsonCommand command; - - @Test - void updateGroupThrowsGroupLevelNotFoundExceptionWhenGroupLevelMissing() { - GroupingTypesWritePlatformServiceJpaRepositoryImpl service = new GroupingTypesWritePlatformServiceJpaRepositoryImpl(context, - groupRepository, clientRepositoryWrapper, officeRepositoryWrapper, staffRepository, noteRepository, groupLevelRepository, - fromApiJsonDeserializer, loanRepositoryWrapper, codeValueRepository, commandProcessingService, calendarInstanceRepository, - configurationDomainService, savingsAccountRepositoryWrapper, accountNumberFormatRepository, accountNumberGenerator, - entityDatatableChecksWritePlatformService, businessEventNotifierService, loanOfficerService, externalIdFactory); - - Long groupId = 1L; - Long groupLevelId = 2L; - - when(groupRepository.findOneWithNotFoundDetection(groupId)).thenReturn(group); - when(group.officeId()).thenReturn(10L); - when(group.getOffice()).thenReturn(office); - when(office.getHierarchy()).thenReturn("."); - when(group.getGroupLevel()).thenReturn(groupLevel); - when(groupLevel.getId()).thenReturn(groupLevelId); - when(command.localDateValueOfParameterNamed(anyString())).thenReturn(null); - when(group.update(any(JsonCommand.class))).thenReturn(Collections.emptyMap()); - when(groupLevelRepository.findById(groupLevelId)).thenReturn(Optional.empty()); - - assertThrows(GroupLevelNotFoundException.class, () -> service.updateGroup(groupId, command)); - } -} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteServiceImplTest.java new file mode 100644 index 00000000000..a091b6e2229 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/group/service/GroupingTypesWriteServiceImplTest.java @@ -0,0 +1,219 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.group.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType; +import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.core.domain.ExternalId; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; +import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; +import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService; +import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.organisation.office.domain.Office; +import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; +import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; +import org.apache.fineract.portfolio.account.service.AccountNumberGenerator; +import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; +import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; +import org.apache.fineract.portfolio.group.data.GroupAssociateClientsRequest; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupCreateRequest; +import org.apache.fineract.portfolio.group.data.GroupCreateResponse; +import org.apache.fineract.portfolio.group.data.GroupDeleteRequest; +import org.apache.fineract.portfolio.group.data.GroupUnassignStaffRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateRequest; +import org.apache.fineract.portfolio.group.data.GroupUpdateResponse; +import org.apache.fineract.portfolio.group.domain.Group; +import org.apache.fineract.portfolio.group.domain.GroupLevel; +import org.apache.fineract.portfolio.group.domain.GroupLevelRepository; +import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; +import org.apache.fineract.portfolio.group.exception.GroupHasNoStaffException; +import org.apache.fineract.portfolio.group.exception.GroupMustBePendingToBeDeletedException; +import org.apache.fineract.portfolio.group.mapping.GroupDateMapper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; +import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService; +import org.apache.fineract.portfolio.note.domain.NoteRepository; +import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; +import org.apache.fineract.useradministration.domain.AppUser; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.test.util.ReflectionTestUtils; + +class GroupingTypesWriteServiceImplTest { + + private final PlatformSecurityContext context = mock(PlatformSecurityContext.class); + private final GroupRepositoryWrapper groupRepository = mock(GroupRepositoryWrapper.class); + private final ClientRepositoryWrapper clientRepository = mock(ClientRepositoryWrapper.class); + private final OfficeRepositoryWrapper officeRepository = mock(OfficeRepositoryWrapper.class); + private final GroupLevelRepository groupLevelRepository = mock(GroupLevelRepository.class); + private final ExternalIdFactory externalIdFactory = mock(ExternalIdFactory.class); + private final EntityDatatableChecksWritePlatformService datatableChecks = mock(EntityDatatableChecksWritePlatformService.class); + private final BusinessEventNotifierService events = mock(BusinessEventNotifierService.class); + private final AccountNumberGenerator accountNumberGenerator = mock(AccountNumberGenerator.class); + + private GroupingTypesWriteServiceImpl service; + + @BeforeEach + void setUp() { + ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, LocalDate.of(2024, 1, 1)))); + service = new GroupingTypesWriteServiceImpl(context, groupRepository, clientRepository, officeRepository, + mock(StaffRepositoryWrapper.class), mock(NoteRepository.class), groupLevelRepository, mock(LoanRepositoryWrapper.class), + mock(CodeValueRepositoryWrapper.class), mock(CalendarInstanceRepository.class), mock(ConfigurationDomainService.class), + mock(SavingsAccountRepositoryWrapper.class), mock(AccountNumberFormatRepositoryWrapper.class), accountNumberGenerator, + datatableChecks, events, mock(LoanOfficerService.class), externalIdFactory, new GroupDateMapper()); + when(context.authenticatedUser()).thenReturn(mock(AppUser.class)); + when(externalIdFactory.create(any())) + .thenAnswer(inv -> inv.getArgument(0) == null ? ExternalId.empty() : new ExternalId(inv.getArgument(0))); + } + + @AfterEach + void tearDown() { + ThreadLocalContextUtil.reset(); + } + + @Test + void createPendingGroupReturnsOfficeAndGroupIds() { + Office office = mock(Office.class); + when(office.getId()).thenReturn(7L); + when(office.getHierarchy()).thenReturn("."); + when(office.getOpeningLocalDate()).thenReturn(LocalDate.of(2000, 1, 1)); + when(officeRepository.findOneWithNotFoundDetection(7L)).thenReturn(office); + GroupLevel level = mock(GroupLevel.class); + when(level.isGroup()).thenReturn(true); + when(level.getLevelName()).thenReturn("Group"); + when(groupLevelRepository.findById(anyLong())).thenReturn(Optional.of(level)); + doAnswer(inv -> { // saveAndFlush is void on the wrapper; simulate the DB assigning the id + Group g = inv.getArgument(0); + ReflectionTestUtils.setField(g, "id", 42L); // AbstractPersistableCustom has no setId + return null; + }).when(groupRepository).saveAndFlush(any(Group.class)); + when(accountNumberGenerator.generateGroupAccountNumber(any(), any())).thenReturn("000000042"); + + GroupCreateResponse response = service.createGroup(GroupCreateRequest.builder().name("Alpha").officeId(7L).active(false).build()); + + assertEquals(7L, response.getOfficeId()); + assertEquals(42L, response.getGroupId()); + assertEquals(42L, response.getResourceId()); + verify(accountNumberGenerator).generateGroupAccountNumber(any(), any()); + } + + @Test + void deleteRejectsNonPendingGroup() { + Group active = mock(Group.class); + when(active.isNotPending()).thenReturn(true); + when(groupRepository.findOneWithNotFoundDetection(5L)).thenReturn(active); + + assertThrows(GroupMustBePendingToBeDeletedException.class, () -> service.deleteGroup(GroupDeleteRequest.builder().id(5L).build())); + } + + @Test + void unassignStaffRequiresCurrentStaff() { + Group group = mock(Group.class); + when(group.getStaff()).thenReturn(null); + when(groupRepository.findOneWithNotFoundDetection(9L)).thenReturn(group); + + assertThrows(GroupHasNoStaffException.class, + () -> service.unassignStaff(GroupUnassignStaffRequest.builder().id(9L).staffId(3L).build())); + } + + @Test + void associateClientsRecordsChanges() { + Group group = mock(Group.class); + when(group.officeId()).thenReturn(7L); + when(group.getId()).thenReturn(9L); + when(group.isGroup()).thenReturn(false); + when(group.associateClients(any())).thenReturn(List.of("11")); + when(groupRepository.findOneWithNotFoundDetection(9L)).thenReturn(group); + Client client = mock(Client.class); + when(client.isOfficeIdentifiedBy(7L)).thenReturn(true); + when(clientRepository.findOneWithNotFoundDetection(11L)).thenReturn(client); + + GroupCommandResponse response = service + .associateClients(GroupAssociateClientsRequest.builder().id(9L).clientMembers(List.of(11L)).build()); + + assertEquals(9L, response.getGroupId()); + assertEquals(List.of("11"), response.getChanges().get("clientMembers")); + } + + private Group existingGroup(long id) { + Office office = mock(Office.class); + when(office.getHierarchy()).thenReturn("."); + when(office.getOpeningLocalDate()).thenReturn(LocalDate.of(2000, 1, 1)); + GroupLevel level = mock(GroupLevel.class); + when(level.getId()).thenReturn(1L); + when(level.getLevelName()).thenReturn("Group"); + when(groupLevelRepository.findById(1L)).thenReturn(Optional.of(level)); + Group group = mock(Group.class); + when(group.getId()).thenReturn(id); + when(group.officeId()).thenReturn(7L); + when(group.getOffice()).thenReturn(office); + when(group.getGroupLevel()).thenReturn(level); + when(group.getName()).thenReturn("Old"); + when(groupRepository.findOneWithNotFoundDetection(id)).thenReturn(group); + return group; + } + + @Test + void updateRecordsOnlyChangedFieldsInLegacyOrder() { + Group group = existingGroup(9L); + + GroupUpdateResponse response = service.updateGroup(GroupUpdateRequest.builder().id(9L).name("New").externalId("ext-9") + .activationDate("02 January 2024").dateFormat("dd MMMM yyyy").locale("en").build()); + + assertEquals(9L, response.getGroupId()); + assertEquals(List.of("externalId", "name", "activationDate", "dateFormat", "locale"), + new ArrayList<>(response.getChanges().keySet())); + verify(group).setName("New"); + verify(group).setExternalId("ext-9"); + verify(group).setActivationDate(LocalDate.of(2024, 1, 2)); + verify(groupRepository).saveAndFlush(group); + } + + @Test + void updateRejectsActivationDateBeforeSubmittedOnDate() { + existingGroup(9L); + + PlatformApiDataValidationException e = assertThrows(PlatformApiDataValidationException.class, + () -> service.updateGroup(GroupUpdateRequest.builder().id(9L).name("Old").activationDate("01 January 2024") + .submittedOnDate("02 January 2024").dateFormat("dd MMMM yyyy").locale("en").build())); + + assertEquals("validation.msg.group.activationDate.is.less.than.date", e.getErrors().get(0).getUserMessageGlobalisationCode()); + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/portfolio/transfer/service/TransferTypedAdapterTest.java b/fineract-provider/src/test/java/org/apache/fineract/portfolio/transfer/service/TransferTypedAdapterTest.java new file mode 100644 index 00000000000..6f6baef1a0b --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/portfolio/transfer/service/TransferTypedAdapterTest.java @@ -0,0 +1,171 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.transfer.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; +import org.apache.fineract.infrastructure.core.service.TransactionBoundApplicationEventPublisher; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.organisation.office.domain.Office; +import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper; +import org.apache.fineract.organisation.staff.domain.Staff; +import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; +import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository; +import org.apache.fineract.portfolio.client.domain.Client; +import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; +import org.apache.fineract.portfolio.client.domain.ClientTransferDetailsRepositoryWrapper; +import org.apache.fineract.portfolio.group.data.GroupCommandResponse; +import org.apache.fineract.portfolio.group.data.GroupTransferClientItem; +import org.apache.fineract.portfolio.group.data.GroupTransferClientsRequest; +import org.apache.fineract.portfolio.group.domain.Group; +import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; +import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService; +import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService; +import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper; +import org.apache.fineract.portfolio.savings.service.SavingsAccountWritePlatformService; +import org.apache.fineract.portfolio.transfer.data.TransfersDataValidator; +import org.apache.fineract.portfolio.transfer.exception.TransferNotSupportedException; +import org.apache.fineract.portfolio.transfer.exception.TransferNotSupportedException.TransferNotSupportedReason; +import org.junit.jupiter.api.Test; + +class TransferTypedAdapterTest { + + private final ClientRepositoryWrapper clientRepositoryWrapper = mock(ClientRepositoryWrapper.class); + private final OfficeRepositoryWrapper officeRepository = mock(OfficeRepositoryWrapper.class); + private final CalendarInstanceRepository calendarInstanceRepository = mock(CalendarInstanceRepository.class); + private final GroupRepositoryWrapper groupRepository = mock(GroupRepositoryWrapper.class); + private final LoanWritePlatformService loanWritePlatformService = mock(LoanWritePlatformService.class); + private final SavingsAccountWritePlatformService savingsAccountWritePlatformService = mock(SavingsAccountWritePlatformService.class); + private final LoanRepositoryWrapper loanRepositoryWrapper = mock(LoanRepositoryWrapper.class); + private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper = mock(SavingsAccountRepositoryWrapper.class); + private final TransfersDataValidator transfersDataValidator = mock(TransfersDataValidator.class); + private final StaffRepositoryWrapper staffRepositoryWrapper = mock(StaffRepositoryWrapper.class); + private final ClientTransferDetailsRepositoryWrapper clientTransferDetailsRepositoryWrapper = mock( + ClientTransferDetailsRepositoryWrapper.class); + private final PlatformSecurityContext context = mock(PlatformSecurityContext.class); + private final LoanOfficerService loanOfficerService = mock(LoanOfficerService.class); + private final TransactionBoundApplicationEventPublisher eventPublisher = mock(TransactionBoundApplicationEventPublisher.class); + + private final TransferWritePlatformServiceJpaRepositoryImpl service = spy(new TransferWritePlatformServiceJpaRepositoryImpl( + clientRepositoryWrapper, officeRepository, calendarInstanceRepository, groupRepository, loanWritePlatformService, + savingsAccountWritePlatformService, loanRepositoryWrapper, savingsAccountRepositoryWrapper, transfersDataValidator, + staffRepositoryWrapper, clientTransferDetailsRepositoryWrapper, context, loanOfficerService, eventPublisher)); + + @Test + void sameSourceAndDestinationGroupIsRejected() { + Group group = mock(Group.class); + when(groupRepository.findOneWithNotFoundDetection(1L)).thenReturn(group); + + GroupTransferClientsRequest request = GroupTransferClientsRequest.builder().id(1L).destinationGroupId(1L) + .clients(List.of(GroupTransferClientItem.builder().id(9L).build())).build(); + + TransferNotSupportedException exception = assertThrows(TransferNotSupportedException.class, + () -> service.transferClientsBetweenGroups(request)); + assertEquals(TransferNotSupportedReason.SOURCE_AND_DESTINATION_GROUP_CANNOT_BE_SAME.errorCode(), + exception.getGlobalisationMessageCode()); + verify(service, never()).transferClientBetweenGroups(any(), any(), any(), any(), any()); + } + + @Test + void crossBranchTransferIsRejected() { + Group sourceGroup = mock(Group.class); + Group destinationGroup = mock(Group.class); + Office sourceOffice = mock(Office.class); + Office destinationOffice = mock(Office.class); + when(sourceOffice.getId()).thenReturn(10L); + when(destinationOffice.getId()).thenReturn(20L); + when(sourceGroup.getOffice()).thenReturn(sourceOffice); + when(destinationGroup.getOffice()).thenReturn(destinationOffice); + when(groupRepository.findOneWithNotFoundDetection(1L)).thenReturn(sourceGroup); + when(groupRepository.findOneWithNotFoundDetection(2L)).thenReturn(destinationGroup); + + GroupTransferClientsRequest request = GroupTransferClientsRequest.builder().id(1L).destinationGroupId(2L) + .clients(List.of(GroupTransferClientItem.builder().id(9L).build())).build(); + + TransferNotSupportedException exception = assertThrows(TransferNotSupportedException.class, + () -> service.transferClientsBetweenGroups(request)); + assertEquals(TransferNotSupportedReason.BULK_CLIENT_TRANSFER_ACROSS_BRANCHES.errorCode(), exception.getGlobalisationMessageCode()); + verify(service, never()).transferClientBetweenGroups(any(), any(), any(), any(), any()); + } + + @Test + void happyPathTransfersEachClientAndReturnsSourceGroupId() { + Group sourceGroup = mock(Group.class); + Group destinationGroup = mock(Group.class); + Office office = mock(Office.class); + when(office.getId()).thenReturn(10L); + when(office.getHierarchy()).thenReturn(".10."); + when(sourceGroup.getOffice()).thenReturn(office); + when(destinationGroup.getOffice()).thenReturn(office); + when(groupRepository.findOneWithNotFoundDetection(1L)).thenReturn(sourceGroup); + when(groupRepository.findOneWithNotFoundDetection(2L)).thenReturn(destinationGroup); + + Client client1 = mock(Client.class); + Client client2 = mock(Client.class); + when(clientRepositoryWrapper.findOneWithNotFoundDetection(100L)).thenReturn(client1); + when(clientRepositoryWrapper.findOneWithNotFoundDetection(200L)).thenReturn(client2); + + Staff staff = mock(Staff.class); + when(staffRepositoryWrapper.findByOfficeHierarchyWithNotFoundDetection(5L, ".10.")).thenReturn(staff); + + doNothing().when(service).transferClientBetweenGroups(any(), any(), any(), any(), any()); + + GroupTransferClientsRequest request = GroupTransferClientsRequest.builder().id(1L).destinationGroupId(2L).staffId(5L) + .inheritDestinationGroupLoanOfficer(true) + .clients(List.of(GroupTransferClientItem.builder().id(100L).build(), GroupTransferClientItem.builder().id(200L).build())) + .build(); + + GroupCommandResponse response = service.transferClientsBetweenGroups(request); + + verify(service).transferClientBetweenGroups(sourceGroup, client1, destinationGroup, true, staff); + verify(service).transferClientBetweenGroups(sourceGroup, client2, destinationGroup, true, staff); + assertEquals(1L, response.getGroupId()); + assertEquals(1L, response.getResourceId()); + } + + @Test + void nullClientsListTransfersNobody() { + Group sourceGroup = mock(Group.class); + Group destinationGroup = mock(Group.class); + Office office = mock(Office.class); + when(office.getId()).thenReturn(10L); + when(sourceGroup.getOffice()).thenReturn(office); + when(destinationGroup.getOffice()).thenReturn(office); + when(groupRepository.findOneWithNotFoundDetection(1L)).thenReturn(sourceGroup); + when(groupRepository.findOneWithNotFoundDetection(2L)).thenReturn(destinationGroup); + + GroupTransferClientsRequest request = GroupTransferClientsRequest.builder().id(1L).destinationGroupId(2L).clients(null).build(); + + GroupCommandResponse response = service.transferClientsBetweenGroups(request); + + verify(service, never()).transferClientBetweenGroups(any(), any(), any(), any(), any()); + assertEquals(1L, response.getGroupId()); + assertEquals(1L, response.getResourceId()); + } +} diff --git a/fineract-validation/src/main/resources/ValidationMessages.properties b/fineract-validation/src/main/resources/ValidationMessages.properties index 752d9fbaffc..8a48366c556 100644 --- a/fineract-validation/src/main/resources/ValidationMessages.properties +++ b/fineract-validation/src/main/resources/ValidationMessages.properties @@ -151,3 +151,24 @@ org.apache.fineract.portfolio.floatingrate.base-lending-rate.duplicate=Base Lend org.apache.fineract.portfolio.floatingrate.base-lending-rate.linked=There are floating rates linked to this Base Lending Rate, it cannot be marked as non-Base Lending Rate org.apache.fineract.portfolio.floatingrate.differential-to-base-lending-rate.not-available=Base Lending Rate doesn't exist org.apache.fineract.portfolio.floatingrate.differential-to-base-lending-rate.invalid-for-base-lending-rate=The parameter 'isDifferentialToBaseLendingRate' cannot be true for a floating rate marked as Base Lending Rate +org.apache.fineract.portfolio.group.name.not-null=The parameter 'name' is mandatory +org.apache.fineract.portfolio.group.name.max=The parameter 'name' exceeds the maximum size of {max} characters +org.apache.fineract.portfolio.group.office-id.not-null=The parameter 'officeId' is mandatory +org.apache.fineract.portfolio.group.office-id.positive=The parameter 'officeId' must be greater than 0 +org.apache.fineract.portfolio.group.center-id.positive=The parameter 'centerId' must be greater than 0 +org.apache.fineract.portfolio.group.external-id.max=The parameter 'externalId' exceeds the maximum size of {max} characters +org.apache.fineract.portfolio.group.staff-id.positive=The parameter 'staffId' must be greater than 0 +org.apache.fineract.portfolio.group.activation-date.not-null=The parameter 'activationDate' is mandatory +org.apache.fineract.portfolio.group.datatables.not-empty=The parameter 'datatables' cannot be empty +org.apache.fineract.portfolio.group.client-members.not-empty=The parameter 'clientMembers' cannot be empty +org.apache.fineract.portfolio.group.group-members.not-empty=The parameter 'groupMembers' cannot be empty +org.apache.fineract.portfolio.group.closure-date.not-null=The parameter 'closureDate' is mandatory +org.apache.fineract.portfolio.group.closure-reason-id.not-null=The parameter 'closureReasonId' is mandatory +org.apache.fineract.portfolio.group.client-id.not-null=The parameter 'clientId' is mandatory +org.apache.fineract.portfolio.group.role.not-null=The parameter 'role' is mandatory +org.apache.fineract.portfolio.group.destination-group-id.not-null=The parameter 'destinationGroupId' is mandatory +org.apache.fineract.portfolio.group.destination-group-id.positive=The parameter 'destinationGroupId' must be greater than 0 +org.apache.fineract.portfolio.group.clients.not-empty=The parameter 'clients' cannot be empty +org.apache.fineract.portfolio.group.calendar-id.not-null=The parameter 'calendarId' is mandatory +org.apache.fineract.portfolio.group.transaction-date.not-null=The parameter 'transactionDate' is mandatory +org.apache.fineract.portfolio.group.note.max=The parameter 'note' exceeds the maximum size of {max} characters diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/CenterIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/CenterIntegrationTest.java index 26594a23bee..6bb35cbfae8 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/CenterIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/CenterIntegrationTest.java @@ -36,13 +36,12 @@ import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.UUID; import org.apache.fineract.client.feign.FineractFeignClient; -import org.apache.fineract.client.models.GetCentersCenterIdResponse; -import org.apache.fineract.client.models.GetCentersGroupMembers; -import org.apache.fineract.client.models.GetCentersPageItems; -import org.apache.fineract.client.models.PutCentersCenterIdRequest; -import org.apache.fineract.client.models.PutCentersChanges; +import org.apache.fineract.client.models.CenterData; +import org.apache.fineract.client.models.CenterUpdateRequest; +import org.apache.fineract.client.models.GroupGeneralData; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.client.feign.helpers.FeignCenterHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignGroupHelper; @@ -87,7 +86,7 @@ public void testBasicCenterCreation() { String name = "TestBasicCreation" + new Timestamp(new Date().getTime()); Long resourceId = centerHelper.createCenter(name, officeId).getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(resourceId); + CenterData center = centerHelper.retrieveCenter(resourceId); assertNotNull(center); assertEquals(name, center.getName()); @@ -98,7 +97,7 @@ public void testBasicCenterCreation() { Long id = centerHelper.listCenters().get(0).getId(); assertTrue(id > 0); - GetCentersCenterIdResponse retrievedCenter = centerHelper.retrieveCenter(id); + CenterData retrievedCenter = centerHelper.retrieveCenter(id); assertNotNull(retrievedCenter); assertNotNull(retrievedCenter.getName()); assertNotNull(retrievedCenter.getHierarchy()); @@ -113,7 +112,7 @@ public void testFullCenterCreation() { Long staffId = staffHelper.createStaff().getResourceId(); List groupMembers = generateGroupMembers(3, officeId); Long resourceId = centerHelper.createCenter(name, officeId, externalId, staffId, groupMembers, null).getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(resourceId); + CenterData center = centerHelper.retrieveCenter(resourceId); assertNotNull(center); assertEquals(name, center.getName()); @@ -175,7 +174,7 @@ public void testCenterCreationWithoutExternalIdGeneratesOne() { Long officeId = officeHelper.createOffice(OFFICE_OPENING_DATE).getResourceId(); String name = "TestNoExternalId" + new Timestamp(new Date().getTime()); Long resourceId = centerHelper.createCenter(name, officeId).getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(resourceId); + CenterData center = centerHelper.retrieveCenter(resourceId); assertNotNull(center); assertNotNull(center.getExternalId()); @@ -188,8 +187,8 @@ public void testCenterCreationWithoutExternalIdGeneratesOne() { @Test public void testListCenters() { - List paginatedList = centerHelper.paginatedListCenters(); - List list = centerHelper.listCenters(); + List paginatedList = centerHelper.paginatedListCenters(); + List list = centerHelper.listCenters(); assertNotNull(paginatedList); assertNotNull(list); @@ -199,7 +198,7 @@ public void testListCenters() { @Test public void testVoidCenterRetrieval() { - List arr = centerHelper.listCentersOrdered(); + List arr = centerHelper.listCentersOrdered(); long nonExistentId = arr.get(arr.size() - 1).getId() + 1; assertEquals(NOT_FOUND, centerHelper.retrieveCenterExpectingError(nonExistentId).getStatus(), @@ -226,14 +225,14 @@ public void testCenterUpdate() { List newGroupMembers = new ArrayList<>(groupMembers); newGroupMembers.addAll(associateGroupMembers); - PutCentersCenterIdRequest request = new PutCentersCenterIdRequest().name(newName).externalId(newExternalId).staffId(newStaffId); - PutCentersChanges changes = centerHelper.updateCenter(resourceId, request); + CenterUpdateRequest request = new CenterUpdateRequest().name(newName).externalId(newExternalId).staffId(newStaffId); + Map changes = centerHelper.updateCenter(resourceId, request); assertNotNull(changes); - assertEquals(newName, changes.getName()); - assertEquals(newExternalId, changes.getExternalId()); - assertEquals(newStaffId, changes.getStaffId()); + assertEquals(newName, changes.get("name")); + assertEquals(newExternalId, changes.get("externalId")); + assertEquals(newStaffId, ((Number) changes.get("staffId")).longValue()); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(resourceId); + CenterData center = centerHelper.retrieveCenter(resourceId); assertNotNull(center); assertEquals(newName, center.getName()); assertEquals(newExternalId, center.getExternalId()); @@ -259,7 +258,7 @@ public void testStaffAssignmentDuringCenterCreation() { assertNotNull(staffId); Long centerId = centerHelper.createActiveCenterWithStaff(staffId).getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(centerId); + CenterData center = centerHelper.retrieveCenter(centerId); assertNotNull(center); assertEquals(centerId, center.getId()); assertEquals(staffId, center.getStaffId()); @@ -274,9 +273,10 @@ public void testAssignStaffToCenter() { Long centerId = centerHelper.createActiveCenter().getResourceId(); assertEquals(centerId, centerHelper.retrieveCenter(centerId).getId()); - assertEquals(staffId, centerHelper.assignStaff(centerId, staffId).getStaffId(), "Verify assigned staff id is the same as id sent"); + assertEquals(staffId, ((Number) centerHelper.assignStaff(centerId, staffId).get("staffId")).longValue(), + "Verify assigned staff id is the same as id sent"); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(centerId); + CenterData center = centerHelper.retrieveCenter(centerId); assertNotNull(center); assertEquals(centerId, center.getId()); assertEquals(staffId, center.getStaffId()); @@ -290,14 +290,15 @@ public void testUnassignStaffToCenter() { Long centerId = centerHelper.createActiveCenter().getResourceId(); assertEquals(centerId, centerHelper.retrieveCenter(centerId).getId()); - assertEquals(staffId, centerHelper.assignStaff(centerId, staffId).getStaffId(), "Verify assigned staff id is the same as id sent"); - GetCentersCenterIdResponse centerWithStaffAssigned = centerHelper.retrieveCenter(centerId); + assertEquals(staffId, ((Number) centerHelper.assignStaff(centerId, staffId).get("staffId")).longValue(), + "Verify assigned staff id is the same as id sent"); + CenterData centerWithStaffAssigned = centerHelper.retrieveCenter(centerId); assertNotNull(centerWithStaffAssigned); assertEquals(centerId, centerWithStaffAssigned.getId()); assertEquals(staffId, centerWithStaffAssigned.getStaffId()); - assertNull(centerHelper.unassignStaff(centerId, staffId).getStaffId(), "Verify staffId is null after unassigning"); - GetCentersCenterIdResponse centerWithStaffUnassigned = centerHelper.retrieveCenter(centerId); + assertNull(centerHelper.unassignStaff(centerId, staffId).get("staffId"), "Verify staffId is null after unassigning"); + CenterData centerWithStaffUnassigned = centerHelper.retrieveCenter(centerId); assertNotNull(centerWithStaffUnassigned); assertEquals(centerId, centerWithStaffUnassigned.getId()); assertNull(centerWithStaffUnassigned.getStaffId()); @@ -309,13 +310,13 @@ public void testCentersOrphanGroups() { String name = "TestBasicCreation" + new Timestamp(new Date().getTime()); Long resourceId = centerHelper.createCenter(name, officeId).getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(resourceId); + CenterData center = centerHelper.retrieveCenter(resourceId); assertNotNull(center); Long id = centerHelper.listCenters().get(0).getId(); assertTrue(id > 0); - GetCentersCenterIdResponse retrievedCenter = centerHelper.retrieveCenter(id); + CenterData retrievedCenter = centerHelper.retrieveCenter(id); assertNotNull(retrievedCenter); assertNotNull(retrievedCenter.getName()); assertNotNull(retrievedCenter.getHierarchy()); @@ -334,11 +335,11 @@ private List generateGroupMembers(int size, Long officeId) { return groupMembers; } - private static List groupMemberIds(GetCentersCenterIdResponse center) { - return center.getGroupMembers().stream().map(GetCentersGroupMembers::getId).toList(); + private static List groupMemberIds(CenterData center) { + return center.getGroupMembers().stream().map(GroupGeneralData::getId).toList(); } - private static List byId(List centers) { - return centers.stream().sorted(Comparator.comparing(GetCentersPageItems::getId)).toList(); + private static List byId(List centers) { + return centers.stream().sorted(Comparator.comparing(CenterData::getId)).toList(); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java index a82268d628e..57d0823353d 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/GroupTest.java @@ -25,9 +25,9 @@ import java.util.UUID; import org.apache.fineract.client.feign.FineractFeignClient; -import org.apache.fineract.client.models.GetGroupsGroupIdResponse; -import org.apache.fineract.client.models.PostGroupsRequest; -import org.apache.fineract.client.models.PostGroupsResponse; +import org.apache.fineract.client.models.GroupCreateRequest; +import org.apache.fineract.client.models.GroupCreateResponse; +import org.apache.fineract.client.models.GroupGeneralData; import org.apache.fineract.client.util.Calls; import org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants; import org.apache.fineract.integrationtests.client.feign.FeignLoanTestBase; @@ -86,10 +86,10 @@ public void testGroupCreationWithoutExternalIdGeneratesOne() { final GlobalConfigurationHelper globalConfigurationHelper = new GlobalConfigurationHelper(); globalConfigurationHelper.manageConfigurations(GlobalConfigurationConstants.ENABLE_AUTO_GENERATED_EXTERNAL_ID, true); try { - final PostGroupsRequest request = groupRequest(null); - final PostGroupsResponse response = Calls.ok(FineractClientHelper.getFineractClient().groups.createGroup(request)); + final GroupCreateRequest request = groupRequest(null); + final GroupCreateResponse response = Calls.ok(FineractClientHelper.getFineractClient().groups.createGroup(request)); - final GetGroupsGroupIdResponse group = Calls + final GroupGeneralData group = Calls .ok(FineractClientHelper.getFineractClient().groups.retrieveOneGroup(response.getGroupId(), false, null)); assertThat(group.getExternalId()).isNotBlank(); assertNotEquals("null", group.getExternalId()); @@ -101,16 +101,16 @@ public void testGroupCreationWithoutExternalIdGeneratesOne() { @Test public void testGroupCreationWithExternalIdIsPersisted() { final String externalId = UUID.randomUUID().toString(); - final PostGroupsRequest request = groupRequest(externalId); - final PostGroupsResponse response = Calls.ok(FineractClientHelper.getFineractClient().groups.createGroup(request)); + final GroupCreateRequest request = groupRequest(externalId); + final GroupCreateResponse response = Calls.ok(FineractClientHelper.getFineractClient().groups.createGroup(request)); - final GetGroupsGroupIdResponse group = Calls + final GroupGeneralData group = Calls .ok(FineractClientHelper.getFineractClient().groups.retrieveOneGroup(response.getGroupId(), false, null)); assertThat(group.getExternalId()).isEqualTo(externalId); } - private static PostGroupsRequest groupRequest(final String externalId) { - final PostGroupsRequest request = new PostGroupsRequest(); + private static GroupCreateRequest groupRequest(final String externalId) { + final GroupCreateRequest request = new GroupCreateRequest(); request.officeId(1L); request.name(GroupHelper.randomNameGenerator("Group_Name_", 5)); request.externalId(externalId); @@ -141,7 +141,8 @@ public void assignStaffToGroup() { assertNotNull(staffId2); // assign staff "staffId1" to the group - assertEquals(staffId1, groupHelper.assignStaff(groupId, staffId1).getStaffId(), "Verify assigned staff id is the same as id sent"); + assertEquals(staffId1, ((Number) groupHelper.assignStaff(groupId, staffId1).get("staffId")).longValue(), + "Verify assigned staff id is the same as id sent"); // assign staff "staffId2" to the client assertEquals(staffId2, clientHelper.assignStaffToClient(clientId, staffId2).getStaffId(), @@ -156,7 +157,8 @@ public void assignStaffToGroup() { disburseLoanWithNetDisbursalAmount(loanId, LOAN_DATE, getLoanDetails(loanId).getNetDisbursalAmount().toPlainString()); // assign staff "staffId1" to the group and cascade it to member client accounts - final Long inheritedStaffId = groupHelper.assignStaffInheritStaffForClientAccounts(groupId, staffId1).getStaffId(); + final Long inheritedStaffId = ((Number) groupHelper.assignStaffInheritStaffForClientAccounts(groupId, staffId1).get("staffId")) + .longValue(); // the client's staff officer changed away from staffId2 and now matches the inherited staff assertNotEquals(staffId2, inheritedStaffId, "Verify if client staff has changed"); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java index 9896740b204..aeb37246eff 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanReschedulingWithinCenterTest.java @@ -34,9 +34,9 @@ import java.util.UUID; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.feign.util.FeignCalls; +import org.apache.fineract.client.models.CenterData; import org.apache.fineract.client.models.ClientCollateralCreateRequest; import org.apache.fineract.client.models.CollateralProductCreateRequest; -import org.apache.fineract.client.models.GetCentersCenterIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.client.models.PostClientsRequest; @@ -97,7 +97,7 @@ public void testCenterReschedulingLoansWithInterestRecalculationEnabled() { final String centerActivationDate = "01 July 2007"; Long centerId = centerHelper.createCenter(name, officeId, externalId, Long.valueOf(staffId), List.of(groupId), centerActivationDate) .getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(centerId); + CenterData center = centerHelper.retrieveCenter(centerId); assertNotNull(center); assertEquals(staffId, center.getStaffId().intValue()); assertTrue(center.getActive()); @@ -167,7 +167,7 @@ public void testCenterReschedulingMultiTrancheLoansWithInterestRecalculationEnab final String centerActivationDate = "01 July 2007"; Long centerId = centerHelper.createCenter(name, officeId, externalId, Long.valueOf(staffId), List.of(groupId), centerActivationDate) .getResourceId(); - GetCentersCenterIdResponse center = centerHelper.retrieveCenter(centerId); + CenterData center = centerHelper.retrieveCenter(centerId); assertNotNull(center); assertEquals(staffId, center.getStaffId().intValue()); assertTrue(center.getActive()); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignCenterHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignCenterHelper.java index 0dd7f52724d..7b5e11ef6ea 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignCenterHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignCenterHelper.java @@ -26,18 +26,14 @@ import java.util.Map; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.feign.util.CallFailedRuntimeException; -import org.apache.fineract.client.models.DeleteCentersCenterIdResponse; -import org.apache.fineract.client.models.GetCentersCenterIdResponse; -import org.apache.fineract.client.models.GetCentersPageItems; -import org.apache.fineract.client.models.GetCentersResponse; -import org.apache.fineract.client.models.PostCentersCenterIdChanges; -import org.apache.fineract.client.models.PostCentersCenterIdRequest; -import org.apache.fineract.client.models.PostCentersRequest; -import org.apache.fineract.client.models.PostCentersResponse; -import org.apache.fineract.client.models.PostGroupsGroupIdChanges; -import org.apache.fineract.client.models.PostGroupsGroupIdRequest; -import org.apache.fineract.client.models.PutCentersCenterIdRequest; -import org.apache.fineract.client.models.PutCentersChanges; +import org.apache.fineract.client.models.CenterCommandRequest; +import org.apache.fineract.client.models.CenterCreateRequest; +import org.apache.fineract.client.models.CenterCreateResponse; +import org.apache.fineract.client.models.CenterData; +import org.apache.fineract.client.models.CenterDeleteResponse; +import org.apache.fineract.client.models.CenterUpdateRequest; +import org.apache.fineract.client.models.CentersPageResponse; +import org.apache.fineract.client.models.GroupCommandRequest; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; @@ -59,43 +55,43 @@ public FeignCenterHelper(FineractFeignClient fineractClient) { } /** Creates a center in {@code pending} status (active=false). */ - public PostCentersResponse createCenter(String name, Long officeId) { + public CenterCreateResponse createCenter(String name, Long officeId) { return createCenter(centerRequest(name, officeId, null, null, null, null)); } /** Creates an {@code active} center with the given activation date. */ - public PostCentersResponse createActiveCenter(String name, Long officeId, String activationDate) { + public CenterCreateResponse createActiveCenter(String name, Long officeId, String activationDate) { return createCenter(centerRequest(name, officeId, null, null, null, activationDate)); } /** Convenience: an {@code active} center in the default office (1) with a generated name. */ - public PostCentersResponse createActiveCenter() { + public CenterCreateResponse createActiveCenter() { return createActiveCenter(Utils.uniqueRandomStringGenerator("Center_Name_", 5), 1L, CREATED_DATE); } /** Convenience: an {@code active} center in the default office (1) with a generated name and the given staff. */ - public PostCentersResponse createActiveCenterWithStaff(Long staffId) { + public CenterCreateResponse createActiveCenterWithStaff(Long staffId) { return createCenter(centerRequest(Utils.uniqueRandomStringGenerator("Center_Name_", 5), 1L, null, staffId, null, CREATED_DATE)); } /** Creates a center with external id, staff and group members; active iff an {@code activationDate} is supplied. */ - public PostCentersResponse createCenter(String name, Long officeId, String externalId, Long staffId, List groupMembers, + public CenterCreateResponse createCenter(String name, Long officeId, String externalId, Long staffId, List groupMembers, String activationDate) { return createCenter(centerRequest(name, officeId, externalId, staffId, groupMembers, activationDate)); } - public PostCentersResponse createCenter(PostCentersRequest request) { + public CenterCreateResponse createCenter(CenterCreateRequest request) { return ok(() -> fineractClient.centers().createCenter(request)); } - public DeleteCentersCenterIdResponse deleteCenter(Long centerId) { + public CenterDeleteResponse deleteCenter(Long centerId) { return ok(() -> fineractClient.centers().deleteCenter(centerId)); } - private PostCentersRequest centerRequest(String name, Long officeId, String externalId, Long staffId, List groupMembers, + private CenterCreateRequest centerRequest(String name, Long officeId, String externalId, Long staffId, List groupMembers, String activationDate) { boolean active = activationDate != null; - PostCentersRequest request = new PostCentersRequest()// + CenterCreateRequest request = new CenterCreateRequest()// .name(name)// .officeId(officeId)// .active(active)// @@ -116,7 +112,7 @@ private PostCentersRequest centerRequest(String name, Long officeId, String exte return request; } - public GetCentersCenterIdResponse retrieveCenter(Long centerId) { + public CenterData retrieveCenter(Long centerId) { return ok(() -> fineractClient.centers().retrieveOneCenter(centerId, Map.of("associations", GROUP_MEMBERS_ASSOCIATION))); } @@ -125,43 +121,41 @@ public CallFailedRuntimeException retrieveCenterExpectingError(Long centerId) { return fail(() -> fineractClient.centers().retrieveOneCenter(centerId, Map.of("associations", GROUP_MEMBERS_ASSOCIATION))); } - public List listCenters() { + public List listCenters() { return ok(nonPagedListingApi::listCenters); } - public List listCentersOrdered() { + public List listCentersOrdered() { return ok(nonPagedListingApi::listCentersOrdered); } - public List paginatedListCenters() { - GetCentersResponse response = ok(() -> fineractClient.centers().retrieveAllCenters(Map.of("paged", true, "limit", -1))); + public List paginatedListCenters() { + CentersPageResponse response = ok(() -> fineractClient.centers().retrieveAllCenters(Map.of("paged", true, "limit", -1))); return response.getPageItems() == null ? List.of() : new ArrayList<>(response.getPageItems()); } - /** Updates a center with the given fields; returns the {@code changes} object. */ - public PutCentersChanges updateCenter(Long centerId, PutCentersCenterIdRequest request) { + public Map updateCenter(Long centerId, CenterUpdateRequest request) { return ok(() -> fineractClient.centers().updateCenter(centerId, request)).getChanges(); } /** Associates groups with the center; returns the associated group ids from the {@code changes} response. */ public List associateGroups(Long centerId, List groupMembers) { - PostCentersCenterIdChanges changes = ok(() -> fineractClient.centers().handleCommandsCenter(centerId, - new PostCentersCenterIdRequest().groupMembers(groupMembers), ASSOCIATE_GROUPS_COMMAND)).getChanges(); - return changes.getGroupMembers().stream().map(Long::valueOf).toList(); + Map changes = ok(() -> fineractClient.centers().handleCommandsCenter(centerId, + new CenterCommandRequest().groupMembers(groupMembers), ASSOCIATE_GROUPS_COMMAND)).getChanges(); + List changedGroupMembers = (List) changes.get("groupMembers"); + return changedGroupMembers.stream().map(item -> Long.valueOf((String) item)).toList(); } - /** Assigns a staff member to the center; returns the {@code changes} object. */ - public PostGroupsGroupIdChanges assignStaff(Long centerId, Long staffId) { - return postGroupCommand(centerId, ASSIGN_STAFF_COMMAND, new PostGroupsGroupIdRequest().staffId(staffId)); + public Map assignStaff(Long centerId, Long staffId) { + return postGroupCommand(centerId, ASSIGN_STAFF_COMMAND, new GroupCommandRequest().staffId(staffId)); } - /** Unassigns the staff member from the center; returns the {@code changes} object (staffId becomes null). */ - public PostGroupsGroupIdChanges unassignStaff(Long centerId, Long staffId) { - return postGroupCommand(centerId, UNASSIGN_STAFF_COMMAND, new PostGroupsGroupIdRequest().staffId(staffId)); + public Map unassignStaff(Long centerId, Long staffId) { + return postGroupCommand(centerId, UNASSIGN_STAFF_COMMAND, new GroupCommandRequest().staffId(staffId)); } // A center is a group server-side: the /centers command endpoint rejects assignStaff/unassignStaff. - private PostGroupsGroupIdChanges postGroupCommand(Long centerId, String command, PostGroupsGroupIdRequest request) { + private Map postGroupCommand(Long centerId, String command, GroupCommandRequest request) { return ok(() -> fineractClient.groups().handleCommandsGroup(centerId, request, Map.of("command", command))).getChanges(); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignGroupHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignGroupHelper.java index f31ac104c97..2e5a5b24715 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignGroupHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignGroupHelper.java @@ -22,19 +22,16 @@ import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import org.apache.fineract.client.feign.FineractFeignClient; -import org.apache.fineract.client.models.DeleteGroupsGroupIdResponse; -import org.apache.fineract.client.models.GetGroupsGroupIdClientMembers; -import org.apache.fineract.client.models.GetGroupsGroupIdResponse; -import org.apache.fineract.client.models.GetGroupsPageItems; -import org.apache.fineract.client.models.PostGroupsGroupIdChanges; -import org.apache.fineract.client.models.PostGroupsGroupIdRequest; -import org.apache.fineract.client.models.PostGroupsRequest; -import org.apache.fineract.client.models.PostGroupsResponse; -import org.apache.fineract.client.models.PutGroupsGroupIdRequest; -import org.apache.fineract.client.models.PutGroupsGroupIdResponse; +import org.apache.fineract.client.models.ClientData; +import org.apache.fineract.client.models.GroupCommandRequest; +import org.apache.fineract.client.models.GroupCreateRequest; +import org.apache.fineract.client.models.GroupCreateResponse; +import org.apache.fineract.client.models.GroupDeleteResponse; +import org.apache.fineract.client.models.GroupGeneralData; +import org.apache.fineract.client.models.GroupUpdateRequest; +import org.apache.fineract.client.models.GroupUpdateResponse; import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.Utils; @@ -60,13 +57,13 @@ public FeignGroupHelper(FineractFeignClient fineractClient) { } /** Creates a group in {@code pending} status (active=false) in the default office. */ - public PostGroupsResponse createGroup() { + public GroupCreateResponse createGroup() { return createGroup(DEFAULT_OFFICE_ID); } /** Creates a group in {@code pending} status (active=false). */ - public PostGroupsResponse createGroup(Long officeId) { - PostGroupsRequest request = new PostGroupsRequest()// + public GroupCreateResponse createGroup(Long officeId) { + GroupCreateRequest request = new GroupCreateRequest()// .officeId(officeId)// .name(Utils.uniqueRandomStringGenerator("Group_Name_", 5))// .externalId(UUID.randomUUID().toString())// @@ -78,12 +75,12 @@ public PostGroupsResponse createGroup(Long officeId) { } /** Creates an {@code active} group in the default office. */ - public PostGroupsResponse createActiveGroup() { + public GroupCreateResponse createActiveGroup() { return createActiveGroup(DEFAULT_OFFICE_ID, DEFAULT_ACTIVATION_DATE); } - public PostGroupsResponse createActiveGroup(Long officeId, String activationDate) { - PostGroupsRequest request = new PostGroupsRequest()// + public GroupCreateResponse createActiveGroup(Long officeId, String activationDate) { + GroupCreateRequest request = new GroupCreateRequest()// .officeId(officeId)// .name(Utils.uniqueRandomStringGenerator("Group_Name_", 5))// .externalId(UUID.randomUUID().toString())// @@ -94,27 +91,27 @@ public PostGroupsResponse createActiveGroup(Long officeId, String activationDate return createGroup(request); } - public PostGroupsResponse createGroup(PostGroupsRequest request) { + public GroupCreateResponse createGroup(GroupCreateRequest request) { return ok(() -> fineractClient.groups().createGroup(request)); } - public GetGroupsGroupIdResponse retrieveGroup(Long groupId) { + public GroupGeneralData retrieveGroup(Long groupId) { Map params = Map.of(); return ok(() -> fineractClient.groups().retrieveOneGroup(groupId, params)); } /** Retrieves a group with the given {@code associations} (e.g. {@code clientMembers}, {@code all}). */ - public GetGroupsGroupIdResponse retrieveGroupWithAssociations(Long groupId, String associations) { + public GroupGeneralData retrieveGroupWithAssociations(Long groupId, String associations) { Map params = Map.of("associations", associations); return ok(() -> fineractClient.groups().retrieveOneGroup(groupId, params)); } - public PutGroupsGroupIdResponse updateGroup(Long groupId, String name) { - PutGroupsGroupIdRequest request = new PutGroupsGroupIdRequest().name(name); + public GroupUpdateResponse updateGroup(Long groupId, String name) { + GroupUpdateRequest request = new GroupUpdateRequest().name(name); return ok(() -> fineractClient.groups().updateGroup(groupId, request)); } - public DeleteGroupsGroupIdResponse deleteGroup(Long groupId) { + public GroupDeleteResponse deleteGroup(Long groupId) { return ok(() -> fineractClient.groups().deleteGroup(groupId)); } @@ -123,7 +120,7 @@ public void activateGroup(Long groupId) { } public void activateGroup(Long groupId, String activationDate) { - PostGroupsGroupIdRequest request = new PostGroupsGroupIdRequest()// + GroupCommandRequest request = new GroupCommandRequest()// .activationDate(activationDate)// .dateFormat(LoanTestData.DATETIME_PATTERN)// .locale(LoanTestData.LOCALE); @@ -131,25 +128,23 @@ public void activateGroup(Long groupId, String activationDate) { } public void associateClient(Long groupId, Long clientId) { - postGroupCommand(groupId, ASSOCIATE_CLIENTS_COMMAND, new PostGroupsGroupIdRequest().clientMembers(List.of(clientId))); + postGroupCommand(groupId, ASSOCIATE_CLIENTS_COMMAND, new GroupCommandRequest().clientMembers(List.of(clientId))); } public void disAssociateClient(Long groupId, Long clientId) { - postGroupCommand(groupId, DISASSOCIATE_CLIENTS_COMMAND, new PostGroupsGroupIdRequest().clientMembers(List.of(clientId))); + postGroupCommand(groupId, DISASSOCIATE_CLIENTS_COMMAND, new GroupCommandRequest().clientMembers(List.of(clientId))); } - /** Assigns a staff member to the group; returns the {@code changes} object (contains {@code staffId}). */ - public PostGroupsGroupIdChanges assignStaff(Long groupId, Long staffId) { - return postGroupCommand(groupId, ASSIGN_STAFF_COMMAND, new PostGroupsGroupIdRequest().staffId(staffId)); + public Map assignStaff(Long groupId, Long staffId) { + return postGroupCommand(groupId, ASSIGN_STAFF_COMMAND, new GroupCommandRequest().staffId(staffId)); } - /** Assigns staff to the group and cascades it to member client accounts; returns the {@code changes} object. */ - public PostGroupsGroupIdChanges assignStaffInheritStaffForClientAccounts(Long groupId, Long staffId) { - PostGroupsGroupIdRequest request = new PostGroupsGroupIdRequest().staffId(staffId).inheritStaffForClientAccounts(true); + public Map assignStaffInheritStaffForClientAccounts(Long groupId, Long staffId) { + GroupCommandRequest request = new GroupCommandRequest().staffId(staffId).inheritStaffForClientAccounts(true); return postGroupCommand(groupId, ASSIGN_STAFF_COMMAND, request); } - private PostGroupsGroupIdChanges postGroupCommand(Long groupId, String command, PostGroupsGroupIdRequest request) { + private Map postGroupCommand(Long groupId, String command, GroupCommandRequest request) { return ok(() -> fineractClient.groups().handleCommandsGroup(groupId, request, Map.of("command", command))).getChanges(); } @@ -157,7 +152,7 @@ private PostGroupsGroupIdChanges postGroupCommand(Long groupId, String command, * The office's groups that have no center as parent. Must stay on the non-paged listing, see * {@link NonPagedListingApi}. */ - public List retrieveOrphanGroups(Long officeId) { + public List retrieveOrphanGroups(Long officeId) { return ok(() -> nonPagedListingApi.listOrphanGroups(officeId)); } @@ -168,7 +163,7 @@ public boolean isGroupActive(Long groupId) { /** The client-member ids associated with the group (empty if none). */ public List retrieveGroupMemberIds(Long groupId) { - Set members = retrieveGroupWithAssociations(groupId, CLIENT_MEMBERS_ASSOCIATION).getClientMembers(); - return members == null ? List.of() : members.stream().map(GetGroupsGroupIdClientMembers::getId).toList(); + List members = retrieveGroupWithAssociations(groupId, CLIENT_MEMBERS_ASSOCIATION).getClientMembers(); + return members == null ? List.of() : members.stream().map(ClientData::getId).toList(); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/NonPagedListingApi.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/NonPagedListingApi.java index 9807810463d..c9071c31d9f 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/NonPagedListingApi.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/NonPagedListingApi.java @@ -22,8 +22,8 @@ import feign.Param; import feign.RequestLine; import java.util.List; -import org.apache.fineract.client.models.GetCentersPageItems; -import org.apache.fineract.client.models.GetGroupsPageItems; +import org.apache.fineract.client.models.CenterData; +import org.apache.fineract.client.models.GroupGeneralData; /** * Feign interface for the non-paged variants of {@code GET /centers} and {@code GET /groups}, which answer a bare JSON @@ -35,11 +35,11 @@ public interface NonPagedListingApi { @RequestLine("GET /v1/centers?limit=-1") - List listCenters(); + List listCenters(); @RequestLine("GET /v1/centers?limit=-1&orderBy=id&sortOrder=asc") - List listCentersOrdered(); + List listCentersOrdered(); @RequestLine("GET /v1/groups?officeId={officeId}&orphansOnly=true") - List listOrphanGroups(@Param("officeId") Long officeId); + List listOrphanGroups(@Param("officeId") Long officeId); }