package com.b2k.
command;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.stream.Collectors;
import com.b2k.common.CalendarComponent;
import com.b2k.loan.schedule.ScheduleGenerator;
import com.b2k.schema.EntityDAOService;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.SqlConnection;
public class LoanAccountPaymentConfigReadjust extends EntityAction {
private static final String PERIOD = "period";
private static final String INSTALLMENTFREQ = "installment_freq";
private static final String YEARS = "years";
private static final String MONTHS = "months";
private static final String DAYS = "days";
private static final String AMOUNT = "amount";
private static final String ORDERINGIDX = "ordering_idx";
@Override
public Future<JsonObject> process(Vertx vtx, SqlConnection conn,
EntityDAOService ed,
ActionRequest arInput) {
Promise<JsonObject> prom = Promise.promise();
Future<LocalDate> futResult = Future.succeededFuture();
JsonObject inputData = arInput.getInputList().get(0).getData();
LocalDate actFirstDisbursementDate = LocalDate
.parse(inputData.getString("firstActDisbursementDat
e"));
Boolean rescheduleLoanBool =
inputData.getBoolean("rescheduleLoanBool");
LocalDate currentDate =
LocalDate.parse(inputData.getString("currentDate"));
JsonArray scheduleInfo = inputData.getJsonArray("scheduleInfo");
JsonArray paymentInfo = inputData.getJsonArray("paymentInfo");
JsonArray processedScheduleInfo =
processScheduleInfo(scheduleInfo);
Integer scheduleEnableIndex = null;
if (Boolean.TRUE.equals(rescheduleLoanBool) && scheduleInfo.size()
> 0) {
LocalDate accumulatedDate = actFirstDisbursementDate;
for (int a = 0; a < scheduleInfo.size(); a++) {
JsonObject scheduleValue =
scheduleInfo.getJsonObject(a);
LocalDate scheduleStartDate = accumulatedDate;
JsonObject changeInperiod = new JsonObject()
.put(YEARS, 0)
.put(MONTHS, 0)
.put(DAYS, 0);
JsonObject periodVal = new JsonObject();
if (scheduleValue.containsKey(PERIOD)) {
periodVal =
scheduleValue.getJsonObject(PERIOD);
int totalYears =
periodVal.getInteger(YEARS);
int totalMonths =
periodVal.getInteger(MONTHS);
int totalDays = periodVal.getInteger(DAYS);
accumulatedDate = scheduleStartDate
.plusYears(totalYears)
.plusMonths(totalMonths)
.plusDays(totalDays);
}
CalendarComponent calendar = new
CalendarComponent(conn, ed,
arInput.getContext());
ScheduleGenerator schedGen = new
ScheduleGenerator();
if (accumulatedDate.isAfter(currentDate)) {
LocalDate baseDate = scheduleStartDate;
JsonObject returnPeriod =
calculatePeriod(scheduleStartDate, currentDate);
JsonObject installmentFreq =
scheduleValue.getJsonObject(INSTALLMENTFREQ);
LocalDate changeEndDate =
baseDate.plusYears(returnPeriod.getInteger(YEARS))
.plusMonths(returnPeriod.ge
tInteger(MONTHS))
.plusDays(returnPeriod.getI
nteger(DAYS));
LocalDate loanScheduleEndDate = baseDate
.plusYears(installmentFreq.
getInteger(YEARS))
.plusMonths(installmentFreq
.getInteger(MONTHS))
.plusDays(installmentFreq.g
etInteger(DAYS));
futResult = futResult.compose(ar -> {
return schedGen.adjustPaymentDate(
baseDate,
loanScheduleEndDate, calendar);
});
futResult.onSuccess(date -> {
System.out.println("DATE: " +
date);
});
int totYears =
changeInperiod.getInteger(YEARS)
+
installmentFreq.getInteger(YEARS);
int totMonths =
changeInperiod.getInteger(MONTHS)
+
installmentFreq.getInteger(MONTHS);
int totDays =
changeInperiod.getInteger(DAYS)
+
installmentFreq.getInteger(DAYS);
LocalDate changeInPeriodDate =
baseDate.plusYears(
totYears).plusMonths(totMonths).plusDays(totDays);
while
(changeEndDate.isAfter(loanScheduleEndDate) &&
changeEndDate.isAfter(
changeInPeriodDate)
&&
(installmentFreq.getInteger(YEARS) != 0
||
installmentFreq.getInteger(MONTHS) != 0
||
installmentFreq.getInteger(DAYS) != 0)) {
changeInperiod.put(YEARS,
changeInperiod.getInteger(YEARS)
+
installmentFreq.getInteger(YEARS));
changeInperiod.put(MONTHS,
changeInperiod.getInteger(MONTHS)
+
installmentFreq.getInteger(MONTHS));
changeInperiod.put(DAYS,
changeInperiod.getInteger(DAYS)
+
installmentFreq.getInteger(DAYS));
changeInPeriodDate =
changeInPeriodDate
.plusYears(installm
entFreq.getInteger(YEARS))
.plusMonths(install
mentFreq.getInteger(MONTHS))
.plusDays(installme
ntFreq.getInteger(DAYS));
}
final LocalDate localChangeInperiod =
changeInPeriodDate;
periodVal.put(YEARS,
changeInperiod.getInteger(YEARS));
periodVal.put(MONTHS,
changeInperiod.getInteger(MONTHS));
periodVal.put(DAYS,
changeInperiod.getInteger(DAYS));
if (periodVal.getInteger(YEARS) == 0 &&
periodVal.getInteger(MONTHS) == 0
&&
periodVal.getInteger(DAYS) == 0) {
scheduleEnableIndex = a;
} else {
scheduleEnableIndex = a + 1;
if (processedScheduleInfo.size() ==
scheduleInfo.size()) {
JsonObject newVal =
scheduleValue.copy();
newVal.put("id", "");
processedScheduleInfo.add(scheduleEnableIndex, newVal);
scheduleValue.getJsonObject("balloon_principal").put(AMOUNT,
0);
}
for (int b = a + 1; b <
processedScheduleInfo.size(); b++) {
JsonObject currentField =
processedScheduleInfo
.getJsonObj
ect(b);
if
(currentField.containsKey(ORDERINGIDX)) {
int currentIndex =
currentField
.ge
tInteger(ORDERINGIDX);
currentField.put(ORDERINGIDX, currentIndex + 1);
} else {
currentField.put(ORDERINGIDX, 0);
}
}
}
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd");
JsonArray filteredPaymentInfo = new
JsonArray(
paymentInfo.stream()
.map(JsonOb
ject.class::cast)
.filter(inf
oObj -> {
String expPaymentDate = infoObj
.getString("exp_payment_date");
LocalDate eleDate = LocalDate.parse(
expPaymentDate,
formatter);
return eleDate.equals(
localChangeInperiod);
})
.collect(Co
llectors.toList()));
String scheduleMethod =
scheduleValue.getString("schedule_method");
if
("EQ_INSTALLMENT".equals(scheduleMethod)) {
BigDecimal principalAmount = new
BigDecimal(filteredPaymentInfo
.getJsonObject(0)
.getJsonObject("exp
_principal").getString(AMOUNT));
BigDecimal interestAmount = new
BigDecimal(filteredPaymentInfo
.getJsonObject(0)
.getJsonObject("exp
_interest").getString(AMOUNT));
BigDecimal newAmount =
principalAmount.add(interestAmount);
scheduleValue.getJsonObject("installment").put(AMOUNT, newAmount);
} else if
("EQ_PRINCIPAL".equals(scheduleMethod)) {
BigDecimal principalAmount = new
BigDecimal(filteredPaymentInfo
.getJsonObject(0)
.getJsonObject("exp
_principal").getString(AMOUNT));
scheduleValue.getJsonObject("principal").put(AMOUNT, principalAmount);
}
break;
} else {
scheduleEnableIndex = null;
}
}
JsonObject respObj = new JsonObject().put("scheduleInfo",
scheduleInfo)
.put("field", processedScheduleInfo).put(
"scheduleEnableIndex",
scheduleEnableIndex);
result = respObj;
prom.complete(result);
} else {
prom.complete(null);
}
return prom.future();
}
private static JsonArray processScheduleInfo(JsonArray scheduleInfo) {
JsonArray processedValues = new JsonArray();
for (int i = 0; i < scheduleInfo.size(); i++) {
JsonObject ele = scheduleInfo.getJsonObject(i);
if (ele.containsKey(PERIOD)) {
ele.put(PERIOD,
convertObjectToPeriod(ele.getJsonObject(PERIOD)));
}
if (ele.containsKey(INSTALLMENTFREQ)) {
ele.put(INSTALLMENTFREQ,
convertObjectToPeriod(ele.getJsonObject(INSTALLMENTFREQ)));
}
processedValues.add(ele);
}
processedValues = processedValues.stream()
.map(JsonObject.class::cast)
.sorted(Comparator.comparingInt(o ->
o.getInteger(ORDERINGIDX, Integer.MAX_VALUE)))
.collect(JsonArray::new, JsonArray::add,
JsonArray::addAll);
return processedValues;
}
private static JsonObject convertObjectToPeriod(JsonObject periodObject) {
return periodObject;
}
private static JsonObject calculatePeriod(LocalDate start, LocalDate end) {
JsonObject calculatedPeriod = new JsonObject();
Period period = Period.between(start, end);
calculatedPeriod.put(YEARS, period.getYears())
.put(MONTHS, period.getMonths())
.put(DAYS, period.getDays());
return calculatedPeriod;
}
}