Savings fee code cleanup and added shcedule for paying charges
This commit is contained in:
@@ -14344,8 +14344,10 @@ POST savingsaccounts/1/charges/2?command=paycharge
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"dateFormat": "dd MMMM yyyy",
|
||||
"locale": "en",
|
||||
"amount": "60",
|
||||
"dueDate": "12 September 2013"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
INSERT INTO `job` (`name`, `display_name`, `cron_expression`, `create_time`, `task_priority`, `group_name`, `previous_run_start_time`, `next_run_time`, `job_key`, `initializing_errorlog`, `is_active`, `currently_running`, `updates_allowed`, `scheduler_group`, `is_misfired`) VALUES ('Pay Due Savings Charges', 'Pay Due Savings Charges', '0 0 12 * * ?', '2013-09-23 00:00:00', 5, NULL, NULL, NULL, 'Pay Due Savings ChargesJobDetail1 _ DEFAULT', NULL, 1, 0, 1, 0, 0);
|
||||
+1
-1
@@ -5,7 +5,7 @@ public enum JobName {
|
||||
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
|
||||
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
|
||||
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS(
|
||||
"Transfer Fee For Loans From Savings");
|
||||
"Transfer Fee For Loans From Savings"), PAY_DUE_SAVINGS_CHARGES("Pay Due Savings Charges");
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
+5
@@ -1,9 +1,14 @@
|
||||
package org.mifosplatform.organisation.holiday.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface HolidayWritePlatformService {
|
||||
|
||||
CommandProcessingResult createHoliday(JsonCommand command);
|
||||
|
||||
boolean isHoliday(Long officeId, LocalDate transactionDate);
|
||||
|
||||
boolean isTransactionAllowedOnHoliday();
|
||||
}
|
||||
|
||||
+17
-2
@@ -1,9 +1,11 @@
|
||||
package org.mifosplatform.organisation.holiday.service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -39,7 +41,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
private final HolidayDataValidator fromApiJsonDeserializer;
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
|
||||
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final OfficeRepository officeRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -47,13 +49,14 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
@Autowired
|
||||
public HolidayWritePlatformServiceJpaRepositoryImpl(final HolidayDataValidator fromApiJsonDeserializer,
|
||||
final HolidayRepository holidayRepository, final PlatformSecurityContext context, final OfficeRepository officeRepository,
|
||||
final FromJsonHelper fromApiJsonHelper, final WorkingDaysRepositoryWrapper daysRepositoryWrapper) {
|
||||
final FromJsonHelper fromApiJsonHelper, final WorkingDaysRepositoryWrapper daysRepositoryWrapper, final ConfigurationDomainService configurationDomainService) {
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.context = context;
|
||||
this.officeRepository = officeRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.daysRepositoryWrapper = daysRepositoryWrapper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -152,4 +155,16 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
toDate.toString(), repaymentsRescheduledTo.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHoliday(Long officeId, LocalDate transactionDate) {
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, transactionDate.toDate());
|
||||
return HolidayUtil.isHoliday(transactionDate, holidays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAllowedOnHoliday() {
|
||||
return this.configurationDomainService.allowTransactionsOnHolidayEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package org.mifosplatform.organisation.workingdays.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public interface WorkingDaysWritePlatformService {
|
||||
|
||||
boolean isWorkingDay(LocalDate transactionDate);
|
||||
|
||||
boolean isTransactionAllowedOnNonWorkingDay();
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package org.mifosplatform.organisation.workingdays.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class WorkingDaysWritePlatformServiceJpaRepositoryImpl implements WorkingDaysWritePlatformService {
|
||||
|
||||
private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
|
||||
@Autowired
|
||||
public WorkingDaysWritePlatformServiceJpaRepositoryImpl(final WorkingDaysRepositoryWrapper daysRepositoryWrapper,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
this.daysRepositoryWrapper = daysRepositoryWrapper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorkingDay(LocalDate transactionDate) {
|
||||
final WorkingDays workingDays = this.daysRepositoryWrapper.findOne();
|
||||
return WorkingDaysUtil.isWorkingDay(workingDays, transactionDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAllowedOnNonWorkingDay() {
|
||||
return this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -43,7 +43,8 @@ public class ChargesApiResource {
|
||||
|
||||
private final Set<String> CHARGES_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "name", "amount", "currency", "penalty",
|
||||
"active", "chargeAppliesTo", "chargeTimeType", "chargeCalculationType", "chargeCalculationTypeOptions",
|
||||
"chargeAppliesToOptions", "chargeTimeTypeOptions", "currencyOptions"));
|
||||
"chargeAppliesToOptions", "chargeTimeTypeOptions", "currencyOptions", "loanChargeCalculationTypeOptions",
|
||||
"loanChargeTimeTypeOptions", "savingsChargeCalculationTypeOptions", "savingsChargeTimeTypeOptions"));
|
||||
|
||||
private final String resourceNameForPermissions = "CHARGE";
|
||||
|
||||
|
||||
+45
-10
@@ -33,30 +33,53 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
private final EnumOptionData chargePaymentMode;
|
||||
|
||||
private final Collection<CurrencyData> currencyOptions;
|
||||
private final List<EnumOptionData> chargeCalculationTypeOptions;
|
||||
private final List<EnumOptionData> chargeAppliesToOptions;
|
||||
private final List<EnumOptionData> chargeTimeTypeOptions;
|
||||
private final List<EnumOptionData> chargePaymetModeOptions;
|
||||
private final List<EnumOptionData> chargeCalculationTypeOptions;//
|
||||
private final List<EnumOptionData> chargeAppliesToOptions;//
|
||||
private final List<EnumOptionData> chargeTimeTypeOptions;//
|
||||
private final List<EnumOptionData> chargePaymetModeOptions;//
|
||||
|
||||
private final List<EnumOptionData> loanChargeCalculationTypeOptions;
|
||||
private final List<EnumOptionData> loanChargeTimeTypeOptions;
|
||||
private final List<EnumOptionData> savingsChargeCalculationTypeOptions;
|
||||
private final List<EnumOptionData> savingsChargeTimeTypeOptions;
|
||||
|
||||
public static ChargeData template(final Collection<CurrencyData> currencyOptions,
|
||||
final List<EnumOptionData> chargeCalculationTypeOptions, final List<EnumOptionData> chargeAppliesToOptions,
|
||||
final List<EnumOptionData> chargeTimeTypeOptions, final List<EnumOptionData> chargePaymentModeOptions) {
|
||||
final List<EnumOptionData> chargeTimeTypeOptions, final List<EnumOptionData> chargePaymentModeOptions,
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions, final List<EnumOptionData> loansChargeTimeTypeOptions,
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions, final List<EnumOptionData> savingsChargeTimeTypeOptions) {
|
||||
|
||||
return new ChargeData(null, null, null, null, null, null, null, null, false, false, currencyOptions, chargeCalculationTypeOptions,
|
||||
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions);
|
||||
chargeAppliesToOptions, chargeTimeTypeOptions, chargePaymentModeOptions, loansChargeCalculationTypeOptions,
|
||||
loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
public static ChargeData withTemplate(final ChargeData charge, final ChargeData template) {
|
||||
return new ChargeData(charge.id, charge.name, charge.amount, charge.currency, charge.chargeTimeType, charge.chargeAppliesTo,
|
||||
charge.chargeCalculationType, charge.chargePaymentMode, charge.penalty, charge.active, template.currencyOptions,
|
||||
template.chargeCalculationTypeOptions, template.chargeAppliesToOptions, template.chargeTimeTypeOptions,
|
||||
template.chargePaymetModeOptions);
|
||||
template.chargePaymetModeOptions, template.loanChargeCalculationTypeOptions, template.loanChargeTimeTypeOptions,
|
||||
template.savingsChargeCalculationTypeOptions, template.savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
public static ChargeData instance(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||
final EnumOptionData chargeTimeType, final EnumOptionData chargeAppliesTo, final EnumOptionData chargeCalculationType,
|
||||
final EnumOptionData chargePaymentMode, final boolean penalty, final boolean active) {
|
||||
|
||||
final Collection<CurrencyData> currencyOptions = null;
|
||||
final List<EnumOptionData> chargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> chargeAppliesToOptions = null;
|
||||
final List<EnumOptionData> chargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> chargePaymentModeOptions = null;
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = null;
|
||||
|
||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||
penalty, active, null, null, null, null, null);
|
||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
public static ChargeData lookup(final Long id, final String name, final boolean isPenalty) {
|
||||
@@ -73,9 +96,15 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final List<EnumOptionData> chargeAppliesToOptions = null;
|
||||
final List<EnumOptionData> chargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> chargePaymentModeOptions = null;
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = null;
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = null;
|
||||
|
||||
return new ChargeData(id, name, amount, currency, chargeTimeType, chargeAppliesTo, chargeCalculationType, chargePaymentMode,
|
||||
penalty, active, currencyOptions, chargeCalculationTypeOptions, chargeAppliesToOptions, chargeTimeTypeOptions,
|
||||
chargePaymentModeOptions);
|
||||
chargePaymentModeOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
private ChargeData(final Long id, final String name, final BigDecimal amount, final CurrencyData currency,
|
||||
@@ -83,7 +112,9 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final EnumOptionData chargePaymentMode, final boolean penalty, final boolean active,
|
||||
final Collection<CurrencyData> currencyOptions, final List<EnumOptionData> chargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> chargeAppliesToOptions, final List<EnumOptionData> chargeTimeTypeOptions,
|
||||
final List<EnumOptionData> chargePaymentModeOptions) {
|
||||
final List<EnumOptionData> chargePaymentModeOptions, final List<EnumOptionData> loansChargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions, final List<EnumOptionData> savingsChargeCalculationTypeOptions,
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.amount = amount;
|
||||
@@ -99,6 +130,10 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
this.chargeAppliesToOptions = chargeAppliesToOptions;
|
||||
this.chargeTimeTypeOptions = chargeTimeTypeOptions;
|
||||
this.chargePaymetModeOptions = chargePaymentModeOptions;
|
||||
this.savingsChargeCalculationTypeOptions = savingsChargeCalculationTypeOptions;
|
||||
this.savingsChargeTimeTypeOptions = savingsChargeTimeTypeOptions;
|
||||
this.loanChargeCalculationTypeOptions = loansChargeCalculationTypeOptions;
|
||||
this.loanChargeTimeTypeOptions = loansChargeTimeTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
@@ -18,4 +18,13 @@ public interface ChargeDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveCollectionTimeTypes();
|
||||
|
||||
List<EnumOptionData> retrivePaymentModes();
|
||||
|
||||
List<EnumOptionData> retrieveLoanCalculationTypes();
|
||||
|
||||
List<EnumOptionData> retrieveLoanCollectionTimeTypes();
|
||||
|
||||
List<EnumOptionData> retrieveSavingsCalculationTypes();
|
||||
|
||||
List<EnumOptionData> retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
}
|
||||
|
||||
+27
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.charge.service;
|
||||
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeCalculationType;
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargePaymentMode;
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeTimeType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -68,4 +69,30 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
public List<EnumOptionData> retrivePaymentModes() {
|
||||
return Arrays.asList(chargePaymentMode(ChargePaymentMode.REGULAR), chargePaymentMode(ChargePaymentMode.ACCOUNT_TRANSFER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveLoanCalculationTypes() {
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT), chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveLoanCollectionTimeTypes() {
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveSavingsCalculationTypes() {
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT)
|
||||
//Enable when percentage of amount is supported for savings charges
|
||||
//, chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveSavingsCollectionTimeTypes() {
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE)
|
||||
//enable when support is added for recurring Monthly and yearly charges
|
||||
//, chargeTimeType(ChargeTimeType.MONTHLY), chargeTimeType(ChargeTimeType.YEARLY)
|
||||
);
|
||||
}
|
||||
}
|
||||
+9
-1
@@ -82,9 +82,17 @@ public class ChargeReadPlatformServiceImpl implements ChargeReadPlatformService
|
||||
final List<EnumOptionData> allowedChargeAppliesToOptions = this.chargeDropdownReadPlatformService.retrieveApplicableToTypes();
|
||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||
final List<EnumOptionData> chargePaymentOptions = this.chargeDropdownReadPlatformService.retrivePaymentModes();
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveLoanCalculationTypes();
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCalculationTypes();
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
return ChargeData.template(currencyOptions, allowedChargeCalculationTypeOptions, allowedChargeAppliesToOptions,
|
||||
allowedChargeTimeOptions, chargePaymentOptions);
|
||||
allowedChargeTimeOptions, chargePaymentOptions, loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions,
|
||||
savingsChargeCalculationTypeOptions, savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+11
-2
@@ -115,8 +115,17 @@ public class LoanChargeReadPlatformServiceImpl implements LoanChargeReadPlatform
|
||||
|
||||
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null);
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveLoanCalculationTypes();
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCalculationTypes();
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
|
||||
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
|
||||
savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
@@ -192,4 +192,7 @@ public class SavingsApiConstants {
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
chargeIdParamName, amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
amountParamName, dueAsOfDateParamName, dateFormatParamName, localeParamName));
|
||||
}
|
||||
+1
-1
@@ -155,7 +155,7 @@ public class SavingsAccountChargesApiResource {
|
||||
@Path("{savingsAccountChargeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String waiveSavingsAccountCharge(@PathParam("savingsAccountId") final Long savingsAccountId,
|
||||
public String payOrWaiveSavingsAccountCharge(@PathParam("savingsAccountId") final Long savingsAccountId,
|
||||
@PathParam("savingsAccountChargeId") final Long savingsAccountChargeId, @QueryParam("command") final String commandParam,
|
||||
final String apiRequestBodyAsJson) {
|
||||
|
||||
|
||||
+27
-2
@@ -6,6 +6,7 @@
|
||||
package org.mifosplatform.portfolio.savings.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGES_ADD_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
@@ -18,6 +19,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
@@ -57,7 +59,8 @@ public class SavingsAccountChargeDataValidator {
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(dueAsOfDateParamName, element)) {
|
||||
this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
@@ -79,12 +82,34 @@ public class SavingsAccountChargeDataValidator {
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(dueAsOfDateParamName, element)) {
|
||||
this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validatePayCharge(final String json) {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SAVINGS_ACCOUNT_CHARGES_PAY_CHARGE_REQUEST_DATA_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_CHARGE_RESOURCE_NAME);
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(amountParamName, element);
|
||||
baseDataValidator.reset().parameter(amountParamName).value(amount).notNull().positiveAmount();
|
||||
|
||||
final LocalDate transactionDate = this.fromApiJsonHelper.extractLocalDateNamed(dueAsOfDateParamName, element);
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate).notNull();
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
+53
-27
@@ -14,6 +14,7 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeri
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -735,7 +736,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
return transactionBeforeLastInterestPosting;
|
||||
}
|
||||
|
||||
|
||||
public void validateAccountBalanceDoesNotBecomeNegative(final BigDecimal transactionAmount) {
|
||||
final List<SavingsAccountTransaction> transactionsSortedByDate = retreiveListOfTransactions();
|
||||
Money runningBalance = Money.zero(this.currency);
|
||||
@@ -1893,7 +1894,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean hasCurrencyCodeOf(final String matchingCurrencyCode) {
|
||||
// TODO AA: revisit
|
||||
if (this.currency == null) { return false; }
|
||||
return this.currency.getCode().equalsIgnoreCase(matchingCurrencyCode);
|
||||
}
|
||||
@@ -1907,7 +1907,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
|
||||
@@ -1935,13 +1935,6 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
// waive charge
|
||||
final Money amountWaived = savingsAccountCharge.waive(getCurrency());
|
||||
// TODO : AA revisit the code
|
||||
/*
|
||||
* Money feeChargesWaived = amountWaived; Money penaltyChargesWaived =
|
||||
* Money.zero(this.getCurrency()); if
|
||||
* (savingsAccountCharge.isPenaltyCharge()) { penaltyChargesWaived =
|
||||
* amountWaived; feeChargesWaived = Money.zero(this.getCurrency()); }
|
||||
*/
|
||||
|
||||
// persist an entry in transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(),
|
||||
@@ -1958,18 +1951,13 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (isNotActive()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.not.active");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!hasCurrencyCodeOf(chargeDefinition.getCurrencyCode())) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
|
||||
"transaction.invalid.account.currency.and.charge.currency.not.same");
|
||||
@@ -1979,7 +1967,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final LocalDate chargeDueDate = savingsAccountCharge.getDueLocalDate();
|
||||
|
||||
if (chargeDueDate != null && chargeDueDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter("dueDate").value(getActivationLocalDate().toString(formatter))
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
@@ -1991,12 +1979,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
}
|
||||
|
||||
public void payCharge(final Long savingsAccountChargeId, final BigDecimal amountPaid, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
public void payCharge(final Long savingsAccountChargeId, final BigDecimal amountPaid, final LocalDate transactionDate,
|
||||
final DateTimeFormatter formatter, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME + "dueDate");
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
if (isClosed()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.is.closed");
|
||||
@@ -2008,6 +1996,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (transactionDate != null && transactionDate.isBefore(getActivationLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(getActivationLocalDate().toString(formatter))
|
||||
.failWithCodeNoParameterAddedToErrorCode("before.activationDate");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = getCharge(savingsAccountChargeId);
|
||||
|
||||
// validate charge is not already paid or waived
|
||||
@@ -2018,17 +2012,19 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.account.charge.is.paid");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final Money amountPaidMoney = Money.of(currency, amountPaid);
|
||||
if (!savingsAccountCharge.getAmountOutstanding(getCurrency()).isGreaterThanOrEqualTo(amountPaidMoney)){
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("transaction.invalid.charge.amount.paid.in.access");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
|
||||
final Money chargePaid = savingsAccountCharge.pay(getCurrency(), amountPaid);
|
||||
|
||||
// If null reset to current date
|
||||
final LocalDate transactionDate = (savingsAccountCharge.getDueLocalDate() == null) ? DateUtils.getLocalDateOfTenant()
|
||||
: savingsAccountCharge.getDueLocalDate();
|
||||
|
||||
// persist an entry in transaction details
|
||||
final Money chargePaid = savingsAccountCharge.pay(getCurrency(), amountPaidMoney);
|
||||
|
||||
// persist transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, chargePaid);
|
||||
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge,
|
||||
@@ -2051,6 +2047,36 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
}
|
||||
|
||||
public void payDueCharge(final SavingsAccountCharge savingsAccountCharge, final LocalDate transactionDate, final List<Long> existingTransactionIds,
|
||||
final List<Long> existingReversedTransactionIds) {
|
||||
|
||||
existingTransactionIds.addAll(findExistingTransactionIds());
|
||||
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
|
||||
final Money amountPaid = savingsAccountCharge.payDueCharge(getCurrency());
|
||||
|
||||
// persist transaction details
|
||||
final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, amountPaid);
|
||||
|
||||
final SavingsAccountChargePaidBy chargePaidBy = SavingsAccountChargePaidBy.instance(chargeTransaction, savingsAccountCharge,
|
||||
amountPaid.getAmount());
|
||||
|
||||
chargeTransaction.getSavingsAccountChargesPaid().add(chargePaidBy);
|
||||
|
||||
this.transactions.add(chargeTransaction);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
postInterest(mc, today, existingTransactionIds, existingReversedTransactionIds);
|
||||
} else {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
calculateInterestUsing(mc, today);
|
||||
}
|
||||
|
||||
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
|
||||
validateAccountBalanceDoesNotBecomeNegative(amountPaid.getAmount());
|
||||
}
|
||||
|
||||
private SavingsAccountCharge getCharge(final Long savingsAccountChargeId) {
|
||||
SavingsAccountCharge charge = null;
|
||||
for (final SavingsAccountCharge existingCharge : this.charges) {
|
||||
|
||||
+23
-3
@@ -228,13 +228,25 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return getAmountWaived(currency);
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final BigDecimal chargePaid) {
|
||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||
|
||||
Money amountPaidToDate = Money.of(currency, this.amountPaid);
|
||||
final Money amountPaid = Money.of(currency, chargePaid);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
amountPaidToDate = amountPaidToDate.plus(amountPaid);
|
||||
amountOutstanding = amountOutstanding.minus(chargePaid);
|
||||
amountOutstanding = amountOutstanding.minus(amountPaid);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
return amountPaid;
|
||||
}
|
||||
|
||||
public Money payDueCharge(final MonetaryCurrency currency) {
|
||||
|
||||
Money amountPaidToDate = Money.of(currency, this.amountPaid);
|
||||
Money amountOutstanding = Money.of(currency, this.amountOutstanding);
|
||||
final Money amountPaid = Money.of(currency, this.amountOutstanding);;
|
||||
amountPaidToDate = amountPaidToDate.plus(amountPaid);
|
||||
amountOutstanding = amountOutstanding.minus(amountPaid);
|
||||
this.amountPaid = amountPaidToDate.getAmount();
|
||||
this.amountOutstanding = amountOutstanding.getAmount();
|
||||
this.paid = determineIfFullyPaid();
|
||||
@@ -440,6 +452,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return Money.of(currency, this.amountWrittenOff);
|
||||
}
|
||||
|
||||
public Money getAmountOutstanding(final MonetaryCurrency currency){
|
||||
return Money.of(currency, this.amountOutstanding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param incrementBy
|
||||
* Amount used to pay off this charge
|
||||
@@ -486,6 +502,10 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
|
||||
return ChargeTimeType.fromInt(this.chargeTime).isOnSpecifiedDueDate();
|
||||
}
|
||||
|
||||
public SavingsAccount savingsAccount(){
|
||||
return this.savingsAccount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) { return false; }
|
||||
|
||||
+8
@@ -5,11 +5,19 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface SavingsAccountChargeRepository extends JpaRepository<SavingsAccountCharge, Long>,
|
||||
JpaSpecificationExecutor<SavingsAccountCharge> {
|
||||
|
||||
SavingsAccountCharge findByIdAndSavingsAccountId(Long id, Long savingsAccountId);
|
||||
|
||||
@Query("from SavingsAccountCharge sac where sac.dueDate <=:transactionDate and sac.waived = 0 and sac.paid=0")
|
||||
List<SavingsAccountCharge> findPendingCharges(@Param("transactionDate") Date transactionDate);
|
||||
}
|
||||
|
||||
+12
@@ -5,6 +5,10 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -36,11 +40,19 @@ public class SavingsAccountChargeRepositoryWrapper {
|
||||
if (savingsAccountCharge == null) { throw new SavingsAccountChargeNotFoundException(id); }
|
||||
return savingsAccountCharge;
|
||||
}
|
||||
|
||||
public List<SavingsAccountCharge> findPendingCharges(final Date transactionDate){
|
||||
return this.repository.findPendingCharges(transactionDate);
|
||||
}
|
||||
|
||||
public void save(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.save(savingsAccountCharge);
|
||||
}
|
||||
|
||||
public void save(final Iterable<SavingsAccountCharge> savingsAccountCharges){
|
||||
this.repository.save(savingsAccountCharges);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final SavingsAccountCharge savingsAccountCharge) {
|
||||
this.repository.saveAndFlush(savingsAccountCharge);
|
||||
}
|
||||
|
||||
+10
@@ -10,6 +10,7 @@ import java.util.List;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
@@ -49,6 +50,13 @@ public final class SavingsAccountSummary {
|
||||
@Column(name = "account_balance_derived", scale = 6, precision = 19)
|
||||
private BigDecimal accountBalance = BigDecimal.ZERO;
|
||||
|
||||
//TODO: AA do we need this data to be persisted.
|
||||
@Transient
|
||||
private BigDecimal totalFeeChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
@Transient
|
||||
private BigDecimal totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
protected SavingsAccountSummary() {
|
||||
//
|
||||
}
|
||||
@@ -63,6 +71,8 @@ public final class SavingsAccountSummary {
|
||||
this.totalAnnualFees = wrapper.calculateTotalAnnualFees(currency, transactions);
|
||||
this.totalFeeCharge = wrapper.calculateTotalFeesCharge(currency, transactions);
|
||||
this.totalPenaltyCharge = wrapper.calculateTotalPenaltyCharge(currency, transactions);
|
||||
this.totalFeeChargesWaived = wrapper.calculateTotalFeesChargeWaived(currency, transactions);
|
||||
this.totalPenaltyChargesWaived = wrapper.calculateTotalPenaltyChargeWaived(currency, transactions);
|
||||
|
||||
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
|
||||
.minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
|
||||
|
||||
+22
@@ -437,6 +437,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
public boolean isCharge() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isCharge();
|
||||
}
|
||||
|
||||
public boolean isWaiveCharge(){
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWaiveCharge();
|
||||
}
|
||||
|
||||
public boolean isFeeCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
@@ -456,6 +460,24 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
return isPenaltyCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaiveFeeCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isFeeCharge() : false;
|
||||
}
|
||||
|
||||
public boolean isWaivePenaltyCharge() {
|
||||
final SavingsAccountChargePaidBy chargePaidBy = getSavingsAccountChargePaidBy();
|
||||
return (isWaiveCharge() && chargePaidBy != null) ? chargePaidBy.isPenaltyCharge() : false;
|
||||
}
|
||||
|
||||
public boolean isWaiveFeeChargeAndNotReversed() {
|
||||
return isWaiveFeeCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaivePenaltyChargeAndNotReversed() {
|
||||
return isWaivePenaltyCharge() && isNotReversed();
|
||||
}
|
||||
|
||||
private SavingsAccountChargePaidBy getSavingsAccountChargePaidBy() {
|
||||
if (!CollectionUtils.isEmpty(this.savingsAccountChargesPaid)) { return this.savingsAccountChargesPaid.iterator().next(); }
|
||||
return null;
|
||||
|
||||
+22
-2
@@ -72,17 +72,37 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
public BigDecimal calculateTotalFeesCharge(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isFeeChargeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isFeeChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalFeesChargeWaived(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWaiveFeeChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalPenaltyCharge(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (transaction.isPenaltyChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalPenaltyChargeWaived(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isWaivePenaltyChargeAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,6 +27,6 @@ public class WaiveSavingsAccountChargeCommandHandler implements NewCommandSource
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.waiveCharge(command.getSavingsId(), command.entityId(), command);
|
||||
return this.writePlatformService.waiveCharge(command.getSavingsId(), command.entityId());
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -112,9 +112,18 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
|
||||
final List<EnumOptionData> allowedChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService.retrieveCalculationTypes();
|
||||
final List<EnumOptionData> allowedChargeTimeOptions = this.chargeDropdownReadPlatformService.retrieveCollectionTimeTypes();
|
||||
final List<EnumOptionData> loansChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveLoanCalculationTypes();
|
||||
final List<EnumOptionData> loansChargeTimeTypeOptions = this.chargeDropdownReadPlatformService.retrieveLoanCollectionTimeTypes();
|
||||
final List<EnumOptionData> savingsChargeCalculationTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCalculationTypes();
|
||||
final List<EnumOptionData> savingsChargeTimeTypeOptions = this.chargeDropdownReadPlatformService
|
||||
.retrieveSavingsCollectionTimeTypes();
|
||||
|
||||
// TODO AA : revisit for merge conflict - Not sure method signature
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null);
|
||||
return ChargeData.template(null, allowedChargeCalculationTypeOptions, null, allowedChargeTimeOptions, null,
|
||||
loansChargeCalculationTypeOptions, loansChargeTimeTypeOptions, savingsChargeCalculationTypeOptions,
|
||||
savingsChargeTimeTypeOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -48,7 +48,9 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult deleteSavingsAccountCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult waiveCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
CommandProcessingResult waiveCharge(Long savingsAccountId, Long savingsAccountChargeId);
|
||||
|
||||
CommandProcessingResult payCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
|
||||
void payDueCharges();
|
||||
}
|
||||
+114
-18
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.service;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.amountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
@@ -34,11 +35,13 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
|
||||
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysWritePlatformService;
|
||||
import org.mifosplatform.portfolio.account.PortfolioAccountType;
|
||||
import org.mifosplatform.portfolio.account.service.AccountAssociationsReadPlatformService;
|
||||
import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||
@@ -65,6 +68,7 @@ import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.mifosplatform.portfolio.savings.exception.InsufficientAccountBalanceException;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsAccountClosingNotAllowedException;
|
||||
import org.mifosplatform.portfolio.savings.exception.SavingsAccountTransactionNotFoundException;
|
||||
import org.mifosplatform.portfolio.savings.exception.TransactionUpdateNotAllowedException;
|
||||
@@ -91,6 +95,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
private final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService;
|
||||
private final ChargeRepositoryWrapper chargeRepository;
|
||||
private final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository;
|
||||
private final HolidayWritePlatformService holidayWritePlatformService;
|
||||
private final WorkingDaysWritePlatformService workingDaysWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
@@ -105,7 +111,9 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
final SavingsAccountDomainService savingsAccountDomainService, final NoteRepository noteRepository,
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
|
||||
final AccountAssociationsReadPlatformService accountAssociationsReadPlatformService,
|
||||
final ChargeRepositoryWrapper chargeRepository, final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository) {
|
||||
final ChargeRepositoryWrapper chargeRepository, final SavingsAccountChargeRepositoryWrapper savingsAccountChargeRepository,
|
||||
final HolidayWritePlatformService holidayWritePlatformService,
|
||||
final WorkingDaysWritePlatformService workingDaysWritePlatformService) {
|
||||
this.context = context;
|
||||
this.savingAccountRepository = savingAccountRepository;
|
||||
this.savingsAccountTransactionRepository = savingsAccountTransactionRepository;
|
||||
@@ -121,6 +129,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.accountAssociationsReadPlatformService = accountAssociationsReadPlatformService;
|
||||
this.chargeRepository = chargeRepository;
|
||||
this.savingsAccountChargeRepository = savingsAccountChargeRepository;
|
||||
this.holidayWritePlatformService = holidayWritePlatformService;
|
||||
this.workingDaysWritePlatformService = workingDaysWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -586,6 +596,10 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
public CommandProcessingResult addSavingsAccountCharge(final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final Long savingsAccountId = command.getSavingsId();
|
||||
this.savingsAccountChargeDataValidator.validateAdd(command.json());
|
||||
|
||||
@@ -599,6 +613,23 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
final SavingsAccountCharge savingsAccountCharge = SavingsAccountCharge.createNewFromJson(savingsAccount, chargeDefinition, command);
|
||||
|
||||
if (savingsAccountCharge.getDueLocalDate() != null) {
|
||||
// transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay()
|
||||
&& !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
|
||||
savingsAccount.addCharge(fmt, savingsAccountCharge, chargeDefinition);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
@@ -616,9 +647,12 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult updateSavingsAccountCharge(final JsonCommand command) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.savingsAccountChargeDataValidator.validateUpdate(command.json());
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
final Long savingsAccountId = command.getSavingsId();
|
||||
// SavingsAccount Charge entity
|
||||
final Long savingsChargeId = command.entityId();
|
||||
@@ -630,20 +664,30 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
savingsAccountId);
|
||||
|
||||
final Map<String, Object> changes = savingsAccountCharge.update(command);
|
||||
|
||||
if (savingsAccountCharge.getDueLocalDate() != null) {
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
// transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay()
|
||||
&& !this.workingDaysWritePlatformService.isWorkingDay(savingsAccountCharge.getDueLocalDate())) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(savingsAccountCharge.getDueLocalDate().toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.due.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
|
||||
this.savingsAccountChargeRepository.saveAndFlush(savingsAccountCharge);
|
||||
// TODO AA: revisit the code
|
||||
/*
|
||||
* // Charges may be edited only when the loan associated with them are
|
||||
* // yet to be approved (are in submitted and pending status) if
|
||||
* (!loan.status().isSubmittedAndPendingApproval()) { throw new
|
||||
* LoanChargeCannotBeUpdatedException(
|
||||
* LOAN_CHARGE_CANNOT_BE_UPDATED_REASON
|
||||
* .LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE,
|
||||
* loanCharge.getId()); }
|
||||
*/
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsChargeId) //
|
||||
// .withOfficeId(savings) //
|
||||
// .withClientId(loan.getClientId()) //
|
||||
@@ -655,7 +699,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
|
||||
public CommandProcessingResult waiveCharge(final Long savingsAccountId, final Long savingsAccountChargeId) {
|
||||
|
||||
this.context.authenticatedUser();
|
||||
|
||||
@@ -670,7 +714,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
@@ -707,21 +750,45 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult payCharge(final Long savingsAccountId, final Long savingsAccountChargeId, final JsonCommand command) {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.context.authenticatedUser();
|
||||
this.savingsAccountChargeDataValidator.validatePayCharge(command.json());
|
||||
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
|
||||
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(savingsAccountId);
|
||||
checkClientOrGroupActive(savingsAccount);
|
||||
|
||||
final BigDecimal chargeAmount = command.bigDecimalValueOfParameterNamed(amountParamName);
|
||||
savingsAccount.payCharge(savingsAccountChargeId, chargeAmount, existingTransactionIds, existingReversedTransactionIds);
|
||||
final LocalDate transactionDate = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
//transaction date should not be on a holiday or non working day
|
||||
if (!this.holidayWritePlatformService.isTransactionAllowedOnHoliday()
|
||||
&& this.holidayWritePlatformService.isHoliday(savingsAccount.officeId(), transactionDate)) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.on.holiday");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
if (!this.workingDaysWritePlatformService.isTransactionAllowedOnNonWorkingDay()
|
||||
&& !this.workingDaysWritePlatformService.isWorkingDay(transactionDate)) {
|
||||
baseDataValidator.reset().parameter(dueAsOfDateParamName).value(transactionDate.toString(fmt))
|
||||
.failWithCodeNoParameterAddedToErrorCode("transaction.not.allowed.transaction.date.is.a.nonworking.day");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
savingsAccount.payCharge(savingsAccountChargeId, chargeAmount, transactionDate, fmt, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
this.savingAccountRepository.saveAndFlush(savingsAccount);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(savingsAccountChargeId) //
|
||||
.withOfficeId(savingsAccount.officeId()) //
|
||||
.withClientId(savingsAccount.clientId()) //
|
||||
@@ -731,4 +798,33 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.PAY_DUE_SAVINGS_CHARGES)
|
||||
public void payDueCharges() {
|
||||
//always use current date as transaction date for batch job
|
||||
final LocalDate transactionDate = DateUtils.getLocalDateOfTenant();
|
||||
final List<SavingsAccountCharge> pendingCharges = this.savingsAccountChargeRepository.findPendingCharges(transactionDate.toDate());
|
||||
final List<SavingsAccountCharge> paidCharges = new ArrayList<SavingsAccountCharge>(pendingCharges.size());
|
||||
for (SavingsAccountCharge savingsAccountCharge : pendingCharges) {
|
||||
// Get Savings account from savings charge
|
||||
final SavingsAccount account = savingsAccountCharge.savingsAccount();
|
||||
this.savingAccountAssembler.assignSavingAccountHelpers(account);
|
||||
final List<Long> existingTransactionIds = new ArrayList<Long>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<Long>();
|
||||
|
||||
try {
|
||||
account.payDueCharge(savingsAccountCharge, transactionDate, existingTransactionIds, existingReversedTransactionIds);
|
||||
paidCharges.add(savingsAccountCharge);
|
||||
} catch (InsufficientAccountBalanceException isab) {
|
||||
// TODO: AA - provide a meaningful error with failed
|
||||
// transactions list
|
||||
}
|
||||
}
|
||||
|
||||
this.savingsAccountChargeRepository.save(paidCharges);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user