Skip to content

Commit af715a6

Browse files
authored
Merge pull request #5766 from symbaglobal/FINERACT-2588
FINERACT-2588: Include transactionId in payCharge response for Savings Account
2 parents 64b21ef + 9eed765 commit af715a6

2 files changed

Lines changed: 135 additions & 13 deletions

File tree

fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,6 +1431,7 @@ public CommandProcessingResult payCharge(final Long savingsAccountId, final Long
14311431
.withClientId(savingsAccountCharge.savingsAccount().clientId()) //
14321432
.withGroupId(savingsAccountCharge.savingsAccount().groupId()) //
14331433
.withSavingsId(savingsAccountCharge.savingsAccount().getId()) //
1434+
.withTransactionId(chargeTransaction.getId().toString()) //
14341435
.build();
14351436

14361437
}

fineract-provider/src/test/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImplTest.java

Lines changed: 134 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,34 @@
2121
import static org.assertj.core.api.Assertions.assertThat;
2222
import static org.assertj.core.api.Assertions.assertThatNoException;
2323
import static org.assertj.core.api.Assertions.assertThatThrownBy;
24+
import static org.mockito.ArgumentMatchers.any;
25+
import static org.mockito.ArgumentMatchers.anyBoolean;
26+
import static org.mockito.ArgumentMatchers.anyLong;
2427
import static org.mockito.Mockito.mock;
2528
import static org.mockito.Mockito.when;
2629

2730
import java.lang.reflect.InvocationTargetException;
2831
import java.lang.reflect.Method;
32+
import java.math.BigDecimal;
2933
import java.time.LocalDate;
34+
import java.util.Collections;
35+
import java.util.HashMap;
36+
import java.util.HashSet;
3037
import java.util.List;
38+
import java.util.Map;
3139
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
40+
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
3241
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
42+
import org.apache.fineract.infrastructure.core.api.JsonCommand;
43+
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
3344
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
3445
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
46+
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
3547
import org.apache.fineract.infrastructure.dataqueries.service.EntityDatatableChecksWritePlatformService;
3648
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
3749
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
3850
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
51+
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
3952
import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper;
4053
import org.apache.fineract.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
4154
import org.apache.fineract.portfolio.account.domain.StandingInstructionRepository;
@@ -51,34 +64,87 @@
5164
import org.apache.fineract.portfolio.savings.domain.GSIMRepositoy;
5265
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
5366
import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
67+
import org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge;
5468
import org.apache.fineract.portfolio.savings.domain.SavingsAccountChargeRepositoryWrapper;
5569
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
5670
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
5771
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
5872
import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper;
5973
import org.junit.jupiter.api.BeforeEach;
6074
import org.junit.jupiter.api.Test;
75+
import org.junit.jupiter.api.extension.ExtendWith;
76+
import org.mockito.InjectMocks;
77+
import org.mockito.Mock;
78+
import org.mockito.junit.jupiter.MockitoExtension;
79+
import org.mockito.junit.jupiter.MockitoSettings;
80+
import org.mockito.quality.Strictness;
6181

82+
@ExtendWith(MockitoExtension.class)
83+
@MockitoSettings(strictness = Strictness.LENIENT)
6284
class SavingsAccountWritePlatformServiceJpaRepositoryImplTest {
6385

86+
@Mock
87+
private PlatformSecurityContext context;
88+
@Mock
89+
private SavingsAccountDataValidator fromApiJsonDeserializer;
90+
@Mock
91+
private SavingsAccountRepositoryWrapper savingAccountRepositoryWrapper;
92+
@Mock
93+
private StaffRepositoryWrapper staffRepository;
94+
@Mock
95+
private SavingsAccountTransactionRepository savingsAccountTransactionRepository;
96+
@Mock
97+
private SavingsAccountAssembler savingAccountAssembler;
98+
@Mock
99+
private SavingsAccountTransactionDataValidator savingsAccountTransactionDataValidator;
100+
@Mock
101+
private SavingsAccountChargeDataValidator savingsAccountChargeDataValidator;
102+
@Mock
103+
private PaymentDetailWritePlatformService paymentDetailWritePlatformService;
104+
@Mock
105+
private JournalEntryWritePlatformService journalEntryWritePlatformService;
106+
@Mock
107+
private SavingsAccountDomainService savingsAccountDomainService;
108+
@Mock
109+
private NoteRepository noteRepository;
110+
@Mock
111+
private AccountTransfersReadPlatformService accountTransfersReadPlatformService;
112+
@Mock
113+
private AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
114+
@Mock
115+
private ChargeRepositoryWrapper chargeRepository;
116+
@Mock
117+
private SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository;
118+
@Mock
119+
private HolidayRepositoryWrapper holidayRepository;
120+
@Mock
121+
private WorkingDaysRepositoryWrapper workingDaysRepository;
122+
@Mock
123+
private ConfigurationDomainService configurationDomainService;
124+
@Mock
125+
private DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
126+
@Mock
127+
private EntityDatatableChecksWritePlatformService entityDatatableChecksWritePlatformService;
128+
@Mock
129+
private AppUserRepositoryWrapper appuserRepository;
130+
@Mock
131+
private StandingInstructionRepository standingInstructionRepository;
132+
@Mock
133+
private BusinessEventNotifierService businessEventNotifierService;
134+
@Mock
135+
private GSIMRepositoy gsimRepository;
136+
@Mock
137+
private SavingsAccountInterestPostingService savingsAccountInterestPostingService;
138+
@Mock
139+
private ErrorHandler errorHandler;
140+
141+
@InjectMocks
64142
private SavingsAccountWritePlatformServiceJpaRepositoryImpl service;
143+
65144
private Method validateTransactionsForTransfer;
66145

67146
@BeforeEach
68147
void setUp() throws Exception {
69-
service = new SavingsAccountWritePlatformServiceJpaRepositoryImpl(mock(PlatformSecurityContext.class),
70-
mock(SavingsAccountDataValidator.class), mock(SavingsAccountRepositoryWrapper.class), mock(StaffRepositoryWrapper.class),
71-
mock(SavingsAccountTransactionRepository.class), mock(SavingsAccountAssembler.class),
72-
mock(SavingsAccountTransactionDataValidator.class), mock(SavingsAccountChargeDataValidator.class),
73-
mock(PaymentDetailWritePlatformService.class), mock(JournalEntryWritePlatformService.class),
74-
mock(SavingsAccountDomainService.class), mock(NoteRepository.class), mock(AccountTransfersReadPlatformService.class),
75-
mock(AccountAssociationsReadPlatformService.class), mock(ChargeRepositoryWrapper.class),
76-
mock(SavingsAccountChargeRepositoryWrapper.class), mock(HolidayRepositoryWrapper.class),
77-
mock(WorkingDaysRepositoryWrapper.class), mock(ConfigurationDomainService.class),
78-
mock(DepositAccountOnHoldTransactionRepository.class), mock(EntityDatatableChecksWritePlatformService.class),
79-
mock(AppUserRepositoryWrapper.class), mock(StandingInstructionRepository.class), mock(BusinessEventNotifierService.class),
80-
mock(GSIMRepositoy.class), mock(SavingsAccountInterestPostingService.class), mock(ErrorHandler.class));
81-
82148
validateTransactionsForTransfer = SavingsAccountWritePlatformServiceJpaRepositoryImpl.class
83149
.getDeclaredMethod("validateTransactionsForTransfer", SavingsAccount.class, LocalDate.class);
84150
validateTransactionsForTransfer.setAccessible(true);
@@ -158,4 +224,59 @@ void validateTransactionsForTransfer_transactionDateBeforeTransferDate_doesNotTh
158224

159225
assertThatNoException().isThrownBy(() -> validateTransactionsForTransfer.invoke(service, savingsAccount, transferDate));
160226
}
227+
228+
@Test
229+
void payCharge_shouldReturnTransactionIdInResult() {
230+
// Given
231+
final Long savingsAccountId = 1L;
232+
final Long chargeId = 2L;
233+
final Long expectedTransactionId = 42L;
234+
final LocalDate transactionDate = LocalDate.of(2024, 3, 15);
235+
236+
ThreadLocalContextUtil.setBusinessDates(new HashMap<>(Map.of(BusinessDateType.BUSINESS_DATE, transactionDate)));
237+
238+
JsonCommand command = mock(JsonCommand.class);
239+
when(command.json()).thenReturn("{}");
240+
when(command.extractLocale()).thenReturn(java.util.Locale.ENGLISH);
241+
when(command.dateFormat()).thenReturn("dd MMMM yyyy");
242+
when(command.bigDecimalValueOfParameterNamed("amount")).thenReturn(BigDecimal.TEN);
243+
when(command.localDateValueOfParameterNamed("dueAsOfDate")).thenReturn(transactionDate);
244+
when(command.stringValueOfParameterNamed("note")).thenReturn(null);
245+
246+
SavingsAccount savingsAccount = mock(SavingsAccount.class);
247+
when(savingsAccount.getId()).thenReturn(savingsAccountId);
248+
when(savingsAccount.officeId()).thenReturn(1L);
249+
when(savingsAccount.clientId()).thenReturn(1L);
250+
when(savingsAccount.groupId()).thenReturn(1L);
251+
when(savingsAccount.findExistingTransactionIds()).thenReturn(new HashSet<>());
252+
when(savingsAccount.findExistingReversedTransactionIds()).thenReturn(new HashSet<>());
253+
when(savingsAccount.getOnHoldFunds()).thenReturn(BigDecimal.ZERO);
254+
when(savingsAccount.isBeforeLastPostingPeriod(any(LocalDate.class), anyBoolean())).thenReturn(false);
255+
MonetaryCurrency currency = mock(MonetaryCurrency.class);
256+
when(currency.getCode()).thenReturn("USD");
257+
when(savingsAccount.getCurrency()).thenReturn(currency);
258+
when(savingsAccount.deriveAccountingBridgeData(any(), any(), any(), anyBoolean(), anyBoolean())).thenReturn(new HashMap<>());
259+
260+
SavingsAccountCharge savingsAccountCharge = mock(SavingsAccountCharge.class);
261+
when(savingsAccountCharge.getId()).thenReturn(chargeId);
262+
when(savingsAccountCharge.savingsAccount()).thenReturn(savingsAccount);
263+
264+
SavingsAccountTransaction chargeTransaction = mock(SavingsAccountTransaction.class);
265+
when(chargeTransaction.getId()).thenReturn(expectedTransactionId);
266+
267+
when(savingsAccountChargeRepository.findOneWithNotFoundDetection(chargeId, savingsAccountId)).thenReturn(savingsAccountCharge);
268+
when(configurationDomainService.allowTransactionsOnHolidayEnabled()).thenReturn(true);
269+
when(configurationDomainService.allowTransactionsOnNonWorkingDayEnabled()).thenReturn(true);
270+
when(configurationDomainService.isSavingsInterestPostingAtCurrentPeriodEnd()).thenReturn(false);
271+
when(configurationDomainService.retrieveFinancialYearBeginningMonth()).thenReturn(1);
272+
when(savingsAccountTransactionRepository.findBySavingsAccountIdAndLessThanDateOfAndReversedIsFalse(anyLong(), any(LocalDate.class),
273+
any())).thenReturn(Collections.emptyList());
274+
when(savingsAccount.payCharge(any(), any(), any(), any(), anyBoolean(), any())).thenReturn(chargeTransaction);
275+
276+
// When
277+
CommandProcessingResult result = service.payCharge(savingsAccountId, chargeId, command);
278+
279+
// Then
280+
assertThat(result.getTransactionId()).isEqualTo(expectedTransactionId.toString());
281+
}
161282
}

0 commit comments

Comments
 (0)