| Line 165... |
Line 165... |
| 165 |
|
165 |
|
| 166 |
@Component
|
166 |
@Component
|
| 167 |
@Transactional(rollbackFor = {Throwable.class, ProfitMandiBusinessException.class})
|
167 |
@Transactional(rollbackFor = {Throwable.class, ProfitMandiBusinessException.class})
|
| 168 |
public class ScheduledTasks {
|
168 |
public class ScheduledTasks {
|
| 169 |
|
169 |
|
| - |
|
170 |
// Lock to serialize all methods that write to sd_credit_requirement table.
|
| - |
|
171 |
// Prevents deadlocks and stale-data overwrites from concurrent cron threads.
|
| - |
|
172 |
public static final Object SD_CREDIT_LOCK = new Object();
|
| - |
|
173 |
|
| 170 |
@Value("${oxigen.recharge.enquiry.url}")
|
174 |
@Value("${oxigen.recharge.enquiry.url}")
|
| 171 |
private String oxigenRechargeEnquiryUrl;
|
175 |
private String oxigenRechargeEnquiryUrl;
|
| 172 |
|
176 |
|
| 173 |
@Autowired
|
177 |
@Autowired
|
| 174 |
PurchaseMigration purchaseMigration;
|
178 |
PurchaseMigration purchaseMigration;
|
| Line 3799... |
Line 3803... |
| 3799 |
|
3803 |
|
| 3800 |
@Autowired
|
3804 |
@Autowired
|
| 3801 |
private SanctionRequestRepository sanctionRequestRepository;
|
3805 |
private SanctionRequestRepository sanctionRequestRepository;
|
| 3802 |
|
3806 |
|
| 3803 |
public void calculateInterestAccured() throws ProfitMandiBusinessException {
|
3807 |
public void calculateInterestAccured() throws ProfitMandiBusinessException {
|
| - |
|
3808 |
synchronized (SD_CREDIT_LOCK) {
|
| 3804 |
List<Loan> loans = loanRepository.selectAllActiveLoan();
|
3809 |
List<Loan> loans = loanRepository.selectAllActiveLoan();
|
| 3805 |
|
3810 |
|
| 3806 |
for (Loan loan : loans) {
|
3811 |
for (Loan loan : loans) {
|
| 3807 |
List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());
|
3812 |
List<LoanStatement> loanStatements = loanStatementRepository.selectByLoanId(loan.getId());
|
| 3808 |
Map<LoanReferenceType, Double> loanStatusAmount = loanStatements.stream().collect(groupingBy(
|
3813 |
Map<LoanReferenceType, Double> loanStatusAmount = loanStatements.stream().collect(groupingBy(
|
| 3809 |
x -> x.getLoanReferenceType(), Collectors.summingDouble(x -> x.getAmount().doubleValue())));
|
3814 |
x -> x.getLoanReferenceType(), Collectors.summingDouble(x -> x.getAmount().doubleValue())));
|
| 3810 |
|
3815 |
|
| 3811 |
// Interest starts from this date (inclusive). Under current policy (MIN_FREE_DAYS=1),
|
3816 |
// Interest starts from this date (inclusive). Under current policy (MIN_FREE_DAYS=1),
|
| 3812 |
// this is at minimum createdOn + 1 — billing day is always free.
|
3817 |
// this is at minimum createdOn + 1 — billing day is always free.
|
| 3813 |
LocalDate interestStartDate = com.spice.profitmandi.service.transaction.SDCreditServiceImpl.computeInterestStartDate(loan);
|
3818 |
LocalDate interestStartDate = com.spice.profitmandi.service.transaction.SDCreditServiceImpl.computeInterestStartDate(loan);
|
| 3814 |
|
3819 |
|
| 3815 |
LOGGER.info("Loan id - {}, interestStartDate {}", loan.getId(), interestStartDate);
|
3820 |
LOGGER.info("Loan id - {}, interestStartDate {}", loan.getId(), interestStartDate);
|
| 3816 |
if (!LocalDate.now().isBefore(interestStartDate)) {
|
3821 |
if (!LocalDate.now().isBefore(interestStartDate)) {
|
| 3817 |
int loanStatementId = loanStatementRepository.selectLatestLoanSatement(loan.getFofoId(), loan.getId());
|
3822 |
int loanStatementId = loanStatementRepository.selectLatestLoanSatement(loan.getFofoId(), loan.getId());
|
| 3818 |
LOGGER.info("loanStatementId {}", loanStatementId);
|
3823 |
LOGGER.info("loanStatementId {}", loanStatementId);
|
| 3819 |
if (loanStatementId != 0) {
|
3824 |
if (loanStatementId != 0) {
|
| 3820 |
this.calculateInterest(loan, loanStatusAmount, loanStatementId);
|
3825 |
this.calculateInterest(loan, loanStatusAmount, loanStatementId);
|
| 3821 |
} else {
|
3826 |
} else {
|
| 3822 |
sdCreditService.addInterest(interestStartDate, LocalDate.now(), loan, loanStatusAmount);
|
3827 |
sdCreditService.addInterest(interestStartDate, LocalDate.now(), loan, loanStatusAmount);
|
| - |
|
3828 |
}
|
| 3823 |
}
|
3829 |
}
|
| 3824 |
}
|
3830 |
}
|
| 3825 |
}
|
3831 |
}
|
| 3826 |
}
|
3832 |
}
|
| 3827 |
|
3833 |
|
| Line 3854... |
Line 3860... |
| 3854 |
throw new ProfitMandiBusinessException("loanstament", loanStatement.getLoanId(), "Invalid LoanId");
|
3860 |
throw new ProfitMandiBusinessException("loanstament", loanStatement.getLoanId(), "Invalid LoanId");
|
| 3855 |
}
|
3861 |
}
|
| 3856 |
}
|
3862 |
}
|
| 3857 |
|
3863 |
|
| 3858 |
public void loanSettlement() throws Exception {
|
3864 |
public void loanSettlement() throws Exception {
|
| - |
|
3865 |
synchronized (SD_CREDIT_LOCK) {
|
| 3859 |
List<Loan> loans = loanRepository.selectAllActiveLoanForSettlement().stream().filter(x -> x.canBeSettled()).collect(toList());
|
3866 |
List<Loan> loans = loanRepository.selectAllActiveLoanForSettlement().stream().filter(x -> x.canBeSettled()).collect(toList());
|
| 3860 |
//TODO:Upto here
|
3867 |
//TODO:Upto here
|
| 3861 |
if (!loans.isEmpty()) {
|
3868 |
if (!loans.isEmpty()) {
|
| 3862 |
|
3869 |
|
| 3863 |
for (Loan loan : loans) {
|
3870 |
for (Loan loan : loans) {
|
| 3864 |
LOGGER.info("Loan - {}, {}", loan.getId(), loan.canBeSettled());
|
3871 |
LOGGER.info("Loan - {}, {}", loan.getId(), loan.canBeSettled());
|
| 3865 |
double settledAmount = sdCreditService.settleLoan(loan);
|
3872 |
double settledAmount = sdCreditService.settleLoan(loan);
|
| 3866 |
|
3873 |
|
| 3867 |
List<SanctionRequest> sanctionRequests = sanctionRequestRepository.selectHoldSanctionByFofoId(loan.getFofoId());
|
3874 |
List<SanctionRequest> sanctionRequests = sanctionRequestRepository.selectHoldSanctionByFofoId(loan.getFofoId());
|
| 3868 |
for (SanctionRequest sanctionRequest : sanctionRequests) {
|
3875 |
for (SanctionRequest sanctionRequest : sanctionRequests) {
|
| - |
|
3876 |
|
| - |
|
3877 |
List<Order> orders = orderRepository.selectAllByTransactionId(sanctionRequest.getTransactionId());
|
| - |
|
3878 |
if (orders.size() == 0) {
|
| - |
|
3879 |
LOGGER.info("Could not find orders - for Sanction Request {}", sanctionRequest);
|
| - |
|
3880 |
continue;
|
| - |
|
3881 |
}
|
| 3869 |
|
3882 |
|
| 3870 |
List<Order> orders = orderRepository.selectAllByTransactionId(sanctionRequest.getTransactionId());
|
3883 |
if (settledAmount >= sanctionRequest.getPendingAmount().doubleValue()) {
|
| 3871 |
if (orders.size() == 0) {
|
3884 |
settledAmount -= sanctionRequest.getPendingAmount().doubleValue();
|
| 3872 |
LOGGER.info("Could not find orders - for Sanction Request {}", sanctionRequest);
|
3885 |
sanctionRequest.setPendingAmount(BigDecimal.valueOf(0));
|
| - |
|
3886 |
this.sendUnholdEmail(orders);
|
| 3873 |
continue;
|
3887 |
} else {
|
| - |
|
3888 |
double pendinAmount = sanctionRequest.getPendingAmount().doubleValue() - settledAmount;
|
| - |
|
3889 |
System.out.println("Pending Amount - " + pendinAmount);
|
| - |
|
3890 |
sanctionRequest.setPendingAmount(BigDecimal.valueOf(pendinAmount));
|
| 3874 |
}
|
3891 |
break;
|
| 3875 |
|
3892 |
|
| 3876 |
if (settledAmount >= sanctionRequest.getPendingAmount().doubleValue()) {
|
- |
|
| 3877 |
settledAmount -= sanctionRequest.getPendingAmount().doubleValue();
|
- |
|
| 3878 |
sanctionRequest.setPendingAmount(BigDecimal.valueOf(0));
|
- |
|
| 3879 |
this.sendUnholdEmail(orders);
|
- |
|
| 3880 |
} else {
|
- |
|
| 3881 |
double pendinAmount = sanctionRequest.getPendingAmount().doubleValue() - settledAmount;
|
- |
|
| 3882 |
System.out.println("Pending Amount - " + pendinAmount);
|
- |
|
| 3883 |
sanctionRequest.setPendingAmount(BigDecimal.valueOf(pendinAmount));
|
- |
|
| 3884 |
break;
|
3893 |
}
|
| 3885 |
|
3894 |
|
| 3886 |
}
|
3895 |
}
|
| 3887 |
|
- |
|
| 3888 |
}
|
3896 |
}
|
| 3889 |
}
|
- |
|
| 3890 |
|
3897 |
|
| - |
|
3898 |
}
|
| 3891 |
}
|
3899 |
}
|
| 3892 |
|
3900 |
|
| 3893 |
|
- |
|
| 3894 |
}
|
3901 |
}
|
| 3895 |
|
3902 |
|
| 3896 |
|
3903 |
|
| 3897 |
private void sendUnholdEmail(List<Order> orders) throws Exception {
|
3904 |
private void sendUnholdEmail(List<Order> orders) throws Exception {
|
| 3898 |
|
3905 |
|
| Line 4016... |
Line 4023... |
| 4016 |
}
|
4023 |
}
|
| 4017 |
|
4024 |
|
| 4018 |
}
|
4025 |
}
|
| 4019 |
|
4026 |
|
| 4020 |
public void updatePartnerLimit() throws ProfitMandiBusinessException {
|
4027 |
public void updatePartnerLimit() throws ProfitMandiBusinessException {
|
| - |
|
4028 |
synchronized (SD_CREDIT_LOCK) {
|
| 4021 |
Map<Integer, CustomRetailer> customRetailerMap = retailerService.getFofoRetailers(true);
|
4029 |
Map<Integer, CustomRetailer> customRetailerMap = retailerService.getFofoRetailers(true);
|
| 4022 |
Map<Integer, BigDecimal> fofoSidbiLimitMap = sidbiService.getSuggestedLimitMap();
|
4030 |
Map<Integer, BigDecimal> fofoSidbiLimitMap = sidbiService.getSuggestedLimitMap();
|
| 4023 |
Map<Integer, SDCreditRequirement> sdCreditRequirementMap = sdCreditRequirementRepository.selectAll().stream().collect(Collectors.toMap(x -> x.getFofoId(), x -> x));
|
4031 |
Map<Integer, SDCreditRequirement> sdCreditRequirementMap = sdCreditRequirementRepository.selectAll().stream().collect(Collectors.toMap(x -> x.getFofoId(), x -> x));
|
| 4024 |
Map<Integer, CreditAccount> creditAccountMap = creditAccountRepository.selectAllByGateways(Arrays.asList(Gateway.SIDBI, Gateway.SDDIRECT))
|
4032 |
Map<Integer, CreditAccount> creditAccountMap = creditAccountRepository.selectAllByGateways(Arrays.asList(Gateway.SIDBI, Gateway.SDDIRECT))
|
| 4025 |
.stream().filter(x -> x.isActive()).collect(Collectors.toMap(x -> x.getFofoId(), x -> x));
|
4033 |
.stream().filter(x -> x.isActive()).collect(Collectors.toMap(x -> x.getFofoId(), x -> x));
|
| 4026 |
Map<Integer, BulkCreditSummary> bulkSummaryMap = sdCreditService.getCreditSummaryBulk();
|
4034 |
Map<Integer, BulkCreditSummary> bulkSummaryMap = sdCreditService.getCreditSummaryBulk();
|
| 4027 |
for (Entry<Integer, CustomRetailer> customRetailerEntry : customRetailerMap.entrySet()) {
|
- |
|
| 4028 |
int fofoId = customRetailerEntry.getKey();
|
- |
|
| 4029 |
LocalDateTime firstBillingDate = transactionRepository.getFirstBillingDate(fofoId);
|
- |
|
| 4030 |
|
- |
|
| 4031 |
CreditAccount creditAccount = creditAccountMap.get(fofoId);
|
- |
|
| 4032 |
BulkCreditSummary bulkSummary = bulkSummaryMap.get(fofoId);
|
- |
|
| 4033 |
BigDecimal utilizationAmount = bulkSummary != null ? bulkSummary.getUtilization() : BigDecimal.ZERO;
|
- |
|
| 4034 |
PartnerDailyInvestment partnerDailyInvestment = partnerInvestmentService.getInvestment(fofoId, 0);
|
- |
|
| 4035 |
BigDecimal suggestedAmount = this.getSuggestedAmount(creditAccount, partnerDailyInvestment, utilizationAmount, fofoSidbiLimitMap.get(fofoId));
|
- |
|
| 4036 |
SDCreditRequirement sdCreditRequirement = sdCreditRequirementMap.get(fofoId);
|
- |
|
| 4037 |
|
- |
|
| 4038 |
LOGGER.info("suggestedAmount {} ", suggestedAmount);
|
- |
|
| 4039 |
|
- |
|
| 4040 |
if (sdCreditRequirement == null) {
|
- |
|
| 4041 |
sdCreditRequirement = new SDCreditRequirement();
|
- |
|
| 4042 |
sdCreditRequirement.setFofoId(fofoId);
|
- |
|
| 4043 |
sdCreditRequirement.setCreditDays(15);
|
- |
|
| 4044 |
sdCreditRequirement.setInterestRate(ProfitMandiConstants.NEW_INTEREST_RATE);
|
- |
|
| 4045 |
sdCreditRequirement.setRisk(CreditRisk.HIGH_RISK);
|
- |
|
| 4046 |
sdCreditRequirement.setUtilizedAmount(BigDecimal.ZERO);
|
- |
|
| 4047 |
sdCreditRequirement.setCreateTimestamp(LocalDateTime.now());
|
- |
|
| 4048 |
sdCreditRequirement.setUpdateTimestamp(LocalDateTime.now());
|
- |
|
| 4049 |
sdCreditRequirementRepository.persist(sdCreditRequirement);
|
- |
|
| 4050 |
}
|
- |
|
| 4051 |
|
4035 |
|
| - |
|
4036 |
// Sort by fofoId to ensure deterministic row-locking order and prevent deadlocks
|
| 4052 |
CreditRisk creditRisk = sdCreditService.getCurrentRisk(sdCreditRequirement, firstBillingDate);
|
4037 |
List<Integer> sortedFofoIds = customRetailerMap.keySet().stream().sorted().collect(Collectors.toList());
|
| 4053 |
|
4038 |
|
| 4054 |
sdCreditRequirement.setRisk(creditRisk);
|
4039 |
for (int fofoId : sortedFofoIds) {
|
| - |
|
4040 |
CustomRetailer customRetailer = customRetailerMap.get(fofoId);
|
| - |
|
4041 |
LocalDateTime firstBillingDate = transactionRepository.getFirstBillingDate(fofoId);
|
| 4055 |
|
4042 |
|
| 4056 |
sdCreditRequirement.setSuggestedLimit(suggestedAmount);
|
4043 |
CreditAccount creditAccount = creditAccountMap.get(fofoId);
|
| 4057 |
if (!sdCreditRequirement.isHardLimit()) {
|
4044 |
BulkCreditSummary bulkSummary = bulkSummaryMap.get(fofoId);
|
| - |
|
4045 |
BigDecimal utilizationAmount = bulkSummary != null ? bulkSummary.getUtilization() : BigDecimal.ZERO;
|
| - |
|
4046 |
PartnerDailyInvestment partnerDailyInvestment = partnerInvestmentService.getInvestment(fofoId, 0);
|
| - |
|
4047 |
BigDecimal suggestedAmount = this.getSuggestedAmount(creditAccount, partnerDailyInvestment, utilizationAmount, fofoSidbiLimitMap.get(fofoId));
|
| 4058 |
sdCreditRequirement.setLimit(suggestedAmount);
|
4048 |
SDCreditRequirement sdCreditRequirement = sdCreditRequirementMap.get(fofoId);
|
| 4059 |
}
|
- |
|
| 4060 |
|
4049 |
|
| 4061 |
BigDecimal availableLimit = sdCreditRequirement.getLimit().subtract(utilizationAmount);
|
4050 |
LOGGER.info("suggestedAmount {} ", suggestedAmount);
|
| 4062 |
|
4051 |
|
| - |
|
4052 |
if (sdCreditRequirement == null) {
|
| 4063 |
LOGGER.info("utilizedLimit {} ", utilizationAmount);
|
4053 |
sdCreditRequirement = new SDCreditRequirement();
|
| - |
|
4054 |
sdCreditRequirement.setFofoId(fofoId);
|
| - |
|
4055 |
sdCreditRequirement.setCreditDays(15);
|
| - |
|
4056 |
sdCreditRequirement.setInterestRate(ProfitMandiConstants.NEW_INTEREST_RATE);
|
| - |
|
4057 |
sdCreditRequirement.setRisk(CreditRisk.HIGH_RISK);
|
| - |
|
4058 |
sdCreditRequirement.setUtilizedAmount(BigDecimal.ZERO);
|
| - |
|
4059 |
sdCreditRequirement.setCreateTimestamp(LocalDateTime.now());
|
| - |
|
4060 |
sdCreditRequirement.setUpdateTimestamp(LocalDateTime.now());
|
| - |
|
4061 |
sdCreditRequirementRepository.persist(sdCreditRequirement);
|
| - |
|
4062 |
}
|
| 4064 |
|
4063 |
|
| 4065 |
LOGGER.info("availableLimit {} ", availableLimit);
|
4064 |
CreditRisk creditRisk = sdCreditService.getCurrentRisk(sdCreditRequirement, firstBillingDate);
|
| 4066 |
|
4065 |
|
| 4067 |
sdCreditRequirement.setUtilizedAmount(utilizationAmount);
|
4066 |
sdCreditRequirement.setRisk(creditRisk);
|
| 4068 |
|
4067 |
|
| 4069 |
sdCreditRequirement.setUpdateTimestamp(LocalDateTime.now());
|
4068 |
sdCreditRequirement.setSuggestedLimit(suggestedAmount);
|
| - |
|
4069 |
if (!sdCreditRequirement.isHardLimit()) {
|
| - |
|
4070 |
sdCreditRequirement.setLimit(suggestedAmount);
|
| - |
|
4071 |
}
|
| 4070 |
|
4072 |
|
| 4071 |
if (creditAccount != null) {
|
4073 |
BigDecimal availableLimit = sdCreditRequirement.getLimit().subtract(utilizationAmount);
|
| 4072 |
|
4074 |
|
| 4073 |
creditAccount.setInterestRate(sdCreditRequirement.getInterestRate().floatValue());
|
- |
|
| 4074 |
creditAccount.setSanctionedAmount(sdCreditRequirement.getLimit().floatValue());
|
4075 |
LOGGER.info("utilizedLimit {} ", utilizationAmount);
|
| - |
|
4076 |
|
| 4075 |
creditAccount.setAvailableAmount(availableLimit.floatValue());
|
4077 |
LOGGER.info("availableLimit {} ", availableLimit);
|
| - |
|
4078 |
|
| 4076 |
creditAccount.setFreeDays(sdCreditRequirement.getFreeDays());
|
4079 |
sdCreditRequirement.setUtilizedAmount(utilizationAmount);
|
| - |
|
4080 |
|
| 4077 |
creditAccount.setUpdatedOn(LocalDateTime.now());
|
4081 |
sdCreditRequirement.setUpdateTimestamp(LocalDateTime.now());
|
| 4078 |
}
|
- |
|
| 4079 |
|
4082 |
|
| - |
|
4083 |
if (creditAccount != null) {
|
| - |
|
4084 |
|
| - |
|
4085 |
creditAccount.setInterestRate(sdCreditRequirement.getInterestRate().floatValue());
|
| - |
|
4086 |
creditAccount.setSanctionedAmount(sdCreditRequirement.getLimit().floatValue());
|
| - |
|
4087 |
creditAccount.setAvailableAmount(availableLimit.floatValue());
|
| - |
|
4088 |
creditAccount.setFreeDays(sdCreditRequirement.getFreeDays());
|
| - |
|
4089 |
creditAccount.setUpdatedOn(LocalDateTime.now());
|
| - |
|
4090 |
}
|
| - |
|
4091 |
|
| - |
|
4092 |
}
|
| 4080 |
}
|
4093 |
}
|
| 4081 |
|
4094 |
|
| 4082 |
}
|
4095 |
}
|
| 4083 |
|
4096 |
|
| 4084 |
private static final NavigableMap<Double, Double> discountMap = new TreeMap<>();
|
4097 |
private static final NavigableMap<Double, Double> discountMap = new TreeMap<>();
|
| Line 4134... |
Line 4147... |
| 4134 |
}
|
4147 |
}
|
| 4135 |
return suggestedAmount;
|
4148 |
return suggestedAmount;
|
| 4136 |
}
|
4149 |
}
|
| 4137 |
|
4150 |
|
| 4138 |
public void notifyDefaultLoans() throws ProfitMandiBusinessException, MessagingException, IOException {
|
4151 |
public void notifyDefaultLoans() throws ProfitMandiBusinessException, MessagingException, IOException {
|
| 4139 |
|
- |
|
| - |
|
4152 |
synchronized (SD_CREDIT_LOCK) {
|
| 4140 |
sdCreditService.updateRisk();
|
4153 |
sdCreditService.updateRisk();
|
| 4141 |
List<Loan> defaultLoans = sdCreditService.getDefaultLoans();
|
4154 |
List<Loan> defaultLoans = sdCreditService.getDefaultLoans();
|
| 4142 |
if (!defaultLoans.isEmpty()) {
|
4155 |
if (!defaultLoans.isEmpty()) {
|
| 4143 |
this.sendDefaultLoanAlert(defaultLoans);
|
4156 |
this.sendDefaultLoanAlert(defaultLoans);
|
| - |
|
4157 |
}
|
| 4144 |
}
|
4158 |
}
|
| 4145 |
|
- |
|
| 4146 |
}
|
4159 |
}
|
| 4147 |
|
4160 |
|
| 4148 |
public void sendDefaultLoanAlert(List<Loan> defaultLoans) throws
|
4161 |
public void sendDefaultLoanAlert(List<Loan> defaultLoans) throws
|
| 4149 |
ProfitMandiBusinessException, MessagingException, IOException {
|
4162 |
ProfitMandiBusinessException, MessagingException, IOException {
|
| 4150 |
String subject = "Default Partners";
|
4163 |
String subject = "Default Partners";
|
| Line 5107... |
Line 5120... |
| 5107 |
}
|
5120 |
}
|
| 5108 |
|
5121 |
|
| 5109 |
}
|
5122 |
}
|
| 5110 |
|
5123 |
|
| 5111 |
public void sendMailWhatsAppAfterLoanDueDate() throws Exception {
|
5124 |
public void sendMailWhatsAppAfterLoanDueDate() throws Exception {
|
| - |
|
5125 |
synchronized (SD_CREDIT_LOCK) {
|
| 5112 |
sdCreditService.updateRisk();
|
5126 |
sdCreditService.updateRisk();
|
| 5113 |
List<Loan> defaultLoans = sdCreditService.getDefaultLoans();
|
5127 |
List<Loan> defaultLoans = sdCreditService.getDefaultLoans();
|
| 5114 |
if (!defaultLoans.isEmpty()) {
|
5128 |
if (!defaultLoans.isEmpty()) {
|
| 5115 |
this.sendLoanAlert(defaultLoans);
|
5129 |
this.sendLoanAlert(defaultLoans);
|
| - |
|
5130 |
}
|
| 5116 |
}
|
5131 |
}
|
| 5117 |
|
- |
|
| 5118 |
|
- |
|
| 5119 |
}
|
5132 |
}
|
| 5120 |
|
5133 |
|
| 5121 |
public void sendLoanAlert(List<Loan> defaultLoans) throws
|
5134 |
public void sendLoanAlert(List<Loan> defaultLoans) throws
|
| 5122 |
Exception {
|
5135 |
Exception {
|
| 5123 |
|
5136 |
|