Skip to content
Open
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
Expand Up @@ -39,4 +39,15 @@ private StandingInstructionApiConstants() {
public static final String recurrenceOnMonthDayParamName = "recurrenceOnMonthDay";
public static final String monthDayFormatParamName = "monthDayFormat";

public static final String INVALID_MONTH_DAY_FORMAT_ERROR_CODE = "invalid.month.day.format";
public static final String BEFORE_FIRST_EXECUTION_DATE_ERROR_CODE = "must.not.be.before.first.execution.date";
public static final String AMOUNT_NOT_ALLOWED_FOR_DUES_ERROR_CODE = "not.allowed.for.dues.instruction";
public static final String CANNOT_TRANSFER_TO_SAME_ACCOUNT_ERROR_CODE = "transfer.to.same.account.not.allowed";
public static final String INSTRUCTION_TYPE_DUES_NOT_ALLOWED_FOR_ACCOUNT_TRANSFER_ERROR_CODE = "dues.not.allowed.for.account.transfer";
public static final String RECURRENCE_AS_PER_DUES_NOT_ALLOWED_FOR_SAVINGS_ERROR_CODE = "as.per.dues.not.allowed.for.account.transfer";
public static final String ACCOUNT_TRANSFER_NOT_ALLOWED_FOR_LOAN_ERROR_CODE = "account.transfer.is.not.allowed.for.loan.accounts";
public static final String RECURRENCE_AS_PER_DUES_NOT_ALLOWED_WITH_FIXED_INSTRUCTION_ERROR_CODE = "as.per.dues.not.allowed.with.fixed.amount";
public static final String NOT_A_VALID_LOAN_REPAYMENT_ERROR_CODE = "is.not.a.valid.loan.repayment";
public static final String MUST_BE_BEFORE_EXISTING_VALID_TILL_ERROR_CODE = "must.be.before.existing.valid.till";
public static final String CANNOT_BE_BEFORE_LAST_RUN_DATE_ERROR_CODE = "cannot.be.before.last.run.date";
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,29 @@
* Immutable data object representing a savings account.
*/
@SuppressWarnings("unused")
@Getter
public final class StandingInstructionData {

@Getter
private final Long id;
@Getter
private final Long accountDetailId;
@Getter
private final String name;
private final OfficeData fromOffice;
@Getter
private final ClientData fromClient;
private final EnumOptionData fromAccountType;
@Getter
private final PortfolioAccountData fromAccount;
private final OfficeData toOffice;
@Getter
private final ClientData toClient;
private final EnumOptionData toAccountType;
@Getter
private final PortfolioAccountData toAccount;
private final EnumOptionData transferType;
private final EnumOptionData priority;
private final EnumOptionData instructionType;
@Getter
private final EnumOptionData status;
@Getter
private final BigDecimal amount;
@Getter
private final LocalDate validFrom;
private final LocalDate validTill;
private final EnumOptionData recurrenceType;
private final EnumOptionData recurrenceFrequency;
@Getter
private final Integer recurrenceInterval;
private final MonthDay recurrenceOnMonthDay;
private final Page<AccountTransferData> transactions;
Expand Down Expand Up @@ -326,4 +316,11 @@ public Integer toTransferType() {
return transferType;
}

public Collection<EnumOptionData> getRecurrenceFrequencyOptions() {
if (this.recurrenceFrequencyOptions == null) {
return null;
}
return this.recurrenceFrequencyOptions.stream().filter(option -> option.getId() != null && option.getId() < 4)
.collect(java.util.stream.Collectors.toList());
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import jakarta.persistence.Table;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
import org.apache.fineract.organisation.office.domain.Office;
import org.apache.fineract.portfolio.client.domain.Client;
Expand All @@ -37,6 +38,7 @@

@Entity
@Table(name = "m_account_transfer_details")
@Getter
public class AccountTransferDetails extends AbstractPersistableCustom<Long> {

@ManyToOne
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
package org.apache.fineract.portfolio.account.domain;

import static org.apache.fineract.portfolio.account.AccountDetailConstants.transferTypeParamName;
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.ACCOUNT_TRANSFER_NOT_ALLOWED_FOR_LOAN_ERROR_CODE;
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.AMOUNT_NOT_ALLOWED_FOR_DUES_ERROR_CODE;
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.NOT_A_VALID_LOAN_REPAYMENT_ERROR_CODE;
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.STANDING_INSTRUCTION_RESOURCE_NAME;
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.amountParamName;
import static org.apache.fineract.portfolio.account.api.StandingInstructionApiConstants.instructionTypeParamName;
Expand All @@ -44,6 +47,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
Expand All @@ -54,6 +58,7 @@
@Entity
@Table(name = "m_account_transfer_standing_instructions", uniqueConstraints = {
@UniqueConstraint(columnNames = { "name" }, name = "name") })
@Getter
public class AccountTransferStandingInstruction extends AbstractPersistableCustom<Long> {

@ManyToOne
Expand Down Expand Up @@ -97,7 +102,7 @@ public class AccountTransferStandingInstruction extends AbstractPersistableCusto
private Integer recurrenceOnMonth;

@Column(name = "last_run_date")
private LocalDate latsRunDate;
private LocalDate lastRunDate;

protected AccountTransferStandingInstruction() {

Expand Down Expand Up @@ -205,13 +210,13 @@ public Map<String, Object> update(JsonCommand command) {
final MonthDay monthDay = command.extractMonthDayNamed(recurrenceOnMonthDayParamName);
final String actualValueEntered = command.stringValueOfParameterNamed(recurrenceOnMonthDayParamName);
final Integer dayOfMonthValue = monthDay.getDayOfMonth();
if (!this.recurrenceOnDay.equals(dayOfMonthValue)) {
if (!java.util.Objects.equals(this.recurrenceOnDay, dayOfMonthValue)) {
actualChanges.put(recurrenceOnMonthDayParamName, actualValueEntered);
this.recurrenceOnDay = dayOfMonthValue;
}

final Integer monthOfYear = monthDay.getMonthValue();
if (!this.recurrenceOnMonth.equals(monthOfYear)) {
if (!java.util.Objects.equals(this.recurrenceOnMonth, monthOfYear)) {
actualChanges.put(recurrenceOnMonthDayParamName, actualValueEntered);
this.recurrenceOnMonth = monthOfYear;
}
Expand All @@ -222,6 +227,46 @@ public Map<String, Object> update(JsonCommand command) {
actualChanges.put(recurrenceIntervalParamName, newValue);
this.recurrenceInterval = newValue;
}

if (StandingInstructionType.fromInt(this.instructionType).isDuesAmoutTransfer()) {
if (this.amount != null) {
actualChanges.put(amountParamName, null);
this.amount = null;
}
}

if (AccountTransferRecurrenceType.fromInt(this.recurrenceType).isDuesRecurrence()) {
if (this.recurrenceFrequency != null) {
actualChanges.put(recurrenceFrequencyParamName, null);
this.recurrenceFrequency = null;
}
if (this.recurrenceInterval != null) {
actualChanges.put(recurrenceIntervalParamName, null);
this.recurrenceInterval = null;
}
if (this.recurrenceOnDay != null) {
actualChanges.put(recurrenceOnMonthDayParamName, null);
this.recurrenceOnDay = null;
}
if (this.recurrenceOnMonth != null) {
this.recurrenceOnMonth = null;
}
}

if (this.recurrenceFrequency != null) {
final PeriodFrequencyType frequencyType = PeriodFrequencyType.fromInt(this.recurrenceFrequency);

if (frequencyType.isDaily() || frequencyType.isWeekly()) {
if (this.recurrenceOnDay != null) {
actualChanges.put(recurrenceOnMonthDayParamName, null);
this.recurrenceOnDay = null;
}
if (this.recurrenceOnMonth != null) {
this.recurrenceOnMonth = null;
}
}
}

validateDependencies(baseDataValidator);
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(dataValidationErrors);
Expand Down Expand Up @@ -258,22 +303,28 @@ private void validateDependencies(final DataValidatorBuilder baseDataValidator)
baseDataValidator.reset().parameter(amountParamName).value(this.amount).notNull();
}

if (StandingInstructionType.fromInt(this.instructionType).isDuesAmoutTransfer()) {
if (this.amount != null) {
baseDataValidator.reset().parameter(amountParamName).failWithCode(AMOUNT_NOT_ALLOWED_FOR_DUES_ERROR_CODE);
}
}

String errorCode = null;
if (this.accountTransferDetails.transferType().isAccountTransfer()
&& (this.accountTransferDetails.fromSavingsAccount() == null || this.accountTransferDetails.toSavingsAccount() == null)) {
errorCode = "not.account.transfer";
errorCode = ACCOUNT_TRANSFER_NOT_ALLOWED_FOR_LOAN_ERROR_CODE;
} else if (this.accountTransferDetails.transferType().isLoanRepayment()
&& (this.accountTransferDetails.fromSavingsAccount() == null || this.accountTransferDetails.toLoanAccount() == null)) {
errorCode = "not.loan.repayment";
errorCode = NOT_A_VALID_LOAN_REPAYMENT_ERROR_CODE;
}
if (errorCode != null) {
baseDataValidator.reset().parameter(transferTypeParamName).failWithCode(errorCode);
}

}

public void updateLatsRunDate(LocalDate latsRunDate) {
this.latsRunDate = latsRunDate;
public void updateLastRunDate(LocalDate lastRunDate) {
this.lastRunDate = lastRunDate;
}

public void updateStatus(Integer status) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,24 @@ public StandingInstructionData retrieveTemplate(final Long fromOfficeId, final L
*/);
final Collection<EnumOptionData> statusOptions = Arrays.asList(standingInstructionStatus(StandingInstructionStatus.ACTIVE),
standingInstructionStatus(StandingInstructionStatus.DISABLED));
final Collection<EnumOptionData> instructionTypeOptions = Arrays.asList(standingInstructionType(StandingInstructionType.FIXED),
standingInstructionType(StandingInstructionType.DUES));
final Collection<EnumOptionData> priorityOptions = Arrays.asList(standingInstructionPriority(StandingInstructionPriority.URGENT),
standingInstructionPriority(StandingInstructionPriority.HIGH),
standingInstructionPriority(StandingInstructionPriority.MEDIUM),
standingInstructionPriority(StandingInstructionPriority.LOW));
final Collection<EnumOptionData> recurrenceTypeOptions = Arrays.asList(recurrenceType(AccountTransferRecurrenceType.PERIODIC),
recurrenceType(AccountTransferRecurrenceType.AS_PER_DUES));

Collection<EnumOptionData> instructionTypeOptions = null;
Collection<EnumOptionData> recurrenceTypeOptions = null;

if (accountTransferType.isAccountTransfer()) {
instructionTypeOptions = Arrays.asList(standingInstructionType(StandingInstructionType.FIXED));
recurrenceTypeOptions = Arrays.asList(recurrenceType(AccountTransferRecurrenceType.PERIODIC));
} else {
instructionTypeOptions = Arrays.asList(standingInstructionType(StandingInstructionType.FIXED),
standingInstructionType(StandingInstructionType.DUES));
recurrenceTypeOptions = Arrays.asList(recurrenceType(AccountTransferRecurrenceType.PERIODIC),
recurrenceType(AccountTransferRecurrenceType.AS_PER_DUES));
}

final Collection<EnumOptionData> recurrenceFrequencyOptions = this.dropdownReadPlatformService.retrievePeriodFrequencyTypeOptions();

return StandingInstructionData.template(fromOffice, fromClient, fromAccountTypeData, fromAccount, transferDate, toOffice, toClient,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,17 +123,26 @@ private boolean isSavingsToSavingsAccountTransfer(final PortfolioAccountType fro
return PortfolioAccountType.SAVINGS.equals(fromAccountType) && PortfolioAccountType.SAVINGS.equals(toAccountType);
}

@Transactional
@Override
public CommandProcessingResult update(final Long id, final JsonCommand command) {
this.standingInstructionDataValidator.validateForUpdate(command);
AccountTransferStandingInstruction standingInstructionsForUpdate = this.standingInstructionRepository.findById(id)
final AccountTransferStandingInstruction standingInstructionForUpdate = this.standingInstructionRepository.findById(id)
.orElseThrow(() -> new StandingInstructionNotFoundException(id));
final Map<String, Object> actualChanges = standingInstructionsForUpdate.update(command);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withEntityId(id) //
.with(actualChanges) //
.build();

this.standingInstructionDataValidator.validateForUpdate(command, standingInstructionForUpdate);

final Map<String, Object> actualChanges = standingInstructionForUpdate.update(command);
if (!actualChanges.isEmpty()) {
try {
this.standingInstructionRepository.saveAndFlush(standingInstructionForUpdate);
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
final Throwable throwable = dve.getMostSpecificCause();
handleDataIntegrityIssues(command, throwable, dve);
return CommandProcessingResult.empty();
}
}

return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(id).with(actualChanges).build();
}

@Override
Expand Down
Loading