Merge pull request #621 from ashok-conflux/MIFOSX-697-patch
Fixed annual fee batch job and savings charges related issues
This commit is contained in:
@@ -11123,6 +11123,21 @@ GET https://DomainName/api/v1/charges/template
|
||||
"id": 2,
|
||||
"code": "chargeTimeType.specifiedDueDate",
|
||||
"value": "Specified due date"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"code": "chargeTimeType.savingsActivation",
|
||||
"value": "Savings Activation"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"code": "chargeTimeType.withdrawalFee",
|
||||
"value": "Withdrawal Fee"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"code": "chargeTimeType.annualFee",
|
||||
"value": "Annual Fee"
|
||||
}
|
||||
],
|
||||
"chargePaymetModeOptions":
|
||||
|
||||
@@ -1,25 +1,253 @@
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
CHANGE COLUMN `due_for_collection_as_of_date` `charge_due_date` DATE NULL DEFAULT NULL AFTER `charge_time_enum`;
|
||||
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
ADD COLUMN `fee_on_month` SMALLINT(5) NULL DEFAULT NULL AFTER `charge_due_date`,
|
||||
ADD COLUMN `fee_on_day` SMALLINT(5) NULL DEFAULT NULL AFTER `fee_on_month`,
|
||||
ADD COLUMN `is_active` TINYINT(1) NOT NULL DEFAULT '1' AFTER `waived`;
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
DROP COLUMN `withdrawal_fee_amount`,
|
||||
DROP COLUMN `withdrawal_fee_type_enum`;
|
||||
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
ADD COLUMN `fee_on_month` SMALLINT(5) NULL DEFAULT NULL AFTER `due_for_collection_as_of_date`,
|
||||
ADD COLUMN `fee_on_day` SMALLINT(5) NULL DEFAULT NULL AFTER `fee_on_month`;
|
||||
delimiter //
|
||||
CREATE PROCEDURE migrate_withdrwal_fees()
|
||||
begin
|
||||
declare no_more_rows boolean default false;
|
||||
declare v_currency_code VARCHAR(3);
|
||||
declare v_withdrawal_fee_type_enum SMALLINT(5);
|
||||
declare v_withdrawal_fee_amount_charge_def DECIMAL(19,6);
|
||||
declare v_account_id BIGINT(20);
|
||||
declare v_withdrawal_fee_amount DECIMAL(19,6);
|
||||
declare t_calculation_percentage DECIMAL(19,6);
|
||||
declare t_calculation_on_amount DECIMAL(19,6);
|
||||
declare t_withdrawal_fee_name VARCHAR(100);
|
||||
|
||||
declare t_charge_id BIGINT(20);
|
||||
declare t_savings_charge_id BIGINT(20);
|
||||
|
||||
ALTER TABLE `m_savings_account_charge`
|
||||
CHANGE COLUMN `due_for_collection_as_of_date` `charge_due_date` DATE NULL DEFAULT NULL AFTER `charge_time_enum`;
|
||||
-- savings transaction variables
|
||||
declare v_savings_transaction_id BIGINT(20);
|
||||
declare v_transaction_amount DECIMAL(19,6);
|
||||
|
||||
|
||||
declare cursor1 cursor for
|
||||
select sa.currency_code, sa.withdrawal_fee_type_enum, sa.withdrawal_fee_amount
|
||||
from m_savings_account sa where sa.withdrawal_fee_amount is not null and sa.withdrawal_fee_amount > 0 group by sa.currency_code, sa.withdrawal_fee_type_enum;
|
||||
|
||||
declare cursor2 cursor for
|
||||
select sa.id, sa.withdrawal_fee_amount from m_savings_account sa where sa.currency_code=v_currency_code and sa.withdrawal_fee_type_enum=v_withdrawal_fee_type_enum and sa.withdrawal_fee_amount is not null and sa.withdrawal_fee_amount > 0;
|
||||
|
||||
declare cursor3 cursor for
|
||||
select sat.id, sat.amount from m_savings_account_transaction sat
|
||||
where sat.savings_account_id=v_account_id and sat.transaction_type_enum=4;
|
||||
|
||||
declare continue handler for not found
|
||||
set no_more_rows := true;
|
||||
|
||||
open cursor1;
|
||||
LOOP1: loop
|
||||
fetch cursor1 into v_currency_code, v_withdrawal_fee_type_enum, v_withdrawal_fee_amount_charge_def;
|
||||
if no_more_rows then
|
||||
close cursor1;
|
||||
leave LOOP1;
|
||||
end if;
|
||||
-- set withdrawal fee name
|
||||
if(v_withdrawal_fee_type_enum = 1) then
|
||||
set t_withdrawal_fee_name = CONCAT('Withdrawal fee-Flat-',v_currency_code);
|
||||
else
|
||||
set t_withdrawal_fee_name = CONCAT('Withdrawal fee-Percentage-',v_currency_code);
|
||||
end if;
|
||||
|
||||
-- get charge id if already exists
|
||||
set t_charge_id = (select id from m_charge where name = t_withdrawal_fee_name);
|
||||
|
||||
if t_charge_id is null then
|
||||
-- add withdrawal fee to charges
|
||||
INSERT INTO `m_charge` (`name`, `currency_code`, `charge_applies_to_enum`, `charge_time_enum`, `charge_calculation_enum`, `charge_payment_mode_enum`, `amount`, `is_penalty`, `is_active`, `is_deleted`) VALUES (t_withdrawal_fee_name , v_currency_code, 2, 5, v_withdrawal_fee_type_enum, 0, v_withdrawal_fee_amount_charge_def, 0, 1, 0);
|
||||
|
||||
-- get inserted charge id
|
||||
set t_charge_id = last_insert_id();
|
||||
end if;
|
||||
|
||||
open cursor2;
|
||||
LOOP2: loop
|
||||
fetch cursor2 into v_account_id, v_withdrawal_fee_amount;
|
||||
if no_more_rows then
|
||||
set no_more_rows := false;
|
||||
close cursor2;
|
||||
leave LOOP2;
|
||||
end if;
|
||||
|
||||
if (v_withdrawal_fee_type_enum=1) then
|
||||
set t_calculation_percentage = NULL;
|
||||
set t_calculation_on_amount = NULL;
|
||||
else
|
||||
set t_calculation_percentage = v_withdrawal_fee_amount;
|
||||
set v_withdrawal_fee_amount = 0;
|
||||
set t_calculation_on_amount = 0;
|
||||
end if;
|
||||
|
||||
if not exists (select id from m_savings_account_charge sac where
|
||||
sac.savings_account_id=v_account_id and sac.charge_id=t_charge_id and sac.charge_time_enum=5) then
|
||||
|
||||
-- attach withdrawal charge to savings
|
||||
INSERT INTO `m_savings_account_charge` (`savings_account_id`, `charge_id`, `is_penalty`, `charge_time_enum`, `charge_due_date`, `fee_on_month`, `fee_on_day`, `charge_calculation_enum`, `calculation_percentage`, `calculation_on_amount`, `amount`, `amount_paid_derived`, `amount_waived_derived`, `amount_writtenoff_derived`, `amount_outstanding_derived`, `is_paid_derived`, `waived`, `is_active`) VALUES (v_account_id, t_charge_id, 0, 5, NULL, NULL, NULL, v_withdrawal_fee_type_enum, t_calculation_percentage, t_calculation_on_amount, v_withdrawal_fee_amount, NULL, NULL, NULL, 0.000000, 0, 0, 1);
|
||||
|
||||
-- set savings account charge id
|
||||
set t_savings_charge_id = last_insert_id();
|
||||
|
||||
else
|
||||
|
||||
set t_savings_charge_id = (select id from m_savings_account_charge sac where sac.savings_account_id=v_account_id and sac.charge_id=t_charge_id and sac.charge_time_enum=5);
|
||||
|
||||
end if;
|
||||
|
||||
|
||||
open cursor3;
|
||||
LOOP3: loop
|
||||
fetch cursor3 into v_savings_transaction_id, v_transaction_amount;
|
||||
|
||||
if no_more_rows then
|
||||
set no_more_rows := false;
|
||||
close cursor3;
|
||||
leave LOOP3;
|
||||
end if;
|
||||
|
||||
if not exists (select id from m_savings_account_charge_paid_by sacp where
|
||||
sacp.savings_account_transaction_id=v_savings_transaction_id and sacp.savings_account_charge_id=t_savings_charge_id) then
|
||||
|
||||
-- insert a record into savings account charge paid by
|
||||
INSERT INTO `m_savings_account_charge_paid_by` (`savings_account_transaction_id`, `savings_account_charge_id`, `amount`) VALUES(v_savings_transaction_id, t_savings_charge_id, v_transaction_amount);
|
||||
|
||||
end if;
|
||||
|
||||
end loop LOOP3;
|
||||
end loop LOOP2;
|
||||
end loop LOOP1;
|
||||
end //
|
||||
|
||||
CREATE PROCEDURE migrate_annual_fees()
|
||||
begin
|
||||
declare no_more_rows boolean default false;
|
||||
declare v_currency_code VARCHAR(3);
|
||||
declare v_annual_fee_amount_charge_def DECIMAL(19,6);
|
||||
declare v_account_id BIGINT(20);
|
||||
declare v_annual_fee_amount DECIMAL(19,6);
|
||||
declare v_annual_fee_on_month SMALLINT(5);
|
||||
declare v_annual_fee_on_day SMALLINT(5);
|
||||
declare v_annual_fee_next_due_date DATE;
|
||||
declare t_annual_fee_name VARCHAR(100);
|
||||
declare t_charge_id BIGINT(20);
|
||||
declare t_savings_charge_id BIGINT(20);
|
||||
|
||||
-- savings transaction variables
|
||||
declare v_savings_transaction_id BIGINT(20);
|
||||
declare v_transaction_amount DECIMAL(19,6);
|
||||
|
||||
|
||||
declare cursor1 cursor for
|
||||
select sa.currency_code, sa.annual_fee_amount
|
||||
from m_savings_account sa where sa.annual_fee_amount is not null and sa.annual_fee_on_month is not null and sa.annual_fee_on_day is not null group by sa.currency_code;
|
||||
|
||||
declare cursor2 cursor for
|
||||
select sa.id, sa.annual_fee_amount, sa.annual_fee_on_month, sa.annual_fee_on_day, sa.annual_fee_next_due_date from m_savings_account sa where sa.currency_code=v_currency_code and sa.annual_fee_amount is not null and sa.annual_fee_on_month is not null and sa.annual_fee_on_day is not null;
|
||||
|
||||
declare cursor3 cursor for
|
||||
select sat.id, sat.amount from m_savings_account_transaction sat
|
||||
where sat.savings_account_id=v_account_id and sat.transaction_type_enum=5;
|
||||
|
||||
declare continue handler for not found
|
||||
set no_more_rows := true;
|
||||
|
||||
open cursor1;
|
||||
LOOP1: loop
|
||||
fetch cursor1 into v_currency_code, v_annual_fee_amount_charge_def;
|
||||
|
||||
if no_more_rows then
|
||||
close cursor1;
|
||||
leave LOOP1;
|
||||
end if;
|
||||
|
||||
-- set annual fee name
|
||||
set t_annual_fee_name = CONCAT('Annual fee - ',v_currency_code);
|
||||
|
||||
-- get charge id if already exists
|
||||
set t_charge_id = (select id from m_charge where name = t_annual_fee_name);
|
||||
|
||||
if t_charge_id is null then
|
||||
|
||||
-- add annual fee to charges
|
||||
INSERT INTO `m_charge` (`name`, `currency_code`, `charge_applies_to_enum`, `charge_time_enum`, `charge_calculation_enum`, `charge_payment_mode_enum`, `amount`, `is_penalty`, `is_active`, `is_deleted`) VALUES (t_annual_fee_name, v_currency_code, 2, 6, 1, 0, v_annual_fee_amount_charge_def, 0, 1, 0);
|
||||
|
||||
-- get inserted charge id
|
||||
set t_charge_id = last_insert_id();
|
||||
|
||||
end if;
|
||||
|
||||
open cursor2;
|
||||
LOOP2: loop
|
||||
fetch cursor2 into v_account_id, v_annual_fee_amount, v_annual_fee_on_month, v_annual_fee_on_day, v_annual_fee_next_due_date;
|
||||
|
||||
if no_more_rows then
|
||||
set no_more_rows := false;
|
||||
close cursor2;
|
||||
leave LOOP2;
|
||||
end if;
|
||||
|
||||
if not exists (select id from m_savings_account_charge sac where
|
||||
sac.savings_account_id=v_account_id and sac.charge_id=t_charge_id and sac.charge_time_enum=6) then
|
||||
|
||||
-- attach annual charge to savings
|
||||
INSERT INTO `m_savings_account_charge` (`savings_account_id`, `charge_id`, `is_penalty`, `charge_time_enum`, `charge_due_date`, `fee_on_month`, `fee_on_day`, `charge_calculation_enum`, `calculation_percentage`, `calculation_on_amount`, `amount`, `amount_paid_derived`, `amount_waived_derived`, `amount_writtenoff_derived`, `amount_outstanding_derived`, `is_paid_derived`, `waived`, `is_active`) VALUES (v_account_id, t_charge_id, 0, 6, v_annual_fee_next_due_date, v_annual_fee_on_month, v_annual_fee_on_day, 1, NULL, NULL, v_annual_fee_amount, NULL, NULL, NULL, v_annual_fee_amount, 0, 0, 1);
|
||||
|
||||
-- set savings account charge id
|
||||
set t_savings_charge_id = last_insert_id();
|
||||
|
||||
else
|
||||
|
||||
set t_savings_charge_id = (select id from m_savings_account_charge sac where sac.savings_account_id=v_account_id and sac.charge_id=t_charge_id and sac.charge_time_enum=6);
|
||||
|
||||
end if;
|
||||
|
||||
open cursor3;
|
||||
LOOP3: loop
|
||||
fetch cursor3 into v_savings_transaction_id, v_transaction_amount;
|
||||
|
||||
if no_more_rows then
|
||||
set no_more_rows := false;
|
||||
close cursor3;
|
||||
leave LOOP3;
|
||||
end if;
|
||||
|
||||
if not exists (select id from m_savings_account_charge_paid_by sacp where
|
||||
sacp.savings_account_transaction_id=v_savings_transaction_id and sacp.savings_account_charge_id=t_savings_charge_id) then
|
||||
|
||||
-- insert a record into savings account charge paid by
|
||||
INSERT INTO `m_savings_account_charge_paid_by` (`savings_account_transaction_id`, `savings_account_charge_id`, `amount`) VALUES(v_savings_transaction_id, t_savings_charge_id, v_transaction_amount);
|
||||
|
||||
end if;
|
||||
|
||||
end loop LOOP3;
|
||||
end loop LOOP2;
|
||||
end loop LOOP1;
|
||||
end //
|
||||
|
||||
delimiter ;
|
||||
|
||||
call migrate_withdrwal_fees();
|
||||
call migrate_annual_fees();
|
||||
|
||||
drop procedure if exists migrate_annual_fees;
|
||||
drop procedure if exists migrate_withdrwal_fees;
|
||||
|
||||
|
||||
ALTER TABLE `m_savings_account`
|
||||
DROP COLUMN `annual_fee_amount`,
|
||||
DROP COLUMN `annual_fee_on_month`,
|
||||
DROP COLUMN `annual_fee_on_day`,
|
||||
DROP COLUMN `annual_fee_next_due_date`;
|
||||
DROP COLUMN `annual_fee_next_due_date`,
|
||||
DROP COLUMN `withdrawal_fee_amount`,
|
||||
DROP COLUMN `withdrawal_fee_type_enum`;
|
||||
|
||||
ALTER TABLE `m_savings_product`
|
||||
DROP COLUMN `annual_fee_amount`,
|
||||
DROP COLUMN `annual_fee_on_month`,
|
||||
DROP COLUMN `annual_fee_on_day`;
|
||||
DROP COLUMN `annual_fee_on_day`;
|
||||
|
||||
+14
-2
@@ -293,8 +293,20 @@ public class JsonParserHelper {
|
||||
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
|
||||
final String valueAsString = primitive.getAsString();
|
||||
if (StringUtils.isNotBlank(valueAsString)) {
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(dateFormat).withLocale(clientApplicationLocale);
|
||||
value = MonthDay.parse(valueAsString.toLowerCase(clientApplicationLocale), formatter);
|
||||
try {
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(dateFormat).withLocale(clientApplicationLocale);
|
||||
value = MonthDay.parse(valueAsString.toLowerCase(clientApplicationLocale), formatter);
|
||||
} catch (final IllegalArgumentException e) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.month.day",
|
||||
"The parameter " + parameterName + " is invalid based on the dateFormat: '" + dateFormat
|
||||
+ "' and locale: '" + clientApplicationLocale + "' provided:", parameterName, valueAsString,
|
||||
dateFormat);
|
||||
dataValidationErrors.add(error);
|
||||
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -169,6 +169,7 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
public SavingsAccountChargeData toSavingsAccountChargeData() {
|
||||
|
||||
final Long savingsChargeId = null;
|
||||
final Long savingsAccountId = null;
|
||||
final BigDecimal amountPaid = BigDecimal.ZERO;
|
||||
final BigDecimal amountWaived = BigDecimal.ZERO;
|
||||
final BigDecimal amountWrittenOff = BigDecimal.ZERO;
|
||||
@@ -179,7 +180,7 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final LocalDate dueAsOfDate = null;
|
||||
final MonthDay feeOnMonthDay = null;
|
||||
|
||||
return SavingsAccountChargeData.instance(savingsChargeId, this.id, this.name, this.currency, this.amount, amountPaid, amountWaived,
|
||||
return SavingsAccountChargeData.instance(savingsChargeId, this.id, savingsAccountId, this.name, this.currency, this.amount, amountPaid, amountWaived,
|
||||
amountWrittenOff, amountOutstanding, this.chargeTimeType, dueAsOfDate, this.chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, chargeOptions, this.penalty, feeOnMonthDay);
|
||||
}
|
||||
|
||||
+1
-1
@@ -117,7 +117,7 @@ public class Charge extends AbstractPersistable<Long> {
|
||||
|
||||
if (!ChargeTimeType.fromInt(getChargeTime()).isWithdrawalFee() && ChargeCalculationType.fromInt(getChargeCalculation()).isPercentageOfAmount()) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(this.chargeCalculation)
|
||||
.failWithCodeNoParameterAddedToErrorCode("charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
||||
.failWithCodeNoParameterAddedToErrorCode("savings.charge.calculation.type.percentage.allowed.only.for.withdrawal");
|
||||
}
|
||||
|
||||
} else if (isLoanCharge()) {
|
||||
|
||||
+3
-2
@@ -49,7 +49,7 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
public List<EnumOptionData> retrieveCollectionTimeTypes() {
|
||||
final List<EnumOptionData> chargeTimeTypes = new ArrayList<EnumOptionData>();
|
||||
for (final ChargeTimeType chargeTimeType : ChargeTimeType.values()) {
|
||||
if (ChargeTimeType.INVALID.equals(chargeTimeType)) {
|
||||
if (ChargeTimeType.INVALID.equals(chargeTimeType) || ChargeTimeType.SAVINGS_CLOSURE.equals(chargeTimeType)) {
|
||||
continue;
|
||||
}
|
||||
chargeTimeTypes.add(ChargeEnumerations.chargeTimeType(chargeTimeType));
|
||||
@@ -81,7 +81,8 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveSavingsCollectionTimeTypes() {
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE), chargeTimeType(ChargeTimeType.SAVINGS_ACTIVATION),
|
||||
chargeTimeType(ChargeTimeType.SAVINGS_CLOSURE), chargeTimeType(ChargeTimeType.WITHDRAWAL_FEE),
|
||||
//chargeTimeType(ChargeTimeType.SAVINGS_CLOSURE),
|
||||
chargeTimeType(ChargeTimeType.WITHDRAWAL_FEE),
|
||||
chargeTimeType(ChargeTimeType.ANNUAL_FEE));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -164,7 +164,7 @@ public class SavingsApiConstants {
|
||||
interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
|
||||
lockinPeriodFrequencyTypeParamName,
|
||||
//withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
//withdrawalFeeForTransfersParamName,
|
||||
withdrawalFeeForTransfersParamName,
|
||||
feeAmountParamName, feeOnMonthDayParamName, chargesParamName));
|
||||
|
||||
/**
|
||||
|
||||
+11
-5
@@ -10,15 +10,17 @@ import org.joda.time.LocalDate;
|
||||
public class SavingsAccountAnnualFeeData {
|
||||
|
||||
private final Long id;
|
||||
private final Long accountId;
|
||||
private final String accountNo;
|
||||
private final LocalDate nextAnnualFeeDueDate;
|
||||
|
||||
public static SavingsAccountAnnualFeeData instance(final Long id, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||
return new SavingsAccountAnnualFeeData(id, accountNo, nextAnnualFeeDueDate);
|
||||
public static SavingsAccountAnnualFeeData instance(final Long id, final Long accountId, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||
return new SavingsAccountAnnualFeeData(id, accountId, accountNo, nextAnnualFeeDueDate);
|
||||
}
|
||||
|
||||
private SavingsAccountAnnualFeeData(final Long id, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||
private SavingsAccountAnnualFeeData(final Long id, final Long accountId, final String accountNo, final LocalDate nextAnnualFeeDueDate) {
|
||||
this.id = id;
|
||||
this.accountId = accountId;
|
||||
this.accountNo = accountNo;
|
||||
this.nextAnnualFeeDueDate = nextAnnualFeeDueDate;
|
||||
}
|
||||
@@ -27,11 +29,15 @@ public class SavingsAccountAnnualFeeData {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getAccountNo() {
|
||||
return this.accountNo;
|
||||
public Long getAccountId() {
|
||||
return this.accountId;
|
||||
}
|
||||
|
||||
public LocalDate getNextAnnualFeeDueDate() {
|
||||
return this.nextAnnualFeeDueDate;
|
||||
}
|
||||
|
||||
public String getAccountNo() {
|
||||
return this.accountNo;
|
||||
}
|
||||
}
|
||||
+9
-4
@@ -25,6 +25,9 @@ public class SavingsAccountChargeData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long chargeId;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long accountId;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final String name;
|
||||
@@ -73,6 +76,7 @@ public class SavingsAccountChargeData {
|
||||
public static SavingsAccountChargeData template(final Collection<ChargeData> chargeOptions) {
|
||||
final Long id = null;
|
||||
final Long chargeId = null;
|
||||
final Long accountId = null;
|
||||
final String name = null;
|
||||
final CurrencyData currency = null;
|
||||
final BigDecimal amount = BigDecimal.ZERO;
|
||||
@@ -89,29 +93,30 @@ public class SavingsAccountChargeData {
|
||||
final MonthDay feeOnMonthDay = null;
|
||||
|
||||
|
||||
return new SavingsAccountChargeData(id, chargeId, name, chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
|
||||
return new SavingsAccountChargeData(id, chargeId, accountId, name, chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding, chargeOptions,
|
||||
penalty, feeOnMonthDay);
|
||||
}
|
||||
|
||||
public static SavingsAccountChargeData instance(final Long id, final Long chargeId, final String name, final CurrencyData currency,
|
||||
public static SavingsAccountChargeData instance(final Long id, final Long chargeId, final Long accountId, final String name, final CurrencyData currency,
|
||||
final BigDecimal amount, final BigDecimal amountPaid, final BigDecimal amountWaived, final BigDecimal amountWrittenOff,
|
||||
final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType, final LocalDate dueAsOfDate,
|
||||
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty, final MonthDay feeOnMonthDay) {
|
||||
|
||||
return new SavingsAccountChargeData(id, chargeId, name, chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
|
||||
return new SavingsAccountChargeData(id, chargeId, accountId, name, chargeTimeType, dueAsOfDate, chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, currency, amount, amountPaid, amountWaived, amountWrittenOff, amountOutstanding, chargeOptions,
|
||||
penalty, feeOnMonthDay);
|
||||
}
|
||||
|
||||
private SavingsAccountChargeData(final Long id, final Long chargeId, final String name, final EnumOptionData chargeTimeType,
|
||||
private SavingsAccountChargeData(final Long id, final Long chargeId, final Long accountId, final String name, final EnumOptionData chargeTimeType,
|
||||
final LocalDate dueAsOfDate, final EnumOptionData chargeCalculationType, final BigDecimal percentage,
|
||||
final BigDecimal amountPercentageAppliedTo, final CurrencyData currency, final BigDecimal amount, final BigDecimal amountPaid,
|
||||
final BigDecimal amountWaived, final BigDecimal amountWrittenOff, final BigDecimal amountOutstanding,
|
||||
final Collection<ChargeData> chargeOptions, final boolean penalty, final MonthDay feeOnMonthDay) {
|
||||
this.id = id;
|
||||
this.chargeId = chargeId;
|
||||
this.accountId = accountId;
|
||||
this.name = name;
|
||||
this.chargeTimeType = chargeTimeType;
|
||||
this.dueDate = dueAsOfDate;
|
||||
|
||||
+13
-1
@@ -1212,6 +1212,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
}
|
||||
} else if (transactionToUndo.isWaiveCharge()) {
|
||||
chargeToUndo.undoWaiver(this.getCurrency(), transactionToUndo.getAmount(this.getCurrency()));
|
||||
chargeToUndo.updateToPreviousAnnualFeeDueDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1678,6 +1679,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final Money amountWaived = savingsAccountCharge.waive(getCurrency());
|
||||
|
||||
handleWaiverChargeTransactions(savingsAccountCharge, amountWaived);
|
||||
|
||||
//update next annual fee due date
|
||||
savingsAccountCharge.updateToNextAnnualFeeDueDate();
|
||||
}
|
||||
|
||||
public void addCharge(final DateTimeFormatter formatter, final SavingsAccountCharge savingsAccountCharge, final Charge chargeDefinition) {
|
||||
@@ -1733,13 +1737,21 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
"multiple.annual.fee.per.account.not.supported");
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if(isActive()){
|
||||
savingsAccountCharge.updateToNextAnnualFeeDueDateFrom(getActivationLocalDate());
|
||||
}else if(isApproved()){
|
||||
savingsAccountCharge.updateToNextAnnualFeeDueDateFrom(getApprovedOnLocalDate());
|
||||
}
|
||||
//if account is in submitted and pending approval state,
|
||||
//upon account activation annual fee charges due date get updated.
|
||||
}
|
||||
|
||||
//activation charge and withdrawal charges not required this validation
|
||||
if(savingsAccountCharge.isOnSpecifiedDueDate()){
|
||||
validateActivityNotBeforeClientOrGroupTransferDate(SavingsEvent.SAVINGS_APPLY_CHARGE, chargeDueDate);
|
||||
}
|
||||
|
||||
|
||||
// add new charge to savings account
|
||||
charges().add(savingsAccountCharge);
|
||||
|
||||
|
||||
+16
-5
@@ -211,7 +211,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean isPostInterestCalculationRequired(){
|
||||
return this.isDeposit() || this.isWithdrawal() || this.isPayCharge();
|
||||
return this.isDeposit() || this.isChargeTransaction();
|
||||
}
|
||||
|
||||
public boolean isInterestPostingAndNotReversed() {
|
||||
@@ -278,7 +278,14 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public void updateCumulativeBalanceAndDates(final MonetaryCurrency currency, final LocalDate endOfBalanceDate) {
|
||||
this.balanceEndDate = endOfBalanceDate.toDate();
|
||||
//balance end date should not be before transaction date
|
||||
if (endOfBalanceDate != null && endOfBalanceDate.isBefore(this.transactionLocalDate())){
|
||||
this.balanceEndDate = this.transactionLocalDate().toDate();
|
||||
}else if(endOfBalanceDate != null){
|
||||
this.balanceEndDate = endOfBalanceDate.toDate();
|
||||
}else{
|
||||
this.balanceEndDate = null;
|
||||
}
|
||||
this.balanceNumberOfDays = LocalDateInterval.create(getTransactionLocalDate(), endOfBalanceDate).daysInPeriodInclusiveOfEndDate();
|
||||
this.cumulativeBalance = Money.of(currency, this.runningBalance).multipliedBy(this.balanceNumberOfDays).getAmount();
|
||||
}
|
||||
@@ -374,7 +381,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
if (isDeposit()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isWithdrawalFeeAndNotReversed()) {
|
||||
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
}
|
||||
|
||||
@@ -390,7 +397,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
Money endOfDayBalance = openingBalance.copy();
|
||||
if (isDeposit()) {
|
||||
endOfDayBalance = openingBalance.plus(getAmount(currency));
|
||||
} else if (isWithdrawal() || isWithdrawalFeeAndNotReversed()) {
|
||||
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
|
||||
|
||||
if (openingBalance.isGreaterThanZero()) {
|
||||
endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
@@ -420,7 +427,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
// if (endOfDayBalance.isLessThanZero()) {
|
||||
endOfDayBalance = Money.of(currency, this.runningBalance);
|
||||
// }
|
||||
} else if (isWithdrawal() || isWithdrawalFeeAndNotReversed()) {
|
||||
} else if (isWithdrawal() || isChargeTransactionAndNotReversed()) {
|
||||
// endOfDayBalance = openingBalance.minus(getAmount(currency));
|
||||
// if (endOfDayBalance.isLessThanZero()) {
|
||||
endOfDayBalance = Money.of(currency, this.runningBalance);
|
||||
@@ -471,6 +478,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isChargeTransaction();
|
||||
}
|
||||
|
||||
public boolean isChargeTransactionAndNotReversed(){
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isChargeTransaction() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isWaiveCharge(){
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isWaiveCharge();
|
||||
}
|
||||
|
||||
+5
@@ -8,6 +8,7 @@ package org.mifosplatform.portfolio.savings.service;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeData;
|
||||
|
||||
public interface SavingsAccountChargeReadPlatformService {
|
||||
@@ -17,4 +18,8 @@ public interface SavingsAccountChargeReadPlatformService {
|
||||
Collection<SavingsAccountChargeData> retrieveSavingsAccountCharges(Long savingsAccountId);
|
||||
|
||||
SavingsAccountChargeData retrieveSavingsAccountChargeDetails(Long savingsAccountChargeId, Long savingsAccountId);
|
||||
|
||||
Collection<SavingsAccountAnnualFeeData> retrieveChargesWithAnnualFeeDue();
|
||||
|
||||
Collection<SavingsAccountAnnualFeeData> retrieveChargesWithDue();
|
||||
}
|
||||
|
||||
+65
-5
@@ -19,10 +19,13 @@ import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.charge.data.ChargeData;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.mifosplatform.portfolio.charge.exception.SavingsAccountChargeNotFoundException;
|
||||
import org.mifosplatform.portfolio.charge.service.ChargeDropdownReadPlatformService;
|
||||
import org.mifosplatform.portfolio.charge.service.ChargeEnumerations;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountChargeData;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -35,6 +38,9 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final PlatformSecurityContext context;
|
||||
private final ChargeDropdownReadPlatformService chargeDropdownReadPlatformService;
|
||||
|
||||
//mappers
|
||||
private final SavingsAccountChargeDueMapper chargeDueMapper;
|
||||
|
||||
@Autowired
|
||||
public SavingsAccountChargeReadPlatformServiceImpl(final PlatformSecurityContext context,
|
||||
@@ -42,12 +48,13 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
this.context = context;
|
||||
this.chargeDropdownReadPlatformService = chargeDropdownReadPlatformService;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.chargeDueMapper = new SavingsAccountChargeDueMapper();
|
||||
}
|
||||
|
||||
private static final class SavingsAccountChargeMapper implements RowMapper<SavingsAccountChargeData> {
|
||||
|
||||
public String schema() {
|
||||
return "sc.id as id, c.id as chargeId, c.name as name, "
|
||||
return "sc.id as id, c.id as chargeId, sc.savings_account_id as accountId, c.name as name, "
|
||||
+ "sc.amount as amountDue, "
|
||||
+ "sc.amount_paid_derived as amountPaid, "
|
||||
+ "sc.amount_waived_derived as amountWaived, "
|
||||
@@ -72,6 +79,7 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long chargeId = rs.getLong("chargeId");
|
||||
final Long accountId = rs.getLong("accountId");
|
||||
final String name = rs.getString("name");
|
||||
final BigDecimal amount = rs.getBigDecimal("amountDue");
|
||||
final BigDecimal amountPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amountPaid");
|
||||
@@ -102,16 +110,16 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
if (feeOnDay != null) {
|
||||
feeOnMonthDay = new MonthDay(feeOnMonth, feeOnDay);
|
||||
}
|
||||
|
||||
|
||||
final int chargeCalculation = rs.getInt("chargeCalculation");
|
||||
final EnumOptionData chargeCalculationType = ChargeEnumerations.chargeCalculationType(chargeCalculation);
|
||||
final boolean penalty = rs.getBoolean("penalty");
|
||||
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
|
||||
return SavingsAccountChargeData.instance(id, chargeId, name, currency, amount, amountPaid, amountWaived, amountWrittenOff,
|
||||
amountOutstanding, chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf, amountPercentageAppliedTo,
|
||||
chargeOptions, penalty, feeOnMonthDay);
|
||||
return SavingsAccountChargeData.instance(id, chargeId, accountId, name, currency, amount, amountPaid, amountWaived,
|
||||
amountWrittenOff, amountOutstanding, chargeTimeType, dueAsOfDate, chargeCalculationType, percentageOf,
|
||||
amountPercentageAppliedTo, chargeOptions, penalty, feeOnMonthDay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,4 +169,56 @@ public class SavingsAccountChargeReadPlatformServiceImpl implements SavingsAccou
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanId });
|
||||
}
|
||||
|
||||
private static final class SavingsAccountChargeDueMapper implements RowMapper<SavingsAccountAnnualFeeData> {
|
||||
|
||||
private final String schemaSql;
|
||||
|
||||
public SavingsAccountChargeDueMapper() {
|
||||
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||
sqlBuilder.append("sac.id as id, ");
|
||||
sqlBuilder.append("sa.id as accountId, ");
|
||||
sqlBuilder.append("sa.account_no as accountNo, ");
|
||||
sqlBuilder.append("sac.charge_due_date as dueDate ");
|
||||
sqlBuilder.append("from m_savings_account_charge sac join m_savings_account sa on sac.savings_account_id = sa.id ");
|
||||
|
||||
this.schemaSql = sqlBuilder.toString();
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
return this.schemaSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SavingsAccountAnnualFeeData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long accountId = rs.getLong("accountId");
|
||||
final String accountNo = rs.getString("accountNo");
|
||||
final LocalDate annualFeeNextDueDate = JdbcSupport.getLocalDate(rs, "dueDate");
|
||||
|
||||
return SavingsAccountAnnualFeeData.instance(id, accountId, accountNo, annualFeeNextDueDate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithAnnualFeeDue() {
|
||||
final String sql = "select " + this.chargeDueMapper.schema() + " where sac.charge_due_date is not null and sac.charge_time_enum = "
|
||||
+ ChargeTimeType.ANNUAL_FEE.getValue() + " and sac.charge_due_date <= NOW() and sa.status_enum = "
|
||||
+ SavingsAccountStatusType.ACTIVE.getValue();
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SavingsAccountAnnualFeeData> retrieveChargesWithDue() {
|
||||
final String sql = "select "
|
||||
+ this.chargeDueMapper.schema()
|
||||
+ " where sac.charge_due_date is not null and sac.charge_due_date <= NOW() and sac.waived = 0 and sac.is_paid_derived=0 and sac.is_active=1 and sa.status_enum = "
|
||||
+ SavingsAccountStatusType.ACTIVE.getValue() + " order by sac.charge_due_date ";
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.chargeDueMapper, new Object[] {});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult withdrawal(Long savingsId, JsonCommand command);
|
||||
|
||||
/*CommandProcessingResult applyAnnualFee(Long savingsId, LocalDate annualFeeTransactionDate);*/
|
||||
CommandProcessingResult applyAnnualFee(final Long savingsAccountChargeId, final Long accountId);
|
||||
|
||||
CommandProcessingResult calculateInterest(Long savingsId);
|
||||
|
||||
@@ -52,5 +52,5 @@ public interface SavingsAccountWritePlatformService {
|
||||
|
||||
CommandProcessingResult payCharge(Long savingsAccountId, Long savingsAccountChargeId, JsonCommand command);
|
||||
|
||||
void processDueCharges();
|
||||
void applyChargeDue(final Long savingsAccountChargeId, final Long accountId);
|
||||
}
|
||||
+18
-34
@@ -248,36 +248,25 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.build();
|
||||
}
|
||||
|
||||
/*@Transactional
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult applyAnnualFee(final Long savingsId, final LocalDate annualFeeTransactionDate) {
|
||||
public CommandProcessingResult applyAnnualFee(final Long savingsAccountChargeId, final Long accountId) {
|
||||
|
||||
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
|
||||
checkClientOrGroupActive(account);
|
||||
final SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, accountId);
|
||||
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
|
||||
final Set<Long> existingTransactionIds = new HashSet<Long>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<Long>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
final SavingsAccountTransaction annualFee = account.addAnnualFee(mc, fmt, annualFeeTransactionDate, today);
|
||||
final Long transactionId = saveTransactionToGenerateTransactionId(annualFee);
|
||||
this.savingAccountRepository.save(account);
|
||||
|
||||
postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
this.payCharge(savingsAccountCharge, savingsAccountCharge.getDueLocalDate(), savingsAccountCharge.amount(), fmt);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(transactionId) //
|
||||
.withOfficeId(account.officeId()) //
|
||||
.withClientId(account.clientId()) //
|
||||
.withGroupId(account.groupId()) //
|
||||
.withSavingsId(savingsId) //
|
||||
.withEntityId(savingsAccountCharge.getId()) //
|
||||
.withOfficeId(savingsAccountCharge.savingsAccount().officeId()) //
|
||||
.withClientId(savingsAccountCharge.savingsAccount().clientId()) //
|
||||
.withGroupId(savingsAccountCharge.savingsAccount().groupId()) //
|
||||
.withSavingsId(savingsAccountCharge.savingsAccount().getId()) //
|
||||
.build();
|
||||
}*/
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -828,21 +817,16 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.PAY_DUE_SAVINGS_CHARGES)
|
||||
public void processDueCharges() {
|
||||
public void applyChargeDue(final Long savingsAccountChargeId, final Long accountId) {
|
||||
// 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 SavingsAccountCharge savingsAccountCharge = this.savingsAccountChargeRepository.findOneWithNotFoundDetection(
|
||||
savingsAccountChargeId, accountId);
|
||||
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd MM yyyy");
|
||||
for (SavingsAccountCharge savingsAccountCharge : pendingCharges) {
|
||||
try {
|
||||
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt);
|
||||
} catch (Exception exception) {
|
||||
// TODO: AA - provide a meaningful error with failed
|
||||
// transactions list
|
||||
}
|
||||
}
|
||||
payCharge(savingsAccountCharge, transactionDate, savingsAccountCharge.amoutOutstanding(), fmt);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -857,7 +841,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
account.payCharge(savingsAccountCharge, amountPaid, transactionDate, formatter);
|
||||
|
||||
final MathContext mc = MathContext.DECIMAL64;
|
||||
if (account.isBeforeLastPostingPeriod(savingsAccountCharge.getDueLocalDate())) {
|
||||
if (account.isBeforeLastPostingPeriod(transactionDate)) {
|
||||
final LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
account.postInterest(mc, today);
|
||||
} else {
|
||||
|
||||
+2
@@ -14,4 +14,6 @@ public interface ScheduledJobRunnerService {
|
||||
void updateLoanPaidInAdvance();
|
||||
|
||||
void applyAnnualFeeForSavings();
|
||||
|
||||
void applyDueChargesForSavings();
|
||||
}
|
||||
|
||||
+38
-11
@@ -5,11 +5,17 @@
|
||||
*/
|
||||
package org.mifosplatform.scheduledjobs.service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSourceServiceFactory;
|
||||
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.mifosplatform.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.mifosplatform.infrastructure.jobs.service.JobName;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||
import org.mifosplatform.portfolio.savings.data.SavingsAccountAnnualFeeData;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountChargeReadPlatformService;
|
||||
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -24,18 +30,16 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
private final static Logger logger = LoggerFactory.getLogger(ScheduledJobRunnerServiceImpl.class);
|
||||
|
||||
private final RoutingDataSourceServiceFactory dataSourceServiceFactory;
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
|
||||
private final SavingsAccountChargeReadPlatformService savingsAccountChargeReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public ScheduledJobRunnerServiceImpl(final RoutingDataSourceServiceFactory dataSourceServiceFactory,
|
||||
final SavingsAccountWritePlatformService savingsAccountWritePlatformService,
|
||||
final SavingsAccountReadPlatformService savingsAccountReadPlatformService) {
|
||||
final SavingsAccountChargeReadPlatformService savingsAccountChargeReadPlatformService) {
|
||||
this.dataSourceServiceFactory = dataSourceServiceFactory;
|
||||
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
|
||||
this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
|
||||
this.savingsAccountChargeReadPlatformService = savingsAccountChargeReadPlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -194,27 +198,50 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Results affected by update: " + result);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.APPLY_ANNUAL_FEE_FOR_SAVINGS)
|
||||
public void applyAnnualFeeForSavings() {
|
||||
|
||||
/*final Collection<SavingsAccountAnnualFeeData> annualFeeData = this.savingsAccountReadPlatformService
|
||||
.retrieveAccountsWithAnnualFeeDue();
|
||||
final Collection<SavingsAccountAnnualFeeData> annualFeeData = this.savingsAccountChargeReadPlatformService
|
||||
.retrieveChargesWithAnnualFeeDue();
|
||||
|
||||
for (final SavingsAccountAnnualFeeData savingsAccountReference : annualFeeData) {
|
||||
try {
|
||||
this.savingsAccountWritePlatformService.applyAnnualFee(savingsAccountReference.getId(),
|
||||
savingsAccountReference.getNextAnnualFeeDueDate());
|
||||
savingsAccountReference.getAccountId());
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
final List<ApiParameterError> errors = e.getErrors();
|
||||
for (final ApiParameterError error : errors) {
|
||||
logger.error("Apply annual fee failed for account:" + savingsAccountReference.getAccountNo() + " with message "
|
||||
+ error.getDeveloperMessage());
|
||||
}
|
||||
} catch (final Exception ex){
|
||||
//need to handle this scenario
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Savings accounts affected by update: " + annualFeeData.size());*/
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Savings accounts affected by update: " + annualFeeData.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.PAY_DUE_SAVINGS_CHARGES)
|
||||
public void applyDueChargesForSavings() {
|
||||
final Collection<SavingsAccountAnnualFeeData> chargesDueData = this.savingsAccountChargeReadPlatformService
|
||||
.retrieveChargesWithDue();
|
||||
|
||||
for (final SavingsAccountAnnualFeeData savingsAccountReference : chargesDueData) {
|
||||
try {
|
||||
this.savingsAccountWritePlatformService.applyChargeDue(savingsAccountReference.getId(), savingsAccountReference.getAccountId());
|
||||
} catch (final PlatformApiDataValidationException e) {
|
||||
final List<ApiParameterError> errors = e.getErrors();
|
||||
for (final ApiParameterError error : errors) {
|
||||
logger.error("Apply Charges due for savings failed for account:" + savingsAccountReference.getAccountNo() + " with message "
|
||||
+ error.getDeveloperMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(ThreadLocalContextUtil.getTenant().getName() + ": Savings accounts affected by update: " + chargesDueData.size());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user