Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.infrastructure.event.business.domain.client;

import org.apache.fineract.portfolio.client.domain.Client;

public class ClientCloseBusinessEvent extends ClientBusinessEvent {

private static final String TYPE = "ClientCloseBusinessEvent";

public ClientCloseBusinessEvent(Client value) {
super(value);
}

@Override
public String getType() {
return TYPE;
}
}
Original file line number Diff line number Diff line change
@@ -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.infrastructure.event.business.domain.client;

import org.apache.fineract.portfolio.client.domain.Client;

public class ClientReactivateBusinessEvent extends ClientBusinessEvent {

private static final String TYPE = "ClientReactivateBusinessEvent";

public ClientReactivateBusinessEvent(Client value) {
super(value);
}

@Override
public String getType() {
return TYPE;
}
}
Original file line number Diff line number Diff line change
@@ -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.infrastructure.event.business.domain.client;

import org.apache.fineract.portfolio.client.domain.Client;

public class ClientUndoRejectionBusinessEvent extends ClientBusinessEvent {

private static final String TYPE = "ClientUndoRejectionBusinessEvent";

public ClientUndoRejectionBusinessEvent(Client value) {
super(value);
}

@Override
public String getType() {
return TYPE;
}
}
Original file line number Diff line number Diff line change
@@ -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.infrastructure.event.business.domain.client;

import org.apache.fineract.portfolio.client.domain.Client;

public class ClientUndoWithdrawalBusinessEvent extends ClientBusinessEvent {

private static final String TYPE = "ClientUndoWithdrawalBusinessEvent";

public ClientUndoWithdrawalBusinessEvent(Client value) {
super(value);
}

@Override
public String getType() {
return TYPE;
}
}
Original file line number Diff line number Diff line change
@@ -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.infrastructure.event.business.domain.client;

import org.apache.fineract.portfolio.client.domain.Client;

public class ClientWithdrawBusinessEvent extends ClientBusinessEvent {

private static final String TYPE = "ClientWithdrawBusinessEvent";

public ClientWithdrawBusinessEvent(Client value) {
super(value);
}

@Override
public String getType() {
return TYPE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
Expand All @@ -52,8 +51,13 @@
import org.apache.fineract.infrastructure.dataqueries.data.StatusEnum;
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientActivateBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientCloseBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientCreateBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientReactivateBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientRejectBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientUndoRejectionBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientUndoWithdrawalBusinessEvent;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientWithdrawBusinessEvent;
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;
Expand Down Expand Up @@ -91,12 +95,13 @@
import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException;
import org.apache.fineract.portfolio.savings.service.SavingsApplicationProcessWritePlatformService;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@AllArgsConstructor
@Service
@Slf4j
public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWritePlatformService {
Expand Down Expand Up @@ -125,6 +130,47 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
private final ExternalIdFactory externalIdFactory;

@Autowired
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final ClientRepositoryWrapper clientRepository, final ClientNonPersonRepositoryWrapper clientNonPersonRepository,
final OfficeRepositoryWrapper officeRepositoryWrapper, final NoteRepository noteRepository,
final GroupRepository groupRepository, final ClientDataValidator fromApiJsonDeserializer,
final AccountNumberGenerator accountNumberGenerator, final StaffRepositoryWrapper staffRepository,
final CodeValueRepositoryWrapper codeValueRepository, final LoanRepositoryWrapper loanRepositoryWrapper,
final SavingsAccountRepositoryWrapper savingsRepositoryWrapper, final SavingsProductRepository savingsProductRepository,
final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService,
final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService,
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, final FromJsonHelper fromApiJsonHelper,
final AddressWritePlatformService addressWritePlatformService,
final ClientFamilyMembersWritePlatformService clientFamilyMembersWritePlatformService,
@Lazy final BusinessEventNotifierService businessEventNotifierService, // BREAKS THE CYCLE
final EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService,
final ExternalIdFactory externalIdFactory) {
this.context = context;
this.clientRepository = clientRepository;
this.clientNonPersonRepository = clientNonPersonRepository;
this.officeRepositoryWrapper = officeRepositoryWrapper;
this.noteRepository = noteRepository;
this.groupRepository = groupRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.accountNumberGenerator = accountNumberGenerator;
this.staffRepository = staffRepository;
this.codeValueRepository = codeValueRepository;
this.loanRepositoryWrapper = loanRepositoryWrapper;
this.savingsRepositoryWrapper = savingsRepositoryWrapper;
this.savingsProductRepository = savingsProductRepository;
this.savingsApplicationProcessWritePlatformService = savingsApplicationProcessWritePlatformService;
this.commandProcessingService = commandProcessingService;
this.configurationDomainService = configurationDomainService;
this.accountNumberFormatRepository = accountNumberFormatRepository;
this.fromApiJsonHelper = fromApiJsonHelper;
this.addressWritePlatformService = addressWritePlatformService;
this.clientFamilyMembersWritePlatformService = clientFamilyMembersWritePlatformService;
this.businessEventNotifierService = businessEventNotifierService;
this.entityDatatableChecksWritePlatformService = entityDatatableChecksWritePlatformService;
this.externalIdFactory = externalIdFactory;
}

@Transactional
@Override
public CommandProcessingResult deleteClient(final Long clientId) {
Expand Down Expand Up @@ -885,6 +931,7 @@ public CommandProcessingResult closeClient(final Long clientId, final JsonComman

client.close(currentUser, closureReason, closureDate);
this.clientRepository.saveAndFlush(client);
businessEventNotifierService.notifyPostBusinessEvent(new ClientCloseBusinessEvent(client));
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withClientId(clientId) //
Expand Down Expand Up @@ -1014,6 +1061,7 @@ public CommandProcessingResult withdrawClient(Long entityId, JsonCommand command
}
client.withdraw(currentUser, withdrawalReason, withdrawalDate);
this.clientRepository.saveAndFlush(client);
businessEventNotifierService.notifyPostBusinessEvent(new ClientWithdrawBusinessEvent(client));
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withClientId(entityId) //
Expand All @@ -1040,6 +1088,7 @@ public CommandProcessingResult reActivateClient(Long entityId, JsonCommand comma
}
client.reActivate(currentUser, reactivateDate);
this.clientRepository.saveAndFlush(client);
businessEventNotifierService.notifyPostBusinessEvent(new ClientReactivateBusinessEvent(client));
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withClientId(entityId) //
Expand Down Expand Up @@ -1067,7 +1116,7 @@ public CommandProcessingResult undoRejection(Long entityId, JsonCommand command)

client.reOpened(currentUser, undoRejectDate);
this.clientRepository.saveAndFlush(client);

businessEventNotifierService.notifyPostBusinessEvent(new ClientUndoRejectionBusinessEvent(client));
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withClientId(entityId) //
Expand All @@ -1094,7 +1143,7 @@ public CommandProcessingResult undoWithdrawal(Long entityId, JsonCommand command
}
client.reOpened(currentUser, undoWithdrawalDate);
this.clientRepository.saveAndFlush(client);

businessEventNotifierService.notifyPostBusinessEvent(new ClientUndoWithdrawalBusinessEvent(client));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add unit tests for these function for coverage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aman-Mittal I have added the unit tests for the Client lifecycle events in ClientWritePlatformServiceJpaRepositoryImplTest.java to ensure logic coverage as requested.

return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withClientId(entityId) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,3 +574,4 @@ resilience4j.retry.instances.commandAuditFallback.wait-duration=${FINERACT_PROCE
resilience4j.retry.instances.commandAuditFallback.enable-exponential-backoff=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_ENABLE_EXPONENTIAL_BACKOFF:true}
resilience4j.retry.instances.commandAuditFallback.exponential-backoff-multiplier=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_EXPONENTIAL_BACKOFF_MULTIPLIER:2}
resilience4j.retry.instances.commandAuditFallback.retryExceptions=${FINERACT_PROCESS_COMMAND_AUDIT_FALLBACK_RETRY_EXCEPTIONS:org.springframework.dao.ConcurrencyFailureException,org.eclipse.persistence.exceptions.OptimisticLockException,jakarta.persistence.OptimisticLockException,org.springframework.orm.jpa.JpaOptimisticLockingFailureException}
fineract.events.external.enabled=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* 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.client.service;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.time.LocalDate;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.event.business.domain.client.ClientUndoWithdrawalBusinessEvent;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.portfolio.client.data.ClientDataValidator;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.useradministration.domain.AppUser;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class ClientWritePlatformServiceJpaRepositoryImplTest {

@Mock
private ClientRepositoryWrapper clientRepository;

@Mock
private BusinessEventNotifierService businessEventNotifierService;

@Mock
private PlatformSecurityContext context;

@Mock
private ClientDataValidator fromApiJsonDeserializer;

@InjectMocks
private ClientWritePlatformServiceJpaRepositoryImpl underTest;

@Test
public void testUndoWithdrawalFiresBusinessEvent() {
Long clientId = 1L;
Client client = mock(Client.class);
AppUser currentUser = mock(AppUser.class);
JsonCommand command = mock(JsonCommand.class);
LocalDate dummyDate = LocalDate.now();
when(clientRepository.findOneWithNotFoundDetection(clientId)).thenReturn(client);
when(context.authenticatedUser()).thenReturn(currentUser);
when(command.localDateValueOfParameterNamed(any(String.class))).thenReturn(dummyDate);
when(client.isWithdrawn()).thenReturn(true);
this.underTest.undoWithdrawal(clientId, command);
verify(businessEventNotifierService).notifyPostBusinessEvent(any(ClientUndoWithdrawalBusinessEvent.class));
verify(clientRepository).saveAndFlush(client);
}
}
Loading