[Home] [Help]
PACKAGE BODY: APPS.LNS_FINANCIALS
Source
1 PACKAGE BODY LNS_FINANCIALS AS
2 /* $Header: LNS_FINANCIAL_B.pls 120.79.12020000.4 2013/02/11 16:13:32 scherkas ship $ */
3
4
5 --------------------------------------------
6 -- declaration of global variables and types
7 --------------------------------------------
8 G_DEBUG_COUNT NUMBER := 0;
9 G_DEBUG BOOLEAN := FALSE;
10 G_FILE_NAME CONSTANT VARCHAR2(30) := 'LNS_FINANCIALS_B.pls';
11 G_PKG_NAME CONSTANT VARCHAR2(30) := 'LNS_FINANCIALS';
12
13 procedure LOAD_ORIGINAL_SCHEDULE(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC,
14 x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL);
15
16 --------------------------------------------
17 -- internal package routines
18 --------------------------------------------
19
20 procedure logMessage(log_level in number
21 ,module in varchar2
22 ,message in varchar2)
23 is
24
25 begin
26
27 IF log_level >= FND_LOG.G_CURRENT_RUNTIME_LEVEL THEN
28 FND_LOG.STRING(log_level, module, message);
29 END IF;
30
31 end;
32
33 -- internal usage only
34 function formatTerm(p_timeString IN varchar2) return varchar2
35 is
36
37 l_temp varchar2(30);
38 begin
39
40 -- this logic is to handle "MONTHLY" => "MONTHS" ETC...
41 if substr(p_timeString, length(p_timeString) - 1, 2) = 'LY' then
42 l_temp := substr(p_timeString, 1, length(p_timeString) - 2) || 'S';
43 else
44 l_temp := p_timeString;
45 end if;
46
47 return l_temp;
48
49 end;
50
51 /*
52 || Overview: debugging routine only
53 ||
54 || Parameter: amortizationTable to log
55 ||
56 || Creation date: 12/08/2003 6:31PM
57 ||
58 */
59 procedure printAmortizationTable(p_amort_tbl IN lns_financials.amortization_tbl)
60
61 is
62
63 l_api_name varchar2(30);
64 i number;
65 l_installment_number varchar2(30);
66 l_due_date varchar2(30);
67 l_principal_amount varchar2(30);
68 l_interest_amount varchar2(30);
69 l_fee_amount varchar2(30);
70 l_other_amount varchar2(30);
71 l_total varchar2(30);
72 l_begin_balance varchar2(30);
73 l_end_balance varchar2(30);
74 l_principal_cumulative varchar2(30);
75 l_interest_cumulative varchar2(30);
76 l_fees_cumulative varchar2(30);
77 l_other_cumulative varchar2(30);
78 l_rate_id varchar2(30);
79
80 begin
81 i := 0;
82 l_api_name := 'printAmortizationTable';
83
84 i := p_amort_tbl.count;
85 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
86 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization table count: ' || i);
87 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Period Due Date TOTAL DUE Interest Principal Fees Other ' ||
88 ' Cum.Interest Cum.Principal Cum.Fees Cum.Other Begin Balance End Balanace ');
89 /*
90 for k in 1..i
91 loop
92 l_installment_number := nvl(to_char(p_amort_tbl(k).installment_number), ' ');
93 l_due_date := nvl(to_char(p_amort_tbl(k).due_date, 'mm/dd/yy'), ' ');
94 l_total := nvl(to_char(p_amort_tbl(k).total), ' ');
95 l_interest_amount := nvl(to_char(p_amort_tbl(k).interest_amount), ' ');
96 l_principal_amount := nvl(to_char(p_amort_tbl(k).principal_amount), ' ');
97 l_other_amount := nvl(to_char(p_amort_tbl(k).other_amount), ' ');
98 l_fee_amount := nvl(to_char(p_amort_tbl(k).fee_amount), ' ');
99 -- l_interest_cumulative := nvl(to_char(p_amort_tbl(k).interest_cumulative), ' ');
100 -- l_principal_cumulative := nvl(to_char(p_amort_tbl(k).principal_cumulative), ' ');
101 -- l_fees_cumulative := nvl(to_char(p_amort_tbl(k).fees_cumulative), ' ');
102 -- l_other_cumulative := nvl(to_char(p_amort_tbl(k).other_cumulative), ' ');
103 -- l_rate_id := nvl(to_char(p_amort_tbl(k).rate_id), ' ');
104 l_begin_balance := nvl(to_char(p_amort_tbl(k).begin_balance), ' ');
105 l_end_balance := nvl(to_char(p_amort_tbl(k).end_balance), ' ');
106
107 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ' || l_installment_number ||
108 ' ' || l_due_date ||
109 ' ' || l_total ||
110 ' ' || l_interest_amount ||
111 ' ' || l_principal_amount ||
112 ' ' || l_other_amount ||
113 ' ' || l_fee_amount ||
114 -- ' ' || l_fees_cumulative ||
115 -- ' ' || l_other_cumulative ||
116 -- ' ' || l_interest_cumulative ||
117 -- ' ' || l_principal_cumulative ||
118 ' ' || l_begin_balance ||
119 ' ' || l_end_balance);
120 end loop;
121 */
122 end printAmortizationTable;
123
124 /* routine will sort loanActivities by activityDate
125 */
126 procedure sortRows(p_loan_activity_tbl in out nocopy LNS_FINANCIALS.LOAN_ACTIVITY_TBL)
127
128 is
129 j number; -- counter
130 l_tmp_row LNS_FINANCIALS.LOAN_ACTIVITY_REC; -- to store temp row
131 l_min date; -- minimum date
132
133 begin
134
135 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, ' - sorting the rows');
136 for i in 1..p_loan_activity_tbl.count loop
137 l_min := p_loan_activity_tbl(i).activity_date;
138
139 for j in i + 1..p_loan_activity_tbl.count loop
140
141 if p_loan_activity_tbl(j).activity_date < l_min then
142 l_min := p_loan_activity_tbl(j).activity_date;
143 l_tmp_row := p_loan_activity_tbl(i);
144 p_loan_activity_tbl(i) := p_loan_activity_tbl(j);
145 p_loan_activity_tbl(j) := l_tmp_row;
146 end if;
147 end loop;
148 end loop;
149 end sortRows;
150
151 /*=========================================================================
152 || PUBLIC PROCEDURE floatingRatePostProcessing
153 ||
154 || DESCRIPTION
155 ||
156 || Overview: handle all post processing steps after BILLLING a FLOATING rate loan
157 ||
158 || Parameter: p_loan_id => loan id
159 || p_period_begin_date => date at which interest was last adjusted
160 || p_annualized_interest_rate => rate for which installment was billed
161 || p_rate_id => rateID for rae
162 ||
163 || Return value:
164 ||
165 || Source Tables:
166 ||
167 || Target Tables: LNS_TERMS, LNS_RATE_SCHEDULES
168 ||
169 || KNOWN ISSUES
170 ||
171 || NOTES
172 || -- POST PROCESSING STEPS recalculate and enter into LNS_TERMS
173 || -- 1. next_rate_change_date
174 || -- 2. new projected rate
175 || -- 3. re-align rate schedule
176 ||
177 || MODIFICATION HISTORY
178 || Date Author Description of Changes
179 || 11/24/2005 11:35AM raverma Created
180 || 06/16/2006 11:35AM karamach Added code to check and update only the existing rate sch row
181 || when begin_installment_number = end_installment_number = p_installment_number for the rate schedule row being processed
182 || as part of the fix for bug5331888
183 ||
184 *=======================================================================*/
185 procedure floatingRatePostProcessing(p_loan_id IN NUMBER
186 ,p_init_msg_list IN VARCHAR2
187 ,p_commit IN VARCHAR2
188 ,p_installment_number IN NUMBER
189 ,p_period_begin_date IN DATE
190 ,p_interest_adjustment_freq IN VARCHAR2
191 ,p_annualized_interest_rate IN NUMBER
192 ,p_rate_id IN OUT NOCOPY NUMBER
193 ,p_phase IN VARCHAR2
194 ,x_return_status OUT NOCOPY VARCHAR2
195 ,x_msg_count OUT NOCOPY NUMBER
196 ,x_msg_data OUT NOCOPY VARCHAR2)
197 is
198 l_next_rate_change date;
199 l_api_name varchar2(30);
200 l_new_rate_id number;
201 l_return_status VARCHAR2(1);
202 l_msg_count NUMBER;
203 l_msg_data VARCHAR2(32767);
204
205 Cursor c_get_rate_sch_info(pRateId number) is
206 select begin_installment_number, end_installment_number
207 from lns_rate_schedules where rate_id = pRateId;
208 l_begin_inst_num number;
209 l_end_inst_num number;
210 BEGIN
211
212 l_api_name := 'floatingRatePostProcessing';
213 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
214 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
215 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
216 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number ' || p_installment_number);
217 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_period_begin_date ' || p_period_begin_date);
218 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_interest_adjustment_freq ' || p_interest_adjustment_freq);
219 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_annualized_interest_rate ' || p_annualized_interest_rate);
220 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_rate_id ' || p_rate_id);
221 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
222
223 -- Standard Start of API savepoint
224 SAVEPOINT floatingPostProcessor;
225
226 -- Initialize message list IF p_init_msg_list is set to TRUE.
227 IF FND_API.to_Boolean(p_init_msg_list) THEN
228 FND_MSG_PUB.initialize;
229 END IF;
230
231 -- Initialize API return status to SUCCESS
232 x_return_status := FND_API.G_RET_STS_SUCCESS;
233
234 --
235 -- Api body
236 -- ----------------------------------------------------------------
237
238 if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
239 ,p_phase => p_phase) then
240 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting next rate change info');
241 l_next_rate_change := lns_fin_utils.getNextDate(p_date => p_period_begin_date
242 ,p_interval_type => p_interest_adjustment_freq
243 ,p_direction => 1);
244 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating terms with new date ' || l_next_rate_change);
245 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating terms with new rate' || p_annualized_interest_rate);
246 if p_phase = 'OPEN' then
247 update lns_terms
248 set next_rate_change_date = l_next_rate_change
249 ,open_projected_rate = p_annualized_interest_rate
250 ,last_update_date = sysdate
251 ,last_updated_by = lns_utility_pub.user_id
252 where loan_id = p_loan_id;
253 elsif p_phase = 'TERM' then
254 update lns_terms
255 set next_rate_change_date = l_next_rate_change
256 ,term_projected_rate = p_annualized_interest_rate
257 ,last_update_date = sysdate
258 ,last_updated_by = lns_utility_pub.user_id
259 where loan_id = p_loan_id;
260 end if;
261
262 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating the rate schedule ' || p_rate_id);
263 -- store the row on lns_rate_schedules(only if the existing row does not have begin and end installment numbers same as this installment) and update existing rate_schedule row
264 open c_get_rate_sch_info(p_rate_id);
265 fetch c_get_rate_sch_info into l_begin_inst_num,l_end_inst_num;
266 close c_get_rate_sch_info;
267
268 if (l_begin_inst_num = l_end_inst_num and l_begin_inst_num = p_installment_number) then
269 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' (l_begin_inst_num = l_end_inst_num = p_installment_number) - NO need to insert new row - updating the existing rate schedule ' || p_rate_id);
270
271 -- update existing rate_schedule row
272 update lns_rate_schedules
273 set current_interest_rate = p_annualized_interest_rate
274 ,index_rate = p_annualized_interest_rate - nvl(spread,0)
275 where rate_id = p_rate_id;
276
277 else --else for if (l_begin_inst_num = l_end_inst_num = p_installment_number) then
278 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' update the existing row as the next row and insert new row for the current rate sch');
279 update lns_rate_schedules
280 set begin_installment_number = begin_installment_number + 1
281 ,current_interest_rate = spread
282 ,index_rate = null
283 where rate_id = p_rate_id;
284
285 select LNS_RATE_SCHEDULES_S.NEXTVAL into l_new_rate_id
286 from dual;
287
288 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - adding new row into rate schedule');
289 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_rate_id ' || l_new_rate_id );
290 insert into lns_rate_schedules(RATE_ID
291 ,TERM_ID
292 ,INDEX_RATE
293 ,SPREAD
294 ,CURRENT_INTEREST_RATE
295 ,START_DATE_ACTIVE
296 ,END_DATE_ACTIVE
297 ,CREATED_BY
298 ,CREATION_DATE
299 ,LAST_UPDATED_BY
300 ,LAST_UPDATE_DATE
301 ,LAST_UPDATE_LOGIN
302 ,OBJECT_VERSION_NUMBER
303 ,INDEX_DATE
304 ,BEGIN_INSTALLMENT_NUMBER
305 ,END_INSTALLMENT_NUMBER
306 ,INTEREST_ONLY_FLAG
307 ,FLOATING_FLAG
308 ,PHASE)
309 (select
310 l_new_rate_id
311 ,TERM_ID
312 ,p_annualized_interest_rate - nvl(spread,0)
313 ,SPREAD
314 ,p_annualized_interest_rate --make sure you only insert spread overtop of CIR
315 ,START_DATE_ACTIVE
316 ,END_DATE_ACTIVE
317 ,CREATED_BY
318 ,sysdate
319 ,LAST_UPDATED_BY
320 ,sysdate
321 ,LAST_UPDATE_LOGIN
322 ,1
323 ,INDEX_DATE
324 ,p_installment_number
325 ,p_installment_number
326 ,INTEREST_ONLY_FLAG
327 ,FLOATING_FLAG
328 ,PHASE
329 from lns_rate_schedules
330 where rate_id = p_rate_id);
331
332 -- assign new rate id for OUT parameter
333 p_rate_id := l_new_rate_id ;
334
335 end if; --end else part for if (l_begin_inst_num = l_end_inst_num = p_installment_number) then
336
337 else --else for if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
338
339 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating the rate schedule LAST ROW ' || p_rate_id);
340 -- update existing rate_schedule row
341 update lns_rate_schedules
342 set current_interest_rate = p_annualized_interest_rate
343 ,index_rate = p_annualized_interest_rate - nvl(spread,0)
344 where rate_id = p_rate_id;
345
346 end if; --end if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
347
348
349 --
350 -- End of API body
351 --
352 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
353 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
354
355 EXCEPTION
356 WHEN FND_API.G_EXC_ERROR THEN
357 ROLLBACK TO floatingPostProcessor;
358 x_return_status := FND_API.G_RET_STS_ERROR;
359 x_msg_count := l_msg_count;
360 x_msg_data := l_msg_data;
361 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
362 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
363
364 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
365 ROLLBACK TO floatingPostProcessor;
366 x_return_status := FND_API.G_RET_STS_ERROR;
367 x_msg_count := l_msg_count;
368 x_msg_data := l_msg_data;
369 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
370 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
371
372 WHEN OTHERS THEN
373 ROLLBACK TO floatingPostProcessor;
374 x_return_status := FND_API.G_RET_STS_ERROR;
375 x_msg_count := l_msg_count;
376 x_msg_data := l_msg_data;
377 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
378 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
379
380 end floatingRatePostProcessing;
381
382 --------------------------------------------
383 -- validation routines
384 --------------------------------------------
385
386 /*=========================================================================
387 || PUBLIC PROCEDURE validateLoan
388 ||
389 || DESCRIPTION
390 ||
391 || Overview: cover rountine to validate the loan
392 ||
393 || Parameter: loan_id
394 ||
395 || Return value:
396 ||
397 || Source Tables: NA
398 ||
399 || Target Tables:
400 ||
401 || KNOWN ISSUES
402 ||
403 || NOTES
404 ||
405 || MODIFICATION HISTORY
406 || Date Author Description of Changes
407 || 12/08/2003 11:35AM raverma Created
408 ||
409 *=======================================================================*/
410 procedure validateLoan(p_api_version IN NUMBER
411 ,p_init_msg_list IN VARCHAR2
412 ,p_loan_ID IN NUMBER
413 ,x_return_status OUT NOCOPY VARCHAR2
414 ,x_msg_count OUT NOCOPY NUMBER
415 ,x_msg_data OUT NOCOPY VARCHAR2)
416 is
417 l_api_name varchar2(25);
418 l_api_version_number number;
419 l_return_status VARCHAR2(1);
420 l_msg_count NUMBER;
421 l_msg_data VARCHAR2(32767);
422
423 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
424 l_amount number;
425 l_status varchar2(30);
426
427 CURSOR c_terms(p_Loan_id NUMBER) IS
428 SELECT TERM_ID
429 FROM LNS_TERMS
430 WHERE LOAN_ID = p_Loan_id;
431
432 BEGIN
433
434 l_api_name := 'validateLoan';
435 l_api_version_number := 1;
436 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
437
438 -- Standard Start of API savepoint
439 SAVEPOINT validateLoan;
440
441 -- Standard call to check for call compatibility.
442 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
443 l_api_name, G_PKG_NAME)
444 THEN
445 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
446 END IF;
447
448 -- Initialize message list IF p_init_msg_list is set to TRUE.
449 IF FND_API.to_Boolean(p_init_msg_list) THEN
450 FND_MSG_PUB.initialize;
451 END IF;
452
453 -- Initialize API return status to SUCCESS
454 x_return_status := FND_API.G_RET_STS_SUCCESS;
455
456 --
457 -- Api body
458 -- ----------------------------------------------------------------
459 -- there should be one active row in the terms
460 -- ----------------------------------------------------------------
461 Begin
462 OPEN c_terms(p_loan_id);
463 CLOSE c_terms;
464
465 Exception
466 When No_Data_Found then
467 CLOSE c_terms;
468 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_TERMS');
469 FND_MSG_PUB.Add;
470 RAISE FND_API.G_EXC_ERROR;
471 end;
472
473 -- rate schedules should have one row
474 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
475
476 if l_rate_tbl.count = 0 then
477 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_RATE_SCHEDULE');
478 FND_MSG_PUB.Add;
479 RAISE FND_API.G_EXC_ERROR;
480 end if;
481
482 Begin
483 l_amount := lns_financials.getRemainingBalance(p_loan_id);
484 if l_amount <= 0 then
485 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_AMOUNT');
486 FND_MSG_PUB.Add;
487 RAISE FND_API.G_EXC_ERROR;
488 end if;
489
490 end;
491
492 --
493 -- End of API body
494 --
495
496 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
497
498 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
499
500 EXCEPTION
501 WHEN FND_API.G_EXC_ERROR THEN
502 x_return_status := FND_API.G_RET_STS_ERROR;
503 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
504
505 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
506 x_return_status := FND_API.G_RET_STS_ERROR;
507 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
508
509 WHEN OTHERS THEN
510 x_return_status := FND_API.G_RET_STS_ERROR;
511 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
512
513 END validateLoan;
514
515 ---------------------------------------------------------------------------
516 --- amortization routines
517 ---------------------------------------------------------------------------
518
519 /*=========================================================================
520 || PUBLIC PROCEDURE runAmortization
521 ||
522 || DESCRIPTION
523 ||
524 || Overview: procedure will run an amortization and store it into a
525 || return an amortization table
526 ||
527 || Parameter: loan_id
528 ||
529 || Source Tables: NA
530 ||
531 || Target Tables: None
532 ||
533 || Return value: x_amort_tbl is table of amortization records
534 ||
535 || KNOWN ISSUES
536 ||
537 || NOTES
538 ||
539 || MODIFICATION HISTORY
540 || Date Author Description of Changes
541 || 11/09/2004 11:35AM raverma Created
542 ||
543 *=======================================================================*/
544 procedure runAmortization(p_api_version IN NUMBER
545 ,p_init_msg_list IN VARCHAR2
546 ,p_commit IN VARCHAR2
547 ,p_loan_ID IN NUMBER
548 ,p_based_on_terms IN VARCHAR2
549 ,x_amort_tbl OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_TBL
550 ,x_return_status OUT NOCOPY VARCHAR2
551 ,x_msg_count OUT NOCOPY NUMBER
552 ,x_msg_data OUT NOCOPY VARCHAR2)
553
554 is
555 l_api_name varchar2(25);
556 l_api_version_number number;
557 l_return_status VARCHAR2(1);
558 l_msg_count NUMBER;
559 l_msg_data VARCHAR2(32767);
560
561 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
562 l_amort_tbl2 LNS_FINANCIALS.AMORTIZATION_TBL;
563 l_total_amortization LNS_FINANCIALS.AMORTIZATION_REC;
564 l_key NUMBER;
565 b_showActual boolean := false;
566 l_last_installment_billed number;
567
568 l_installment_number number;
569 l_due_date date;
570 l_principal_amount number;
571 l_interest_amount number;
572 l_other_amount number;
573 l_fee_amount number;
574 l_begin_balance number;
575 l_end_balance number;
576 l_total number;
577 l_num_records number;
578 i number;
579 m number;
580 l_records_to_copy number;
581 l_num_installments number;
582 l_num_rows number;
583 l_manual_fee_amount number;
584 l_records_to_destroy number;
585 l_start_date number;
586 l_funded_amount number;
587 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
588 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
589
590 l_last_payment number;
591 l_disb_header_id number;
592 l_billed varchar2(1);
593 n number;
594 l_original_loan_amount number;
595 l_fund_sched_count number;
596
597 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
598 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
599 l_custom_tbl LNS_CUSTOM_PUB.CUSTOM_TBL;
600 l_AMORT_METHOD varchar2(30);
601 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
602 l_CUSTOM_SET_REC LNS_CUSTOM_PUB.custom_settings_type;
603
604 cursor c_fund_sched_exist(p_loan_id number) is
605 select decode(loan.loan_class_code,
606 'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
607 'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
608 from lns_loan_headers_all loan
609 where loan.loan_id = p_loan_id;
610
611 BEGIN
612 -- Standard Start of API savepoint
613 SAVEPOINT runAmortization_PVT;
614 l_api_name := 'runAmortization';
615 l_api_version_number := 1;
616 i := 0;
617 l_manual_fee_amount := 0;
618
619 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
620 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_ID ' || p_loan_ID);
621 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_based_on_terms ' || p_based_on_terms);
622
623 -- Standard call to check for call compatibility.
624 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
625 l_api_name, G_PKG_NAME)
626 THEN
627 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
628 END IF;
629
630 -- Initialize message list IF p_init_msg_list is set to TRUE.
631 IF FND_API.to_Boolean( p_init_msg_list ) THEN
632 FND_MSG_PUB.initialize;
633 END IF;
634
635 -- Initialize API return status to SUCCESS
636 x_return_status := FND_API.G_RET_STS_SUCCESS;
637
638 --
639 -- Api body
640 -- ----------------------------------------------------------------
641 -- validate loan_id
642 lns_utility_pub.validate_any_id(p_api_version => 1.0
643 ,p_init_msg_list => p_init_msg_list
644 ,x_msg_count => l_msg_count
645 ,x_msg_data => l_msg_data
646 ,x_return_status => l_return_status
647 ,p_col_id => p_loan_id
648 ,p_col_name => 'LOAN_ID'
649 ,p_table_name => 'LNS_LOAN_HEADERS_ALL');
650
651 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
652 FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
653 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
654 FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
655 FND_MSG_PUB.ADD;
656 RAISE FND_API.G_EXC_ERROR;
657 end if;
658
659 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
660 ,p_based_on_terms => p_based_on_terms
661 ,p_phase => 'TERM');
662
663 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'LOAN_STATUS = ' || l_loan_details.LOAN_STATUS);
664 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_based_on_terms = ' || p_based_on_terms);
665 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'LOAN_PHASE = ' || l_loan_details.LOAN_PHASE);
666
667 l_amort_tbl.delete;
668 if l_loan_details.LOAN_STATUS NOT IN ('INCOMPLETE','DELETED','REJECTED','PENDING') and
669 p_based_on_terms <> 'CURRENT' --and l_loan_details.LOAN_PHASE = 'TERM'
670 then
671
672 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calling LOAD_ORIGINAL_SCHEDULE...');
673 LOAD_ORIGINAL_SCHEDULE(p_loan_details => l_loan_details,
674 x_loan_amort_tbl => l_amort_tbl);
675
676 x_amort_tbl := l_amort_tbl;
677 return;
678
679 end if;
680
681 if (l_loan_details.CUSTOM_SCHEDULE = 'N' or
682 (l_loan_details.CUSTOM_SCHEDULE = 'Y' and l_loan_details.loan_status <> 'INCOMPLETE' and
683 p_based_on_terms <> 'CURRENT' and l_loan_details.ORIG_PAY_CALC_METHOD is not null))
684 then
685
686 -- preProcess will add a re-amortization row if the remaining amount < funded amount
687 -- bug# 5664316
688
689 if p_based_on_terms = 'CURRENT' and l_loan_details.reamortize_overpay = 'Y' then
690
691 -- call preProcessInstallment only for current amortization
692 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - preProcess the loan');
693 preProcessInstallment(p_api_version => 1.0
694 ,p_init_msg_list => p_init_msg_list
695 ,p_commit => FND_API.G_FALSE --p_commit
696 ,p_loan_ID => p_loan_id
697 ,p_installment_number => lns_billing_util_pub.last_payment_number(p_loan_id)
698 ,x_amortization_rec => l_amortization_rec
699 ,x_return_status => l_return_status
700 ,x_msg_count => l_msg_count
701 ,x_msg_data => l_msg_data);
702
703 end if;
704
705 -- call amortization API
706 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
707 ,p_based_on_terms => p_based_on_terms
708 ,p_installment_number => null
709 ,x_loan_amort_tbl => l_amort_tbl);
710 else
711
712 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - loan is customized');
713
714 if p_based_on_terms <> 'CURRENT' then
715 open c_fund_sched_exist(p_loan_id);
716 fetch c_fund_sched_exist into l_fund_sched_count;
717 close c_fund_sched_exist;
718
719 if l_fund_sched_count = 0 then
720 l_original_loan_amount := l_loan_details.requested_amount;
721 else
722 l_original_loan_amount := getFundedAmount(p_loan_id, l_loan_details.loan_start_date, p_based_on_terms);
723 end if;
724 else
725 l_original_loan_amount := getFundedAmount(p_loan_id, l_loan_details.loan_start_date, p_based_on_terms);
726 end if;
727
728 l_fees_tbl.delete;
729 l_fee_amount := 0;
730
731 -- filling out basis table
732 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
733 l_fee_basis_tbl(1).fee_basis_amount := l_loan_details.remaining_balance;
734 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
735 l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.requested_amount;
736 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
737 l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
738 l_fee_basis_tbl(4).fee_basis_name := 'TOTAL_UNDISB_AMT';
739 l_fee_basis_tbl(4).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
740
741 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
742 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
743 ,p_loan_id => p_loan_id
744 ,p_installment => 0
745 ,p_fee_basis_tbl => l_fee_basis_tbl
746 ,p_based_on_terms => p_based_on_terms
747 ,p_phase => 'TERM'
748 ,x_fees_tbl => l_fees_tbl
749 ,x_return_status => l_return_status
750 ,x_msg_count => l_msg_count
751 ,x_msg_data => l_msg_data);
752
753 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
754 if l_return_status <> 'S' then
755 RAISE FND_API.G_EXC_ERROR;
756 end if;
757
758 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
759
760 for k in 1..l_fees_tbl.count loop
761 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
762 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
763 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
764 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
765 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
766 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
767 end loop;
768 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
769
770 if l_fee_amount > 0 then
771 i := i + 1;
772 l_amort_tbl(i).installment_number := 0;
773 l_amort_tbl(i).due_date := l_loan_details.loan_start_date;
774 l_amort_tbl(i).PERIOD_START_DATE := l_loan_details.loan_start_date;
775 l_amort_tbl(i).PERIOD_END_DATE := l_loan_details.loan_start_date;
776 l_amort_tbl(i).principal_amount := 0;
777 l_amort_tbl(i).interest_amount := 0;
778 l_amort_tbl(i).fee_amount := l_fee_amount;
779 l_amort_tbl(i).other_amount := 0;
780 l_amort_tbl(i).begin_balance := l_loan_details.requested_amount;
781 l_amort_tbl(i).end_balance := l_loan_details.requested_amount;
782 l_amort_tbl(i).interest_cumulative := 0;
783 l_amort_tbl(i).principal_cumulative := 0;
784 l_amort_tbl(i).fees_cumulative := l_fee_amount;
785 l_amort_tbl(i).other_cumulative := 0;
786 l_amort_tbl(i).UNPAID_PRIN := 0;
787 l_amort_tbl(i).UNPAID_INT := 0;
788 l_amort_tbl(i).NORMAL_INT_AMOUNT := 0;
789 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT := 0;
790 l_amort_tbl(i).ADD_INT_INT_AMOUNT := 0;
791 l_amort_tbl(i).PENAL_INT_AMOUNT := 0;
792 l_amort_tbl(i).PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_details.loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_details.loan_start_date, 1);
793 l_amort_tbl(i).DISBURSEMENT_AMOUNT := l_original_loan_amount;
794 l_amort_tbl(i).FUNDED_AMOUNT := l_original_loan_amount;
795 l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT := 0;
796 l_amort_tbl(i).DEFERRED_INT_AMOUNT := 0;
797 l_amort_tbl(i).PREV_CAP_INT_AMOUNT := 0;
798 l_amort_tbl(i).CAP_INT_AMOUNT := 0;
799 l_amort_tbl(i).EARLY_PAY_CR_AMOUNT := 0;
800 -- add the record to the amortization table
801
802 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
803 l_amort_tbl(i).INTEREST_RATE := l_rate_tbl(1).annual_rate;
804
805 l_amort_tbl(i).total := l_fee_amount;
806 end if;
807
808 -- load custom schedule
809 LNS_CUSTOM_PUB.loadCustomSchedule(
810 P_API_VERSION => 1.0,
811 P_INIT_MSG_LIST => FND_API.G_TRUE,
812 P_COMMIT => FND_API.G_FALSE,
813 P_VALIDATION_LEVEL => FND_API.G_VALID_LEVEL_FULL,
814 P_LOAN_ID => P_LOAN_ID,
815 P_BASED_ON_TERMS => p_based_on_terms,
816 X_CUSTOM_SET_REC => l_CUSTOM_SET_REC,
817 X_CUSTOM_TBL => l_custom_tbl,
818 x_return_status => l_return_status,
819 x_msg_count => l_msg_count,
820 x_msg_data => l_msg_data);
821
822 IF l_return_status <> 'S' THEN
823 RAISE FND_API.G_EXC_ERROR;
824 END IF;
825
826 for p in 1..l_custom_tbl.count loop
827
828 i := i + 1;
829 l_amort_tbl(i).installment_number := l_custom_tbl(p).PAYMENT_NUMBER;
830 l_amort_tbl(i).due_date := l_custom_tbl(p).DUE_DATE;
831 l_amort_tbl(i).PERIOD_START_DATE := l_custom_tbl(p).PERIOD_START_DATE;
832 l_amort_tbl(i).PERIOD_END_DATE := l_custom_tbl(p).PERIOD_END_DATE;
833 l_amort_tbl(i).principal_amount := l_custom_tbl(p).PRINCIPAL_AMOUNT;
834 l_amort_tbl(i).interest_amount := l_custom_tbl(p).INTEREST_AMOUNT;
835 l_amort_tbl(i).TOTAL := l_custom_tbl(p).CURRENT_TERM_PAYMENT;
836 l_amort_tbl(i).fee_amount := l_custom_tbl(p).FEE_AMOUNT;
837 l_amort_tbl(i).other_amount := l_custom_tbl(p).other_amount;
838 l_amort_tbl(i).begin_balance := l_custom_tbl(p).INSTALLMENT_BEGIN_BALANCE;
839 l_amort_tbl(i).end_balance := l_custom_tbl(p).INSTALLMENT_END_BALANCE;
840 l_amort_tbl(i).UNPAID_PRIN := l_custom_tbl(p).UNPAID_PRIN;
841 l_amort_tbl(i).UNPAID_INT := l_custom_tbl(p).UNPAID_INT;
842 l_amort_tbl(i).INTEREST_RATE := l_custom_tbl(p).INTEREST_RATE;
843 l_amort_tbl(i).NORMAL_INT_AMOUNT := l_custom_tbl(p).NORMAL_INT_AMOUNT;
844 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT := l_custom_tbl(p).ADD_PRIN_INT_AMOUNT;
845 l_amort_tbl(i).ADD_INT_INT_AMOUNT := l_custom_tbl(p).ADD_INT_INT_AMOUNT;
846 l_amort_tbl(i).PENAL_INT_AMOUNT := l_custom_tbl(p).PENAL_INT_AMOUNT;
847 l_amort_tbl(i).NORMAL_INT_DETAILS := l_custom_tbl(p).NORMAL_INT_DETAILS;
848 l_amort_tbl(i).ADD_PRIN_INT_DETAILS := l_custom_tbl(p).ADD_PRIN_INT_DETAILS;
849 l_amort_tbl(i).ADD_INT_INT_DETAILS := l_custom_tbl(p).ADD_INT_INT_DETAILS;
850 l_amort_tbl(i).PENAL_INT_DETAILS := l_custom_tbl(p).PENAL_INT_DETAILS;
851 l_amort_tbl(i).FUNDED_AMOUNT := l_custom_tbl(p).FUNDED_AMOUNT;
852 l_amort_tbl(i).PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_custom_tbl(p).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_custom_tbl(p).PERIOD_END_DATE-1), 1);
853 l_amort_tbl(i).DISBURSEMENT_AMOUNT := l_custom_tbl(p).DISBURSEMENT_AMOUNT;
854 l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT := l_custom_tbl(p).PREV_DEFERRED_INT_AMOUNT;
855 l_amort_tbl(i).DEFERRED_INT_AMOUNT := l_custom_tbl(p).DEFERRED_INT_AMOUNT;
856 l_amort_tbl(i).DEFERRED_INT_DETAILS := l_custom_tbl(p).DEFERRED_INT_DETAILS;
857 l_amort_tbl(i).PREV_CAP_INT_AMOUNT := l_custom_tbl(p).PREV_CAP_INT_AMOUNT;
858 l_amort_tbl(i).CAP_INT_AMOUNT := l_custom_tbl(p).CAP_INT_AMOUNT;
859 l_amort_tbl(i).CAP_INT_DETAILS := l_custom_tbl(p).CAP_INT_DETAILS;
860 l_amort_tbl(i).EARLY_PAY_CR_AMOUNT := l_custom_tbl(p).EARLY_PAY_CR_AMOUNT;
861 l_amort_tbl(i).EARLY_PAY_CR_DETAILS := l_custom_tbl(p).EARLY_PAY_CR_DETAILS;
862
863 END LOOP;
864
865 end if;
866
867 -- delete predicted records based on ORIGINAL amortization
868 if p_based_on_terms = 'CURRENT' and
869 l_loan_details.LOAN_STATUS NOT IN ('INCOMPLETE','DELETED','REJECTED','PENDING','APPROVED')
870 then
871
872 l_num_records := l_amort_tbl.count;
873 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - amortization returns # records '|| l_num_records);
874 l_last_installment_billed := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER_EXT_3(p_loan_id, 'TERM');
875 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - last installment billed '|| l_last_installment_billed);
876
877 -- copy the records not billed to a temp collection
878 m := 0;
879 for i in 1..l_num_records
880 loop
881 if l_amort_tbl(i).installment_number > l_last_installment_billed or
882 (l_amort_tbl(i).installment_number = 0 and l_last_installment_billed = 0)
883 then
884 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - copying record ' || i ||
885 ': installment ' || l_amort_tbl(i).installment_number);
886 m := m + 1;
887 l_amort_tbl2(m) := l_amort_tbl(i);
888 end if;
889 end loop;
890
891 -- copy back to original table
892 l_amort_tbl.delete;
893 m := 0;
894 for i in 1..l_amort_tbl2.count
895 loop
896 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - re-copying record ' || i);
897 m := m + 1;
898 l_amort_tbl(m) := l_amort_tbl2(i);
899 end loop;
900
901
902 end if;
903
904 x_amort_tbl := l_amort_tbl;
905 --
906 -- End of API body
907 --
908
909 -- Standard check for p_commit
910 IF FND_API.to_Boolean(p_commit) THEN
911 COMMIT WORK;
912 END IF;
913
914 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
915 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
916
917 EXCEPTION
918 WHEN FND_API.G_EXC_ERROR THEN
919 ROLLBACK TO runAmortization_PVT;
920 x_return_status := FND_API.G_RET_STS_ERROR;
921 x_msg_count := l_msg_count;
922 x_msg_data := l_msg_data;
923 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
924 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
925
926 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
927 ROLLBACK TO runAmortization_PVT;
928 x_return_status := FND_API.G_RET_STS_ERROR;
929 x_msg_count := l_msg_count;
930 x_msg_data := l_msg_data;
931 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
932 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
933
934 WHEN OTHERS THEN
935 ROLLBACK TO runAmortization_PVT;
936 x_return_status := FND_API.G_RET_STS_ERROR;
937 x_msg_count := l_msg_count;
938 x_msg_data := l_msg_data;
939 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
940 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
941
942 END runAmortization;
943
944 /*=========================================================================
945 | PUBLIC PROCEDURE termlyPayment
946 |
947 | DESCRIPTION
948 ||
949 || Overview: number of periods to pay off a loan according to formula
950 || periods_to_payoff = [ LN(1-(rate*loanAmount)/(payment*payments_per_period)) /
951 || LN(1 + rate/payments_per_period)]
952 ||
953 || Parameter: p_termly amount = periodic amount to pay
954 || p_annual_rate = annual interest rate on the loan
955 || p_loan_amount = amount of the loan
956 || p_payments_per_year = payments @ termly_amount per year
957 || p_period_type = 'YEARS', 'QUARTERS', 'MONTHS'
958 ||
959 || Source Tables: NA
960 ||
961 || Target Tables: NA
962 ||
963 || Return value: number of periods to pay off the loan
964 || if return value = -1 then the loan can never be payed off
965 || at that termly amount and rate
966 ||
967 || KNOWN ISSUES
968 ||
969 || NOTES
970 || NOTE: INSTALLMENT_NUMBER WILL NOT GET YOU THE GIVEN INSTALLMENT
971 || NUMBER CORRESPONDING ON THE LOAN AMORTIZATION SCHEDULE
972 ||
973 || MODIFICATION HISTORY
974 || Date Author Description of Changes
975 || 12/11/2003 6:42PM raverma Created
976 ||
977 *=======================================================================*/
978 function termlyPayment(p_termly_amount in number
979 ,p_annual_rate in number
980 ,p_loan_amount in number
981 ,p_payments_per_year in number
982 ,p_period_type in varchar2) return number
983 is
984 l_periodic_rate number;
985 l_num_periods number;
986 l_api_name varchar2(15);
987
988 begin
989
990 l_api_name := 'termlyPayment';
991 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
992
993 l_periodic_rate := p_annual_rate / 100;
994
995 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate: ' || l_periodic_rate);
996 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': termly amount: ' || p_termly_amount);
997 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payments per year: ' || p_payments_per_year);
998 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan amount : ' || p_loan_amount);
999
1000 if l_periodic_rate <> 0 then
1001 -- we cannot have LN < 0
1002 -- this will be a loan that will never be paid off
1003 if ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount) >= 1 then
1004 FND_MESSAGE.Set_Name('LNS', 'LNS_NEVER_PAYOFF');
1005 FND_MSG_PUB.Add;
1006 RAISE FND_API.G_EXC_ERROR;
1007 end if;
1008
1009 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate * p_loan_amount :' || l_periodic_rate * p_loan_amount);
1010 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_payments_per_year * p_termly_amount : ' || p_payments_per_year * p_termly_amount);
1011 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': LN(1-a/b) : ' || LN(1 - ( ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount))));
1012 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate / p_payments_per_year : ' || l_periodic_rate / p_payments_per_year);
1013 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': LN(1+d) : ' || LN(1 + (l_periodic_rate / p_payments_per_year)));
1014 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': - p_payments_per_year : ' || (- p_payments_per_year));
1015
1016 l_num_periods := (LN(1 - ( ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount))) /
1017 LN(1 + (l_periodic_rate / p_payments_per_year))) / (- p_payments_per_year) ;
1018 else
1019 l_num_periods := p_loan_amount / p_termly_amount / p_payments_per_year;
1020
1021 end if;
1022
1023 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': num years to pay off = ' || l_num_periods);
1024
1025 if p_period_type = 'MONTHS' then
1026 l_num_periods := l_num_periods * 12;
1027
1028 elsif p_period_type = 'QUARTERS' then
1029 l_num_periods := l_num_periods * 4;
1030
1031 elsif p_period_type = 'YEARS' then
1032 null;
1033
1034 end if;
1035
1036 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1037
1038 return l_num_periods;
1039
1040 Exception
1041
1042 When FND_API.G_EXC_ERROR then
1043 return -1;
1044
1045 When others then
1046 return -1;
1047
1048 end termlyPayment;
1049
1050 /*=========================================================================
1051 || PUBLIC PROCEDURE preProcessInstallment
1052 ||
1053 || DESCRIPTION
1054 ||
1055 || Overview: this procedure will recalculate an installment for reamortization
1056 ||
1057 || PSEUDO CODE/LOGIC
1058 ||
1059 || PARAMETERS
1060 ||
1061 || Parameter: p_loan_id => in loanID
1062 || p_installment_number = FLAG to notify to get the
1063 || latest installment
1064 ||
1065 || Return value: AMORTIZATION_REC => contains billing and payment information
1066 ||
1067 || Source Tables: NA
1068 ||
1069 || Target Tables: NA
1070 ||
1071 || KNOWN ISSUES
1072 ||
1073 || NOTES
1074 || NOTE: api used by Billing Engine
1075 ||
1076 || MODIFICATION HISTORY
1077 || Date Author Description of Changes
1078 || 03/12/2004 12:40PM raverma Created
1079 ||
1080 *=======================================================================*/
1081 procedure preProcessInstallment(p_api_version IN NUMBER
1082 ,p_init_msg_list IN VARCHAR2
1083 ,p_commit IN VARCHAR2
1084 ,p_loan_ID IN NUMBER
1085 ,p_installment_number IN NUMBER
1086 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1087 ,x_return_status OUT NOCOPY VARCHAR2
1088 ,x_msg_count OUT NOCOPY NUMBER
1089 ,x_msg_data OUT NOCOPY VARCHAR2)
1090 is
1091 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
1092 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
1093 l_count NUMBER;
1094 l_api_name varchar2(40);
1095 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
1096
1097 l_theoretical_balance NUMBER;
1098 l_actual_balance NUMBER;
1099 l_api_version_number number;
1100 l_return_status VARCHAR2(1);
1101 l_msg_count NUMBER;
1102 l_msg_data VARCHAR2(32767);
1103 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL; -- define what event(s) we are processing fees for
1104 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
1105 l_overdue_amount number;
1106 i number;
1107 l_due_date date;
1108 l_installment number;
1109 l_arr_pos number;
1110
1111 -- this is for get custom dates
1112 cursor c_customized (p_loan_id number) is
1113 SELECT nvl(h.custom_payments_flag, 'N')
1114 FROM lns_loan_headers_all h
1115 WHERE loan_id = p_loan_id;
1116
1117 cursor c_customSchedule(p_loan_id number, p_installment number) is
1118 select payment_number installment_number
1119 ,due_date due_date
1120 from lns_custom_paymnt_scheds
1121 where loan_id = p_loan_id
1122 and payment_number = p_installment;
1123
1124 begin
1125
1126 l_api_name := 'preProcessInstallment';
1127 l_api_version_number := 1;
1128
1129 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1130 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1131 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1132
1133 -- Standard Start of API savepoint
1134 SAVEPOINT preProcessInstallment;
1135
1136 -- Standard call to check for call compatibility.
1137 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
1138 l_api_name, G_PKG_NAME)
1139 THEN
1140 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1141 END IF;
1142
1143 -- Initialize message list IF p_init_msg_list is set to TRUE.
1144 IF FND_API.to_Boolean(p_init_msg_list) THEN
1145 FND_MSG_PUB.initialize;
1146 END IF;
1147 -- Initialize API return status to SUCCESS
1148 x_return_status := FND_API.G_RET_STS_SUCCESS;
1149
1150 -- Api body
1151 -- get the loan details
1152 -- compare the actual balance to the theoretical balance
1153 -- if they are inconsistent and reamorization flag is set
1154 -- then insert reamortization information into LNS_AMORTIZATION_SCHEDS
1155 /*
1156 if p_installment_number = 0 then
1157 i := p_installment_number + 1;
1158 else
1159 i := p_installment_number;
1160 end if;
1161 */
1162 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
1163 ,p_based_on_terms => 'CURRENT'
1164 ,p_phase => 'TERM');
1165
1166 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting next installment info...');
1167 if l_loan_details.custom_schedule = 'N' then
1168 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - regular loan');
1169
1170 -- this is a standard non-customized loan
1171 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
1172 ,p_based_on_terms => 'CURRENT'
1173 ,p_installment_number => p_installment_number
1174 ,x_loan_amort_tbl => l_amort_tbl);
1175 l_count := l_amort_tbl.count;
1176 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' table count is ' || l_count);
1177
1178 for i in REVERSE 1..l_amort_tbl.count loop
1179 if p_installment_number = l_amort_tbl(i).INSTALLMENT_NUMBER then
1180 l_due_date := l_amort_tbl(i).due_date;
1181 l_installment := l_amort_tbl(i).installment_number;
1182 exit;
1183 end if;
1184 end loop;
1185
1186 else
1187 -- we are on a customized loan
1188 -- check if this is 0th installment or not
1189 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - custom loan');
1190 if p_installment_number > 0 then
1191 open c_customSchedule(p_loan_id, p_installment_number);
1192 fetch c_customSchedule into
1193 l_installment
1194 ,l_due_date;
1195 close c_customSchedule;
1196 else
1197 -- we are on 0th installment
1198 l_installment := p_installment_number;
1199 l_due_date := l_loan_details.loan_start_date;
1200 end if;
1201 end if;
1202
1203 -- assign to output record
1204 l_amortization_rec.installment_number := l_installment;
1205 l_amortization_rec.due_date := l_due_date;
1206 --l_amortization_rec.principal_amount := l_amort_tbl(i).principal_amount;
1207 --l_amortization_rec.interest_amount := l_amort_tbl(i).interest_amount;
1208 --l_amortization_rec.fee_amount := l_amort_tbl(i).fee_amount;
1209 --l_amortization_rec.other_amount := l_amort_tbl(i).other_amount;
1210 --l_amortization_rec.total := l_amort_tbl(i).total;
1211 --l_amortization_rec.begin_balance := l_amort_tbl(i).begin_balance;
1212 --l_amortization_rec.end_balance := l_amort_tbl(i).end_balance;
1213 --l_amortization_rec.principal_cumulative := l_amort_tbl(i).principal_cumulative;
1214 --l_amortization_rec.interest_cumulative := l_amort_tbl(i).interest_cumulative;
1215 --l_amortization_rec.fees_cumulative := l_amort_tbl(i).fees_cumulative;
1216 --l_amortization_rec.other_cumulative := l_amort_tbl(i).other_cumulative;
1217 --l_amortization_rec.rate_id := l_amort_tbl(i).rate_id;
1218
1219 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' next installment due: ' || l_amortization_rec.installment_number);
1220 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' next due date: ' || l_amortization_rec.due_date);
1221
1222 -- get theoretical balance
1223 -- bug# 5664316 - remove installment number check
1224 if l_loan_details.reamortize_overpay = 'Y' and
1225 l_loan_details.custom_schedule = 'N' -- fix for bug 6902221
1226 then --and p_installment_number > 1 then
1227
1228 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - checking if we need to reamortize...');
1229
1230 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
1231 ,p_based_on_terms => 'ORIGINAL'
1232 ,p_installment_number => p_installment_number
1233 ,x_loan_amort_tbl => l_amort_tbl);
1234
1235 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' comparing balances...');
1236 l_actual_balance := l_loan_details.remaining_balance;
1237
1238 if p_installment_number > 0 then
1239
1240 -- l_arr_pos is array index
1241 l_arr_pos := p_installment_number;
1242
1243 -- will get inside if only if there is origination fee
1244 if l_amort_tbl(1).INSTALLMENT_NUMBER = 0 then
1245 l_arr_pos := p_installment_number + 1;
1246 end if;
1247
1248 if l_amort_tbl.count < l_arr_pos then
1249 l_theoretical_balance := 0;
1250 else
1251 l_theoretical_balance := l_amort_tbl(l_arr_pos).end_balance;
1252 end if;
1253 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' p_installment_number ' || p_installment_number);
1254 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' l_arr_pos ' || l_arr_pos);
1255
1256 elsif p_installment_number = 0 then
1257 -- this check will take care of multiple reAmortizations on 0th installment
1258 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize zero installment');
1259 if l_loan_details.reamortize_amount = 0 or l_loan_details.reamortize_amount is null then
1260
1261 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize amount is zero - no previous reamortization ');
1262 l_theoretical_balance := l_loan_details.funded_amount;
1263 else
1264
1265 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize amount is not zero - previous reamort amount');
1266 l_theoretical_balance := l_loan_details.reamortize_amount;
1267 end if;
1268 end if;
1269
1270 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' actual balance ' || l_actual_balance);
1271 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' theoretical balance ' || l_theoretical_balance);
1272 -- end bug# 5664316 11-23-2006
1273
1274 if l_actual_balance < l_theoretical_balance then
1275
1276 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZING...');
1277
1278 -- remove all reAmortize rows from amortization schedule
1279 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' removing previous reAmortize rows');
1280
1281 delete
1282 from lns_amortization_scheds
1283 where loan_id = p_loan_id
1284 and reamortization_amount is not null
1285 and reamortize_from_installment is not null;
1286
1287 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZE OVERPAY LOAN');
1288 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' insert record into amortizations');
1289 insert into LNS_AMORTIZATION_SCHEDS(amortization_schedule_id
1290 ,loan_id
1291 ,reamortization_amount
1292 ,reamortize_from_installment
1293 ,reamortize_to_installment
1294 ,created_by
1295 ,creation_date
1296 ,last_updated_by
1297 ,last_update_date
1298 ,object_version_number)
1299 values
1300 (LNS_AMORTIZATION_SCHEDS_S.NEXTVAL
1301 ,p_loan_id
1302 ,l_actual_balance
1303 ,p_installment_number
1304 ,null
1305 ,lns_utility_pub.created_by
1306 ,lns_utility_pub.creation_date
1307 ,lns_utility_pub.last_updated_by
1308 ,lns_utility_pub.last_update_date
1309 ,1);
1310 -- bug #3718480
1311 -- we will need to credit out all unpaid principal documents
1312 /*
1313 elsif l_loan_details.reamortize_underpay = 'Y' and l_actual_balance > l_theoretical_balance then
1314 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZE UNDERPAY LOAN');
1315 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' insert record into amortizations');
1316 insert into LNS_AMORTIZATION_SCHEDS(amortization_schedule_id
1317 ,loan_id
1318 ,reamortization_amount
1319 ,reamortize_from_installment
1320 ,reamortize_to_installment
1321 ,created_by
1322 ,creation_date
1323 ,last_updated_by
1324 ,last_update_date
1325 ,object_version_number)
1326 values
1327 (LNS_AMORTIZATION_SCHEDS_S.NEXTVAL
1328 ,p_loan_id
1329 ,l_actual_balance
1330 ,p_installment_number
1331 ,null
1332 ,lns_utility_pub.created_by
1333 ,lns_utility_pub.creation_date
1334 ,lns_utility_pub.last_updated_by
1335 ,lns_utility_pub.last_update_date
1336 ,1);
1337 */
1338 else
1339 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' WILL NOT REAMORTIZE!');
1340 end if;
1341 end if;
1342
1343 x_amortization_rec := l_amortization_rec;
1344
1345 --
1346 -- End of API body
1347 -- ---------------------------------------------------------------
1348
1349 -- Standard check for p_commit
1350 IF FND_API.to_Boolean(p_commit) THEN
1351 COMMIT WORK;
1352 END IF;
1353
1354 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1355 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1356
1357 Exception
1358 WHEN FND_API.G_EXC_ERROR THEN
1359 ROLLBACK TO preProcessInstallment;
1360 x_return_status := FND_API.G_RET_STS_ERROR;
1361 x_msg_count := l_msg_count;
1362 x_msg_data := l_msg_data;
1363 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1364 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1365
1366 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1367 ROLLBACK TO preProcessInstallment;
1368 x_return_status := FND_API.G_RET_STS_ERROR;
1369 x_msg_count := l_msg_count;
1370 x_msg_data := l_msg_data;
1371 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1372 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
1373
1374 WHEN OTHERS THEN
1375 ROLLBACK TO preProcessInstallment;
1376 x_return_status := FND_API.G_RET_STS_ERROR;
1377 x_msg_count := l_msg_count;
1378 x_msg_data := l_msg_data;
1379 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1380 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1381
1382 end preProcessInstallment;
1383
1384 /*=========================================================================
1385 || PUBLIC PROCEDURE preProcessOpenInstallment
1386 ||
1387 || DESCRIPTION
1388 ||
1389 || Overview: this procedure will preProcess an installment
1390 ||
1391 || PSEUDO CODE/LOGIC
1392 ||
1393 || PARAMETERS
1394 ||
1395 || Parameter: p_loan_id => in loanID
1396 || p_installment_number = FLAG to notify to get the
1397 || latest installment
1398 ||
1399 || Return value: AMORTIZATION_REC => contains billing and payment information
1400 ||
1401 || Source Tables: NA
1402 ||
1403 || Target Tables: NA
1404 ||
1405 || KNOWN ISSUES
1406 ||
1407 || NOTES
1408 || NOTE: api used by Billing Engine
1409 ||
1410 || MODIFICATION HISTORY
1411 || Date Author Description of Changes
1412 || 03/12/2004 12:40PM raverma Created
1413 ||
1414 *=======================================================================*/
1415 procedure preProcessOpenInstallment(p_init_msg_list IN VARCHAR2
1416 ,p_commit IN VARCHAR2
1417 ,p_loan_ID IN NUMBER
1418 ,p_installment_number IN NUMBER
1419 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1420 ,x_return_status OUT NOCOPY VARCHAR2
1421 ,x_msg_count OUT NOCOPY NUMBER
1422 ,x_msg_data OUT NOCOPY VARCHAR2)
1423 is
1424 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
1425 l_count NUMBER;
1426 l_api_name varchar2(40);
1427 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
1428
1429 l_return_status VARCHAR2(1);
1430 l_msg_count NUMBER;
1431 l_msg_data VARCHAR2(32767);
1432 l_fees_tbl LNS_FINANCIALS.FEES_TBL;
1433 i number;
1434 l_installment number;
1435
1436 begin
1437
1438 l_api_name := 'preProcessOpenInstallment';
1439 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1440 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1441 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1442
1443 -- Standard Start of API savepoint
1444 SAVEPOINT preProcessOpenInstallment;
1445
1446 -- Initialize message list IF p_init_msg_list is set to TRUE.
1447 IF FND_API.to_Boolean(p_init_msg_list) THEN
1448 FND_MSG_PUB.initialize;
1449 END IF;
1450
1451 -- Initialize API return status to SUCCESS
1452 x_return_status := FND_API.G_RET_STS_SUCCESS;
1453
1454 -- ---------------------------------------------------------------
1455 -- Beginning of API body
1456 --
1457 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting loan details');
1458 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
1459 ,p_based_on_terms => 'CURRENT'
1460 ,p_phase => 'OPEN');
1461
1462 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting Open Installment');
1463 lns_financials.getOpenInstallment(p_init_msg_list => 'T'
1464 ,p_loan_ID => p_loan_ID
1465 ,p_installment_number => p_installment_number
1466 ,x_fees_tbl => l_fees_tbl
1467 ,x_amortization_rec => l_amortization_rec
1468 ,x_return_status => l_return_Status
1469 ,x_msg_count => l_msg_count
1470 ,x_msg_data => l_msg_data);
1471
1472 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1473 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1474 FND_MSG_PUB.ADD;
1475 RAISE FND_API.G_EXC_ERROR;
1476 end if;
1477
1478 x_amortization_rec := l_amortization_rec;
1479
1480 --
1481 -- End of API body
1482 -- ---------------------------------------------------------------
1483
1484 -- Standard check for p_commit
1485 IF FND_API.to_Boolean(p_commit) THEN
1486 COMMIT WORK;
1487 END IF;
1488
1489 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1490 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1491
1492 Exception
1493 WHEN FND_API.G_EXC_ERROR THEN
1494 ROLLBACK TO preProcessOpenInstallment;
1495 x_return_status := FND_API.G_RET_STS_ERROR;
1496 x_msg_count := l_msg_count;
1497 x_msg_data := l_msg_data;
1498 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1499 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1500
1501 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1502 ROLLBACK TO preProcessOpenInstallment;
1503 x_return_status := FND_API.G_RET_STS_ERROR;
1504 x_msg_count := l_msg_count;
1505 x_msg_data := l_msg_data;
1506 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1507 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
1508
1509 WHEN OTHERS THEN
1510 ROLLBACK TO preProcessOpenInstallment;
1511 x_return_status := FND_API.G_RET_STS_ERROR;
1512 x_msg_count := l_msg_count;
1513 x_msg_data := l_msg_data;
1514 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1515 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1516
1517 end preProcessOpenInstallment;
1518
1519
1520 /*=========================================================================
1521 || PUBLIC PROCEDURE getInstallment
1522 ||
1523 || DESCRIPTION
1524 ||
1525 || Overview: returns interest and principal for a single installment
1526 || this is used for the billing concurrent program
1527 ||
1528 || PSEUDO CODE/LOGIC
1529 ||
1530 || PARAMETERS
1531 ||
1532 || Parameter: p_loan_id => in loanID
1533 || p_installment_number = FLAG to notify to get the
1534 || latest installment
1535 ||
1536 || Return value: AMORTIZATION_REC => contains billing and payment information
1537 ||
1538 || Source Tables: NA
1539 ||
1540 || Target Tables: NA
1541 ||
1542 || KNOWN ISSUES
1543 ||
1544 || NOTES
1545 || NOTE: api used by Billing Engine
1546 ||
1547 || MODIFICATION HISTORY
1548 || Date Author Description of Changes
1549 || 12/11/2003 12:40PM raverma Created
1550 ||
1551 *=======================================================================*/
1552 procedure getInstallment(p_api_version IN NUMBER
1553 ,p_init_msg_list IN VARCHAR2
1554 ,p_commit IN VARCHAR2
1555 ,p_loan_Id in number
1556 ,p_installment_number in number
1557 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1558 ,x_fees_tbl OUT NOCOPY LNS_FINANCIALS.FEES_TBL
1559 ,x_return_status OUT NOCOPY VARCHAR2
1560 ,x_msg_count OUT NOCOPY NUMBER
1561 ,x_msg_data OUT NOCOPY VARCHAR2)
1562 is
1563 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
1564 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
1565 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
1566 l_count NUMBER;
1567 l_api_version_number number;
1568 l_return_status VARCHAR2(1);
1569 l_msg_count NUMBER;
1570 l_msg_data VARCHAR2(32767);
1571 l_api_name varchar2(25);
1572 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
1573 l_fees_tbl_1 LNS_FEE_ENGINE.FEE_CALC_TBL;
1574 l_fees_tbl_2 LNS_FINANCIALS.FEES_TBL;
1575 l_total_fees number;
1576 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
1577 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL; -- define what event(s) we are processing fees for
1578 i number;
1579 --l_begin_balance number; -- used for fees calculation
1580 l_customized varchar2(1);
1581 l_loan_start_date date;
1582 l_funded_amount number;
1583 l_custom_tbl LNS_CUSTOM_PUB.CUSTOM_TBL;
1584 l_AMORT_METHOD varchar2(30);
1585 l_CUSTOM_SET_REC LNS_CUSTOM_PUB.custom_settings_type;
1586
1587 /* query custom amortization */
1588 CURSOR cust_amort_cur(P_LOAN_ID number, P_PAYMENT_NUMBER number) IS
1589 select
1590 cust.DUE_DATE
1591 ,nvl(cust.PRINCIPAL_AMOUNT, 0)
1592 ,nvl(cust.INTEREST_AMOUNT, 0)
1593 ,cust.installment_begin_balance
1594 ,cust.installment_end_balance
1595 --cust.FEE_AMOUNT
1596 from LNS_CUSTOM_PAYMNT_SCHEDS cust
1597 where cust.LOAN_ID = P_LOAN_ID and
1598 cust.PAYMENT_NUMBER = P_PAYMENT_NUMBER;
1599
1600 begin
1601
1602 l_api_version_number := 1;
1603 l_api_name := 'getInstallment';
1604 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1605 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1606 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1607
1608 -- Standard Start of API savepoint
1609 SAVEPOINT getInstallment;
1610
1611 -- Standard call to check for call compatibility.
1612 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
1613 l_api_name, G_PKG_NAME)
1614 THEN
1615 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1616 END IF;
1617
1618 -- Initialize message list IF p_init_msg_list is set to TRUE.
1619 IF FND_API.to_Boolean(p_init_msg_list) THEN
1620 FND_MSG_PUB.initialize;
1621 END IF;
1622
1623 -- Initialize API return status to SUCCESS
1624 x_return_status := FND_API.G_RET_STS_SUCCESS;
1625
1626 -- --------------------------------------------------------------------
1627 -- Api body
1628 -- --------------------------------------------------------------------
1629 l_total_fees := 0;
1630 l_amortization_rec.principal_amount := 0;
1631 l_amortization_rec.interest_amount := 0;
1632 l_amortization_rec.total := 0;
1633 l_amortization_rec.fee_amount := 0;
1634 l_amortization_rec.other_amount := 0;
1635 l_amortization_rec.begin_balance := 0;
1636 l_amortization_rec.end_balance := 0;
1637
1638 -- move logic for billing custom loans into FINANCIALS API
1639 l_loan_Details := lns_financials.getLoanDetails(p_loan_id, 'CURRENT', 'TERM');
1640
1641 if l_loan_details.custom_schedule = 'N' then
1642
1643 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan is not customized');
1644 if l_loan_details.reamortize_overpay = 'Y' then
1645 -- preProcess will add a re-amortization row if the remaining amount < funded amount
1646 -- bug# 5664316 11-23-2006
1647 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling preProcessInstallment...');
1648 preProcessInstallment(p_api_version => 1.0
1649 ,p_init_msg_list => p_init_msg_list
1650 ,p_commit => p_commit
1651 ,p_loan_ID => p_loan_id
1652 ,p_installment_number => lns_billing_util_pub.last_payment_number(p_loan_id)
1653 ,x_amortization_rec => l_amortization_rec
1654 ,x_return_status => l_return_status
1655 ,x_msg_count => l_msg_count
1656 ,x_msg_data => l_msg_data);
1657 end if;
1658
1659 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling amortizeLoan....');
1660 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
1661 ,p_installment_number => p_installment_number
1662 ,p_based_on_terms => 'CURRENT'
1663 ,x_loan_amort_tbl => l_amortization_tbl);
1664
1665 for p in 1..l_amortization_tbl.count loop
1666 if l_amortization_tbl(p).installment_number = p_installment_number then
1667 l_amortization_rec := l_amortization_tbl(p);
1668 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Found installment ' || p_installment_number);
1669 exit;
1670 end if;
1671 end loop;
1672
1673 else -- this is a customized loan
1674
1675 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan is customized');
1676 if p_installment_number > 0 then
1677
1678 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling LNS_CUSTOM_PUB.loadCustomSchedule....');
1679 -- load custom schedule
1680 LNS_CUSTOM_PUB.loadCustomSchedule(
1681 P_API_VERSION => 1.0,
1682 P_INIT_MSG_LIST => FND_API.G_TRUE,
1683 P_COMMIT => FND_API.G_FALSE,
1684 P_VALIDATION_LEVEL => FND_API.G_VALID_LEVEL_FULL,
1685 P_LOAN_ID => p_loan_id,
1686 P_BASED_ON_TERMS => 'CURRENT',
1687 X_CUSTOM_SET_REC => l_CUSTOM_SET_REC,
1688 X_CUSTOM_TBL => l_custom_tbl,
1689 x_return_status => l_return_status,
1690 x_msg_count => l_msg_count,
1691 x_msg_data => l_msg_data);
1692
1693 IF l_return_status <> 'S' THEN
1694 RAISE FND_API.G_EXC_ERROR;
1695 END IF;
1696
1697 for p in 1..l_custom_tbl.count loop
1698
1699 if l_custom_tbl(p).PAYMENT_NUMBER = p_installment_number then
1700 l_amortization_rec.installment_number := l_custom_tbl(p).PAYMENT_NUMBER;
1701 l_amortization_rec.due_date := l_custom_tbl(p).DUE_DATE;
1702 l_amortization_rec.PERIOD_START_DATE := l_custom_tbl(p).PERIOD_START_DATE;
1703 l_amortization_rec.PERIOD_END_DATE := l_custom_tbl(p).PERIOD_END_DATE;
1704 l_amortization_rec.principal_amount := l_custom_tbl(p).PRINCIPAL_AMOUNT;
1705 l_amortization_rec.interest_amount := l_custom_tbl(p).INTEREST_AMOUNT;
1706 l_amortization_rec.begin_balance := l_custom_tbl(p).INSTALLMENT_BEGIN_BALANCE;
1707 l_amortization_rec.end_balance := l_custom_tbl(p).INSTALLMENT_END_BALANCE;
1708 l_amortization_rec.UNPAID_PRIN := l_custom_tbl(p).UNPAID_PRIN;
1709 l_amortization_rec.UNPAID_INT := l_custom_tbl(p).UNPAID_INT;
1710 l_amortization_rec.INTEREST_RATE := l_custom_tbl(p).INTEREST_RATE;
1711 l_amortization_rec.NORMAL_INT_AMOUNT := l_custom_tbl(p).NORMAL_INT_AMOUNT;
1712 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_custom_tbl(p).ADD_PRIN_INT_AMOUNT;
1713 l_amortization_rec.ADD_INT_INT_AMOUNT := l_custom_tbl(p).ADD_INT_INT_AMOUNT;
1714 l_amortization_rec.PENAL_INT_AMOUNT := l_custom_tbl(p).PENAL_INT_AMOUNT;
1715 l_amortization_rec.FUNDED_AMOUNT := l_custom_tbl(p).FUNDED_AMOUNT;
1716 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_custom_tbl(p).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_custom_tbl(p).PERIOD_END_DATE-1), 1);
1717 l_amortization_rec.DISBURSEMENT_AMOUNT := l_custom_tbl(p).DISBURSEMENT_AMOUNT;
1718 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := l_custom_tbl(p).PREV_DEFERRED_INT_AMOUNT;
1719 l_amortization_rec.DEFERRED_INT_AMOUNT := l_custom_tbl(p).DEFERRED_INT_AMOUNT;
1720 l_amortization_rec.DEFERRED_INT_DETAILS := l_custom_tbl(p).DEFERRED_INT_DETAILS;
1721 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_custom_tbl(p).PREV_CAP_INT_AMOUNT;
1722 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_custom_tbl(p).CURR_CAP_INT_AMOUNT;
1723 l_amortization_rec.CAP_INT_AMOUNT := l_custom_tbl(p).CAP_INT_AMOUNT;
1724 l_amortization_rec.CAP_INT_DETAILS := l_custom_tbl(p).CAP_INT_DETAILS;
1725 l_amortization_rec.EARLY_PAY_CR_AMOUNT := l_custom_tbl(p).EARLY_PAY_CR_AMOUNT;
1726 l_amortization_rec.EARLY_PAY_CR_DETAILS := l_custom_tbl(p).EARLY_PAY_CR_DETAILS;
1727 exit;
1728 end if;
1729 end loop;
1730 else
1731 l_amortization_rec.begin_balance := l_loan_details.funded_amount;
1732 l_amortization_rec.due_date := l_loan_details.loan_start_date;
1733 l_amortization_rec.installment_number := p_installment_number;
1734 end if;
1735 end if;
1736 /*
1737 -- bug # 3839974
1738 if l_amortization_rec.principal_amount > l_loan_details.unbilled_principal then
1739 l_amortization_rec.principal_amount := l_loan_details.unbilled_principal;
1740 l_amortization_rec.principal_cumulative := l_amortization_rec.principal_cumulative - l_amortization_rec.principal_amount + l_loan_details.unbilled_principal;
1741 end if;
1742 */
1743 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
1744 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
1745 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
1746 l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.requested_amount;
1747 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
1748 l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
1749 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN';
1750 l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
1751 l_fee_basis_tbl(5).fee_basis_name := 'OVERDUE_PRIN_INT';
1752 l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
1753 l_fee_basis_tbl(6).fee_basis_name := 'IND_DISB_AMT';
1754 l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
1755 l_fee_basis_tbl(7).fee_basis_name := 'TOTAL_UNDISB_AMT';
1756 l_fee_basis_tbl(7).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
1757 l_fee_basis_tbl(8).fee_basis_name := 'OVERDUE_INT';
1758 l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
1759 l_fee_basis_tbl(9).fee_basis_name := 'CURR_LOAN';
1760 l_fee_basis_tbl(9).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT;
1761
1762 if p_installment_number = 0 or p_installment_number = 1 then
1763 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing origination fees');
1764 l_fee_structures(1).fee_category := 'EVENT';
1765 l_fee_structures(1).fee_type := 'EVENT_ORIGINATION';
1766 l_fee_structures(1).phase := l_loan_details.LOAN_PHASE;
1767
1768 if p_installment_number = 0 then
1769 l_fee_structures(1).FEE_BILLING_OPTION := 'ORIGINATION';
1770 else
1771 l_fee_structures(1).FEE_BILLING_OPTION := 'BILL_WITH_INSTALLMENT';
1772 end if;
1773
1774 lns_fee_engine.processFees(p_init_msg_list => FND_API.G_TRUE
1775 ,p_commit => FND_API.G_FALSE
1776 ,p_loan_id => p_loan_id
1777 ,p_installment_number => p_installment_number
1778 ,p_fee_basis_tbl => l_fee_basis_tbl
1779 ,p_fee_structures => l_fee_structures
1780 ,x_fees_tbl => l_fees_tbl
1781 ,x_return_status => l_return_Status
1782 ,x_msg_count => l_msg_count
1783 ,x_msg_data => l_msg_data);
1784
1785 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_return_status = ' || l_return_status);
1786 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1787 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1788 FND_MSG_PUB.ADD;
1789 RAISE FND_API.G_EXC_ERROR;
1790 end if;
1791 end if;
1792
1793 if p_installment_number > 0 then
1794
1795 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing late fees');
1796 lns_fee_engine.processLateFees(p_loan_id => p_loan_id
1797 ,p_init_msg_list => p_init_msg_list
1798 ,p_commit => 'F'
1799 ,p_phase => l_loan_details.LOAN_PHASE
1800 ,x_return_status => l_return_status
1801 ,x_msg_count => l_msg_count
1802 ,x_msg_data => l_msg_data);
1803
1804 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_return_status = ' || l_return_status);
1805 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1806 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1807 FND_MSG_PUB.ADD;
1808 RAISE FND_API.G_EXC_ERROR;
1809 end if;
1810
1811 l_fee_structures.delete;
1812 l_fees_tbl.delete;
1813 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing recurring fees');
1814 -- add the recurring fees for the installment onto the fee schedule
1815 l_fee_structures(1).fee_category := 'RECUR';
1816 l_fee_structures(1).fee_type := null;
1817
1818 lns_fee_engine.processFees(p_init_msg_list => FND_API.G_TRUE
1819 ,p_commit => FND_API.G_FALSE
1820 ,p_loan_id => p_loan_id
1821 ,p_installment_number => p_installment_number
1822 ,p_fee_basis_tbl => l_fee_basis_tbl
1823 ,p_fee_structures => l_fee_structures
1824 ,x_fees_tbl => l_fees_tbl
1825 ,x_return_status => l_return_Status
1826 ,x_msg_count => l_msg_count
1827 ,x_msg_data => l_msg_data);
1828
1829 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_return_status = ' || l_return_status);
1830 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1831 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1832 FND_MSG_PUB.ADD;
1833 RAISE FND_API.G_EXC_ERROR;
1834 end if;
1835 end if;
1836
1837 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling lns_fee_engine.getFeeSchedule...');
1838 lns_fee_engine.getFeeSchedule(p_init_msg_list => FND_API.G_FALSE
1839 ,p_loan_id => p_loan_id
1840 ,p_installment_number => p_installment_number
1841 ,p_disb_header_id => null
1842 ,p_phase => 'TERM'
1843 ,x_fees_tbl => l_fees_tbl_1
1844 ,x_return_status => l_return_status
1845 ,x_msg_count => l_msg_count
1846 ,x_msg_data => l_msg_data);
1847
1848 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1849 FND_MESSAGE.SET_NAME('LNS', 'LNS_READ_FEE_ERROR');
1850 FND_MSG_PUB.ADD;
1851 RAISE FND_API.G_EXC_ERROR;
1852 end if;
1853
1854 for k in 1..l_fees_tbl_1.count loop
1855 l_fees_tbl_2(k).FEE_ID := l_fees_tbl_1(k).FEE_ID;
1856 l_fees_tbl_2(k).FEE_NAME := l_fees_tbl_1(k).FEE_NAME;
1857 l_fees_tbl_2(k).FEE_AMOUNT := l_fees_tbl_1(k).FEE_AMOUNT;
1858 l_fees_tbl_2(k).FEE_INSTALLMENT := l_fees_tbl_1(k).FEE_INSTALLMENT;
1859 l_fees_tbl_2(k).FEE_DESCRIPTION := l_fees_tbl_1(k).FEE_DESCRIPTION;
1860 l_fees_tbl_2(k).FEE_SCHEDULE_ID := l_fees_tbl_1(k).FEE_SCHEDULE_ID;
1861 l_fees_tbl_2(k).FEE_WAIVABLE_FLAG := l_fees_tbl_1(k).FEE_WAIVABLE_FLAG;
1862 l_fees_tbl_2(k).WAIVE_AMOUNT := l_fees_tbl_1(k).WAIVE_AMOUNT;
1863 l_fees_tbl_2(k).BILLED_FLAG := l_fees_tbl_1(k).BILLED_FLAG;
1864 l_fees_tbl_2(k).ACTIVE_FLAG := l_fees_tbl_1(k).ACTIVE_FLAG;
1865 l_total_fees := l_total_fees + l_fees_tbl_1(k).FEE_AMOUNT;
1866 end loop;
1867 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_fees_tbl_2.count = ' || l_fees_tbl_2.count);
1868
1869 -- overwrite amortization record returned from amortizationAPI
1870 l_amortization_rec.fee_amount := l_total_fees;
1871 x_fees_tbl := l_fees_tbl_2;
1872 x_amortization_rec := l_amortization_rec;
1873 -- --------------------------------------------------------------------
1874 -- End of API body
1875 -- --------------------------------------------------------------------
1876
1877 -- Standard check for p_commit
1878 IF FND_API.to_Boolean(p_commit) THEN
1879 COMMIT WORK;
1880 END IF;
1881
1882 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1883 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1884
1885 EXCEPTION
1886 WHEN FND_API.G_EXC_ERROR THEN
1887 ROLLBACK TO getInstallment;
1888 x_return_status := FND_API.G_RET_STS_ERROR;
1889 x_msg_count := l_msg_count;
1890 x_msg_data := l_msg_data;
1891 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1892 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1893
1894 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1895 ROLLBACK TO getInstallment;
1896 x_return_status := FND_API.G_RET_STS_ERROR;
1897 x_msg_count := l_msg_count;
1898 x_msg_data := l_msg_data;
1899 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1900 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1901
1902 WHEN OTHERS THEN
1903 ROLLBACK TO getInstallment;
1904 x_return_status := FND_API.G_RET_STS_ERROR;
1905 x_msg_count := l_msg_count;
1906 x_msg_data := l_msg_data;
1907 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1908 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1909
1910 end getInstallment;
1911
1912
1913 -- created for bug 6599682: EQUALLY SPREAD PRINCIPAL FROM IO PERIODS FOR EPRP LOANS
1914 function get_num_non_ro_instal(p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
1915 ,p_from_installment in NUMBER
1916 ,p_to_installment in NUMBER) return NUMBER
1917 is
1918 l_local_rate_schedule LNS_FINANCIALS.RATE_SCHEDULE_TBL;
1919 l_num_non_ro_payments number;
1920 l_total_installments number;
1921 i number;
1922 j number;
1923 l_api_name varchar2(30);
1924 l_from_installment number;
1925
1926 begin
1927
1928 l_api_name := 'get_num_non_ro_instal';
1929 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - BEGIN');
1930 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_from_installment=' || p_from_installment);
1931
1932 l_from_installment := p_from_installment;
1933 if (l_from_installment is null or l_from_installment = 0) then
1934 l_from_installment := 1;
1935 end if;
1936 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_from_installment=' || l_from_installment);
1937
1938 -- build normal rate schedule table
1939 for i in 1..p_rate_schedule.count loop
1940
1941 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'rate schedule row ' || i || ': from ' || p_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER || ' to ' || p_rate_schedule(i).END_INSTALLMENT_NUMBER);
1942
1943 for j in p_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER..p_rate_schedule(i).END_INSTALLMENT_NUMBER loop
1944
1945 l_local_rate_schedule(j) := p_rate_schedule(i);
1946 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'adding local rate schedule row ' || j);
1947
1948 end loop;
1949
1950 end loop;
1951
1952 l_num_non_ro_payments := 0;
1953 l_total_installments := l_local_rate_schedule.count;
1954
1955 if p_to_installment is not null then
1956 l_total_installments := p_to_installment;
1957 end if;
1958
1959 for i in l_from_installment..l_total_installments loop
1960
1961 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'local rate schedule row ' || i || ': IO ' || l_local_rate_schedule(i).INTEREST_ONLY_FLAG);
1962
1963 if (l_local_rate_schedule(i).INTEREST_ONLY_FLAG = 'N' or i = l_total_installments) then
1964 l_num_non_ro_payments := l_num_non_ro_payments + 1;
1965 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_num_non_ro_payments ' || l_num_non_ro_payments);
1966 end if;
1967
1968 end loop;
1969
1970 if (l_num_non_ro_payments = 0) then
1971 l_num_non_ro_payments := 1;
1972 end if;
1973
1974 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Result num_payments ' || l_num_non_ro_payments);
1975 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - END');
1976
1977 return l_num_non_ro_payments;
1978
1979 end;
1980
1981
1982
1983 /*=========================================================================
1984 || PUBLIC PROCEDURE getOpenInstallment
1985 ||
1986 || DESCRIPTION
1987 ||
1988 || Overview: returns interest for an installment during openend loan
1989 || this is used for the billing concurrent program
1990 ||
1991 || PSEUDO CODE/LOGIC
1992 ||
1993 || PARAMETERS
1994 ||
1995 || Parameter: p_loan_id => in loanID
1996 || p_installment_number = installment
1997 ||
1998 || Return value: AMORTIZATION_REC => contains billing and payment information
1999 ||
2000 || Source Tables: NA
2001 ||
2002 || Target Tables: NA
2003 ||
2004 || KNOWN ISSUES
2005 ||
2006 || NOTES
2007 || NOTE: api used by Billing Engine
2008 ||
2009 || MODIFICATION HISTORY
2010 || Date Author Description of Changes
2011 || 12/11/2003 12:40PM raverma Created
2012 ||
2013 *=======================================================================*/
2014 procedure getOpenInstallment(p_init_msg_list IN VARCHAR2
2015 ,p_loan_Id in number
2016 ,p_installment_number in number
2017 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
2018 ,x_fees_tbl OUT NOCOPY LNS_FINANCIALS.FEES_TBL
2019 ,x_return_status OUT NOCOPY VARCHAR2
2020 ,x_msg_count OUT NOCOPY NUMBER
2021 ,x_msg_data OUT NOCOPY VARCHAR2)
2022 is
2023 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
2024 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
2025 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2026 l_rate_schedule_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2027 l_rates_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2028 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
2029 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
2030
2031 l_count NUMBER;
2032 l_return_status VARCHAR2(1);
2033 l_msg_count NUMBER;
2034 l_msg_data VARCHAR2(32767);
2035 l_api_name varchar2(25);
2036
2037 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
2038 l_fees_tbl_1 LNS_FEE_ENGINE.FEE_CALC_TBL;
2039 l_fees_tbl_2 LNS_FINANCIALS.FEES_TBL;
2040 l_total_fees number;
2041 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
2042 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL; -- define what event(s) we are processing fees for
2043 i number;
2044 m number;
2045 l_wtd_balance number;
2046 l_periodic_rate number;
2047 l_annualized_rate number; -- needs to be converted to periodic rate
2048 l_periodic_interest number;
2049 l_periodic_principal number;
2050 l_installments number;
2051 l_weigted_rate number;
2052 l_days_at_rate number;
2053 l_total_days number;
2054 l_running_rate number;
2055 l_max_date date;
2056 l_spread number;
2057 l_rate_schedule_id number;
2058 l_rate_to_store number;
2059 l_raw_rate number;
2060 l_next_rate_change date;
2061
2062 cursor c_int_rates(p_rate_id number, p_rate_date date) is
2063 select interest_rate
2064 from lns_int_rate_lines
2065 where start_date_active <= p_rate_date
2066 and end_date_active >= p_rate_date
2067 and interest_rate_id = p_rate_id;
2068
2069 cursor c_rate_info(p_loan_id number) is
2070 select spread
2071 ,rate_id
2072 from lns_rate_schedules rs
2073 ,lns_terms t
2074 where t.loan_id = p_loan_id
2075 and t.term_id = rs.term_id
2076 and phase = 'OPEN';
2077 begin
2078
2079 l_api_name := 'getOpenInstallment';
2080 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2081 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
2082 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
2083
2084 -- Standard Start of API savepoint
2085 SAVEPOINT getOpenInstallment;
2086
2087 -- Initialize message list IF p_init_msg_list is set to TRUE.
2088 IF FND_API.to_Boolean(p_init_msg_list) THEN
2089 FND_MSG_PUB.initialize;
2090 END IF;
2091
2092 -- Initialize API return status to SUCCESS
2093 x_return_status := FND_API.G_RET_STS_SUCCESS;
2094
2095 -- --------------------------------------------------------------------
2096 -- Api body
2097 -- --------------------------------------------------------------------
2098 l_total_fees := 0;
2099 l_amortization_rec.principal_amount := 0;
2100 l_amortization_rec.interest_amount := 0;
2101 l_amortization_rec.total := 0;
2102 l_amortization_rec.fee_amount := 0;
2103 l_amortization_rec.begin_balance := 0;
2104 l_amortization_rec.end_balance := 0;
2105
2106 -- move logic for billing custom loans into FINANCIALS API
2107 l_loan_Details := lns_financials.getLoanDetails(p_loan_id, 'CURRENT', 'OPEN');
2108 l_rates_tbl := lns_financials.getRateSchedule(p_loan_id, 'OPEN');
2109
2110 -- call projection API
2111 lns_financials.loanProjection(p_loan_details => l_loan_Details
2112 ,p_based_on_terms => 'CURRENT'
2113 ,p_rate_schedule => l_rates_tbl
2114 ,x_loan_amort_tbl => l_amortization_tbl);
2115
2116 for p in 1..l_amortization_tbl.count loop
2117 if l_amortization_tbl(p).installment_number = p_installment_number then
2118 l_amortization_rec := l_amortization_tbl(p);
2119 exit;
2120 end if;
2121 end loop;
2122
2123 lns_fee_engine.getFeeSchedule(p_init_msg_list => FND_API.G_FALSE
2124 ,p_loan_id => p_loan_id
2125 ,p_installment_number => p_installment_number
2126 ,p_disb_header_id => null
2127 ,p_phase => 'OPEN'
2128 ,x_fees_tbl => l_fees_tbl_1
2129 ,x_return_status => l_return_status
2130 ,x_msg_count => l_msg_count
2131 ,x_msg_data => l_msg_data);
2132
2133 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
2134 FND_MESSAGE.SET_NAME('LNS', 'LNS_READ_FEE_ERROR');
2135 FND_MSG_PUB.ADD;
2136 RAISE FND_API.G_EXC_ERROR;
2137 end if;
2138
2139 for k in 1..l_fees_tbl_1.count loop
2140 l_fees_tbl_2(k).FEE_ID := l_fees_tbl_1(k).FEE_ID;
2141 l_fees_tbl_2(k).FEE_NAME := l_fees_tbl_1(k).FEE_NAME;
2142 l_fees_tbl_2(k).FEE_AMOUNT := l_fees_tbl_1(k).FEE_AMOUNT;
2143 l_fees_tbl_2(k).FEE_INSTALLMENT := l_fees_tbl_1(k).FEE_INSTALLMENT;
2144 l_fees_tbl_2(k).FEE_DESCRIPTION := l_fees_tbl_1(k).FEE_DESCRIPTION;
2145 l_fees_tbl_2(k).FEE_SCHEDULE_ID := l_fees_tbl_1(k).FEE_SCHEDULE_ID;
2146 l_fees_tbl_2(k).FEE_WAIVABLE_FLAG := l_fees_tbl_1(k).FEE_WAIVABLE_FLAG;
2147 l_fees_tbl_2(k).WAIVE_AMOUNT := l_fees_tbl_1(k).WAIVE_AMOUNT;
2148 l_fees_tbl_2(k).BILLED_FLAG := l_fees_tbl_1(k).BILLED_FLAG;
2149 l_fees_tbl_2(k).ACTIVE_FLAG := l_fees_tbl_1(k).ACTIVE_FLAG;
2150 l_total_fees := l_total_fees + l_fees_tbl_1(k).FEE_AMOUNT;
2151 end loop;
2152
2153 -- overwrite amortization record returned from amortizationAPI
2154 l_amortization_rec.rate_id := l_rate_Details.rate_id;
2155 l_amortization_rec.rate_unadj := l_annualized_rate;
2156 l_amortization_rec.RATE_CHANGE_FREQ:= l_loan_details.OPEN_RATE_CHG_FREQ;
2157 l_amortization_rec.fee_amount := l_total_fees;
2158 x_fees_tbl := l_fees_tbl_2;
2159 x_amortization_rec := l_amortization_rec;
2160 -- --------------------------------------------------------------------
2161 -- End of API body
2162 -- --------------------------------------------------------------------
2163
2164 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2165 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
2166
2167 EXCEPTION
2168 WHEN FND_API.G_EXC_ERROR THEN
2169 ROLLBACK TO getOpenInstallment;
2170 x_return_status := FND_API.G_RET_STS_ERROR;
2171 x_msg_count := l_msg_count;
2172 x_msg_data := l_msg_data;
2173 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2174 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2175
2176 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
2177 ROLLBACK TO getOpenInstallment;
2178 x_return_status := FND_API.G_RET_STS_ERROR;
2179 x_msg_count := l_msg_count;
2180 x_msg_data := l_msg_data;
2181 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2182 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2183
2184 WHEN OTHERS THEN
2185 ROLLBACK TO getOpenInstallment;
2186 x_return_status := FND_API.G_RET_STS_ERROR;
2187 x_msg_count := l_msg_count;
2188 x_msg_data := l_msg_data;
2189 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2190 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2191
2192 end getOpenInstallment;
2193
2194 /*=========================================================================
2195 || PUBLIC PROCEDURE getRatesTable
2196 ||
2197 || DESCRIPTION
2198 ||
2199 || Overview: function will return a table of dates for interest rates
2200 ||
2201 || Parameter: p_index_rate_id => index reference
2202 || p_index_date => date to start pulling rates
2203 || p_rate_change_frequency => frequency of rate changes
2204 || p_maturity_date => final date to get rates
2205 ||
2206 || Source Tables: NA
2207 ||
2208 || Target Tables:
2209 ||
2210 ||
2211 || KNOWN ISSUES
2212 ||
2213 || NOTES
2214 ||
2215 || MODIFICATION HISTORY
2216 || Date Author Description of Changes
2217 || 08/15/2005 11:35AM raverma Created
2218 *=======================================================================*/
2219 function getRatesTable(p_index_rate_id in number
2220 ,p_index_date in date
2221 ,p_rate_change_frequency in varchar2
2222 ,p_maturity_date in date) return LNS_FINANCIALS.RATE_SCHEDULE_TBL is
2223
2224 l_intial_date date;
2225 l_rate_date date;
2226 l_rate number;
2227 l_Rates_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2228 i number;
2229 l_api_name varchar2(25);
2230
2231 begin
2232
2233 l_api_name := 'getRatesTable';
2234
2235 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2236 i := 1;
2237 l_Rates_tbl(i).begin_date := p_index_date;
2238 l_rate_date := p_index_date;
2239 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_index_date ' || p_index_date);
2240 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_rate_change_frequency ' || p_rate_change_frequency);
2241 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_maturity_date ' || p_maturity_date );
2242 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_index_rate_id ' || p_index_rate_id );
2243
2244 WHILE l_rate_date <= p_maturity_date LOOP
2245 l_rate_date := lns_fin_utils.getNextDate(l_rate_date, p_rate_change_frequency, 1);
2246 i := i + 1;
2247 l_Rates_tbl(i).begin_date := l_rate_date;
2248 --logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_date ' || l_rate_date);
2249 END LOOP;
2250 /*
2251 for k in 1..l_Rates_tbl.count loop
2252 dbms_output.put_line(l_Rates_tbl(k).begin_date);
2253 end loop;
2254 */
2255 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
2256 return l_Rates_tbl;
2257
2258 end getRatesTable;
2259
2260
2261 -- created for bug 6498771
2262 function get_remain_num_prin_instal(p_payment_tbl in LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL
2263 ,p_from_installment in NUMBER) return NUMBER
2264 is
2265 l_num_prin_payments number;
2266 l_total_installments number;
2267 i number;
2268 begin
2269
2270 -- loop throught the amortization schedule and count number of PRIN and PRIN_INT rows
2271 l_num_prin_payments := 0;
2272 l_total_installments := p_payment_tbl.count;
2273 for i in p_from_installment..l_total_installments loop
2274 if (p_payment_tbl(i).CONTENTS = 'PRIN' or p_payment_tbl(i).CONTENTS = 'PRIN_INT') then
2275 l_num_prin_payments := l_num_prin_payments + 1;
2276 end if;
2277 end loop;
2278
2279 return l_num_prin_payments;
2280
2281 end;
2282
2283
2284 /*=========================================================================
2285 || PUBLIC PROCEDURE amortizeSIPLoan
2286 ||
2287 || DESCRIPTION
2288 ||
2289 || Overview: procedure generates seperate interest and principal amortization
2290 || this is the main calculation API for amortization
2291 || THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
2292 || 1. Amortization UI - when creating a loan
2293 || 2. Billing Engine - to generate installment bills
2294 ||
2295 || Parameter: p_loan_details = details of the loan
2296 || p_rate_schedule = rate schedule for the loan
2297 || p_installment_number => billing will pass in an installment
2298 || number to generate a billt
2299 || x_loan_amort_tbl => table of amortization records
2300 ||
2301 || Source Tables: NA
2302 ||
2303 || Target Tables: LNS_TEMP_AMORTIZATIONS
2304 ||
2305 ||
2306 || KNOWN ISSUES
2307 ||
2308 || NOTES
2309 ||
2310 || MODIFICATION HISTORY
2311 ||
2312 || Date Author Description of Changes
2313 || 10/08/2007 scherkas Created: fix for bug 6498771
2314 || 16/01/2008 scherkas Fixed bug 6749924
2315 || 08/04/2008 scherkas Fixed bug 6945153: change procedure to query past installments
2316 || 18/06/2008 scherkas Fixed bug 7184830
2317 *=======================================================================*/
2318 procedure amortizeSIPLoan(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
2319 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
2320 ,p_based_on_terms in varchar2
2321 ,p_installment_number in number
2322 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
2323 is
2324 l_return_status varchar2(1);
2325 l_msg_count NUMBER;
2326 l_msg_data VARCHAR2(32767);
2327 l_loan_id number;
2328 l_original_loan_amount number; -- loan amount
2329 l_amortized_term number;
2330 l_loan_term number;
2331 l_amortized_term_period varchar2(30);
2332 l_amortization_frequency varchar2(30);
2333 l_loan_period_number number;
2334 l_loan_period_type varchar2(30);
2335 l_first_payment_date date;
2336 l_pay_in_arrears boolean;
2337 l_payment_frequency varchar2(30);
2338 l_day_count_method varchar2(30);
2339 l_interest_comp_freq varchar2(30);
2340 l_calculation_method varchar2(30);
2341 l_reamortize_from_installment number;
2342 l_reamortize_amount number;
2343 l_annualized_rate number; -- annual rate on the loan
2344 l_intervals_remaining number;
2345 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
2346 l_current_rate_id number;
2347 l_previous_rate_id number;
2348 l_precision number;
2349
2350 l_period_start_Date date;
2351 l_period_end_date date;
2352 l_periodic_rate number;
2353 l_maturity_date date;
2354 l_amortized_maturity_date date;
2355
2356 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
2357 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
2358 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2359 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2360 l_principal_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2361 l_loan_start_date date;
2362 l_num_pay_dates number; -- number of dates on installment schedule
2363 l_periodic_payment number;
2364 l_periodic_principal number;
2365 l_periodic_interest number;
2366 l_interest_based_on_amount number; -- do we calculate interest from actual or predicted remaining balance
2367 l_pay_date date;
2368 l_total_principal number;
2369 l_payment_number number;
2370 l_fee_amount number;
2371 l_fee_amount1 number;
2372 l_other_amount number;
2373 l_begin_balance number;
2374 l_end_balance number;
2375 l_unbilled_principal number;
2376 l_unpaid_principal number;
2377 l_unpaid_interest number;
2378
2379 l_remaining_balance_actual number;
2380 l_remaining_balance_theory number;
2381 l_total number;
2382 l_interest_cumulative number;
2383 l_principal_cumulative number;
2384 l_fees_cumulative number;
2385 l_other_cumulative number;
2386 i number;
2387 l_installment_number number;
2388 l_billing boolean; -- switch to notify if billing is calling API
2389 l_api_name varchar2(20);
2390 l_last_installment_billed number;
2391 l_rate_to_calculate number;
2392 l_previous_annualized number;
2393 l_interest_only_flag varchar2(1);
2394 l_calc_method varchar2(30);
2395 l_compound_freq varchar2(30);
2396 l_interest number;
2397 l_hidden_cumul_interest number;
2398 l_num_prin_payments number;
2399 l_hidden_periodic_prin number;
2400 l_prin_first_pay_date date;
2401 l_prin_payment_frequency varchar2(30);
2402 l_prin_intervals number;
2403 l_prin_pay_in_arrears boolean;
2404 l_prin_amortized_intervals number;
2405 l_prin_intervals_diff number;
2406 l_remaining_balance_actual1 number;
2407 l_extend_from_installment number;
2408 l_norm_interest number;
2409 l_add_prin_interest number;
2410 l_add_int_interest number;
2411 l_add_start_date date;
2412 l_add_end_date date;
2413 l_start_installment number;
2414 l_end_installment number;
2415 l_first_installment_billed number;
2416 l_hidden_cumul_norm_int number;
2417 l_hidden_cumul_add_prin_int number;
2418 l_hidden_cumul_add_int_int number;
2419 l_hidden_cumul_penal_int number;
2420 l_periodic_norm_int number;
2421 l_periodic_add_prin_int number;
2422 l_periodic_add_int_int number;
2423 l_periodic_penal_int number;
2424 l_penal_prin_interest number;
2425 l_penal_int_interest number;
2426 l_penal_interest number;
2427 l_prev_grace_end_date date;
2428 l_raw_rate number;
2429 l_balloon_amount number;
2430 l_remaining_balance number;
2431 l_disb_header_id number;
2432 l_billed varchar2(1);
2433 n number;
2434 l_sum_periodic_principal number;
2435 l_date1 date;
2436 l_billed_principal number;
2437 l_detail_int_calc_flag boolean;
2438 l_increased_amount number;
2439 l_increased_amount1 number;
2440 l_begin_funded_amount number;
2441 l_end_funded_amount number;
2442 l_increase_amount_instal number;
2443 l_prev_increase_amount_instal number;
2444 l_begin_funded_amount_new number;
2445 l_begin number;
2446 l_last_prin_installment number;
2447 l_fund_sched_count number;
2448 l_wtd_balance number;
2449 l_balance1 number;
2450 l_balance2 number;
2451 l_remaining_balance_theory1 number;
2452 l_prev_cap_int number;
2453 l_early_pay_cr number;
2454 l_bill_on_appr_amounts varchar2(1);
2455
2456 l_norm_int_detail_str varchar2(2000);
2457 l_add_prin_int_detail_str varchar2(2000);
2458 l_add_int_int_detail_str varchar2(2000);
2459 l_penal_prin_int_detail_str varchar2(2000);
2460 l_penal_int_int_detail_str varchar2(2000);
2461 l_penal_int_detail_str varchar2(2000);
2462 l_hid_cumul_norm_int_dtl_str varchar2(2000);
2463 l_cap_int_detail_str varchar2(2000);
2464 l_early_pay_cr_detail_str varchar2(2000);
2465
2466 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
2467 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
2468 l_int_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
2469 l_prin_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
2470 l_PRIN_FREQUENCY_REC LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
2471 l_INT_FREQUENCY_REC LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
2472 l_current_prin_pay_freq varchar2(30);
2473 l_prev_prin_pay_freq varchar2(30);
2474
2475 -- get last bill date
2476 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
2477 select ACTIVITY_DATE
2478 from LNS_PRIN_TRX_ACTIVITIES_V
2479 where loan_id = p_loan_id
2480 and PAYMENT_NUMBER = p_installment_number
2481 and PARENT_AMORTIZATION_ID is null
2482 and ACTIVITY_CODE in ('BILLING', 'START');
2483
2484 -- get last billed principal info
2485 cursor c_get_last_payment(p_loan_id number, p_installment_number number) is
2486 select PRINCIPAL_AMOUNT, PAYMENT_NUMBER
2487 from lns_amortization_scheds
2488 where loan_id = p_loan_id
2489 and PAYMENT_NUMBER > 0
2490 and PAYMENT_NUMBER <= p_installment_number
2491 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
2492 and PARENT_AMORTIZATION_ID is null
2493 and REAMORTIZE_TO_INSTALLMENT is null
2494 and PRINCIPAL_AMOUNT > 0
2495 and nvl(PHASE, 'TERM') = 'TERM'
2496 order by PAYMENT_NUMBER desc;
2497
2498 -- get infor from last billed installment
2499 cursor c_get_funded_amount(p_loan_id number, p_installment_number number) is
2500 select FUNDED_AMOUNT, nvl(CAP_INT_AMOUNT, 0)
2501 from LNS_AMORTIZATION_SCHEDS
2502 where loan_id = p_loan_id
2503 and PAYMENT_NUMBER = p_installment_number
2504 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
2505 and PARENT_AMORTIZATION_ID is null
2506 and nvl(PHASE, 'TERM') = 'TERM';
2507
2508 cursor c_fund_sched_exist(p_loan_id number) is
2509 select decode(loan.loan_class_code,
2510 'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
2511 'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
2512 from lns_loan_headers_all loan
2513 where loan.loan_id = p_loan_id;
2514
2515 cursor c_get_bill_opt(p_loan_id number) is
2516 select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
2517 from lns_loan_headers_all
2518 where loan_id = p_loan_id;
2519
2520 begin
2521
2522 -- initialize all variables
2523 l_api_name := 'amortizeSIPLoan MAIN';
2524
2525 l_original_loan_amount := 0; -- loan amount
2526 l_loan_period_number := 0;
2527 l_previous_rate_id := -1;
2528 l_previous_annualized := -1;
2529 l_periodic_payment := 0;
2530 l_periodic_principal := 0;
2531 l_periodic_interest := 0;
2532 l_balloon_amount := 0;
2533 l_total_principal := 0;
2534 l_payment_number := 0;
2535 l_fee_amount := 0;
2536 l_other_amount := 0;
2537 l_begin_balance := 0;
2538 l_unbilled_principal := 0;
2539 l_unpaid_principal := 0;
2540 l_remaining_balance_actual := 0;
2541 l_remaining_balance_theory := 0;
2542 l_total := 0;
2543 l_interest_cumulative := 0;
2544 l_principal_cumulative := 0;
2545 l_fees_cumulative := 0;
2546 l_other_cumulative := 0;
2547 i := 0;
2548 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
2549 l_rate_to_calculate := 0;
2550 l_billing := false; -- switch to notify if billing is calling API
2551 l_hidden_cumul_interest := 0;
2552 l_hidden_periodic_prin := 0;
2553
2554 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2555 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
2556 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
2557
2558 l_loan_term := p_loan_details.loan_term;
2559 l_amortized_term := p_loan_details.amortized_term;
2560 l_amortized_term_period := p_loan_details.amortized_term_period;
2561 l_amortization_frequency := p_loan_details.amortization_frequency;
2562 l_payment_frequency := p_loan_details.payment_frequency;
2563 l_first_payment_date := p_loan_details.first_payment_date;
2564 l_original_loan_amount := p_loan_details.requested_amount;
2565 l_remaining_balance_actual := p_loan_details.remaining_balance;
2566 l_remaining_balance_actual1 := p_loan_details.remaining_balance;
2567 l_maturity_date := p_loan_details.maturity_date;
2568 l_balloon_amount := p_loan_details.balloon_payment_amount;
2569 l_last_installment_billed := p_loan_details.last_installment_billed;
2570 l_day_count_method := p_loan_details.day_count_method;
2571 l_loan_start_date := p_loan_details.loan_start_date;
2572 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
2573 l_precision := p_loan_details.currency_precision;
2574 l_reamortize_from_installment := p_loan_details.reamortize_from_installment;
2575 l_reamortize_amount := p_loan_details.reamortize_amount;
2576 l_loan_id := p_loan_details.loan_id;
2577 l_calc_method := p_loan_details.CALCULATION_METHOD;
2578 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
2579 l_prin_first_pay_date := p_loan_details.PRIN_FIRST_PAY_DATE;
2580 l_prin_payment_frequency := p_loan_details.PRIN_PAYMENT_FREQUENCY;
2581 l_prin_pay_in_arrears := p_loan_details.PRIN_PAY_IN_ARREARS_BOOL;
2582 l_extend_from_installment := p_loan_details.EXTEND_FROM_INSTALLMENT;
2583
2584 -- get the interest rate schedule
2585 l_rate_tbl := p_rate_schedule;
2586 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
2587
2588 -- get payment schedule
2589 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
2590
2591 l_int_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
2592 P_LOAN_ID => l_loan_id,
2593 P_PHASE => 'TERM',
2594 P_COMPONENT => 'INT');
2595
2596 l_prin_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
2597 P_LOAN_ID => l_loan_id,
2598 P_PHASE => 'TERM',
2599 P_COMPONENT => 'PRIN');
2600
2601 l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
2602 p_loan_start_date => l_loan_start_date,
2603 p_loan_maturity_date => l_maturity_date,
2604 p_prin_freq_schedule_tbl => l_prin_freq_schedule_tbl,
2605 p_int_freq_schedule_tbl => l_int_freq_schedule_tbl);
2606 /*
2607 l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
2608 p_loan_start_date => l_loan_start_date
2609 ,p_loan_maturity_date => l_maturity_date
2610 ,p_int_first_pay_date => l_first_payment_date
2611 ,p_int_num_intervals => null --l_intervals
2612 ,p_int_interval_type => l_payment_frequency
2613 ,p_int_pay_in_arrears => l_pay_in_arrears
2614 ,p_prin_first_pay_date => l_prin_first_pay_date
2615 ,p_prin_num_intervals => null --l_prin_intervals
2616 ,p_prin_interval_type => l_prin_payment_frequency
2617 ,p_prin_pay_in_arrears => l_prin_pay_in_arrears);
2618 */
2619 l_num_pay_dates := l_payment_tbl.count;
2620
2621 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
2622
2623 -- get amortize principal schedule
2624 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting principal schedule');
2625
2626 l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
2627 ,p_loan_maturity_date => l_maturity_date
2628 ,p_freq_schedule_tbl => l_prin_freq_schedule_tbl);
2629
2630 /*
2631 l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
2632 ,p_loan_maturity_date => l_maturity_date
2633 ,p_first_pay_date => l_prin_first_pay_date
2634 ,p_num_intervals => null --l_intervals
2635 ,p_interval_type => l_prin_payment_frequency
2636 ,p_pay_in_arrears => l_prin_pay_in_arrears);
2637 */
2638 l_prin_intervals := l_principal_tbl.count;
2639 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- principal schedule count = ' || l_prin_intervals);
2640
2641 if l_loan_term <> l_amortized_term then
2642 -- get amortize maturity date
2643 l_amortized_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term => l_amortized_term
2644 ,p_term_period => l_amortized_term_period
2645 ,p_frequency => l_prin_payment_frequency
2646 ,p_start_date => l_loan_start_date);
2647 -- get amortize principal schedule
2648 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting amortize principal schedule');
2649 l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
2650 ,p_loan_maturity_date => l_amortized_maturity_date
2651 ,p_freq_schedule_tbl => l_prin_freq_schedule_tbl);
2652 /*
2653 l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
2654 ,p_loan_maturity_date => l_amortized_maturity_date
2655 ,p_first_pay_date => l_prin_first_pay_date
2656 ,p_num_intervals => null --l_intervals
2657 ,p_interval_type => l_prin_payment_frequency
2658 ,p_pay_in_arrears => l_prin_pay_in_arrears);
2659 */
2660 l_prin_amortized_intervals := l_principal_tbl.count;
2661 else
2662 l_prin_amortized_intervals := l_prin_intervals;
2663 end if;
2664 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- amortize principal schedule count = ' || l_prin_amortized_intervals);
2665
2666 l_prin_intervals_diff := l_prin_amortized_intervals - l_prin_intervals;
2667 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- l_prin_intervals_diff = ' || l_prin_intervals_diff);
2668
2669 if p_based_on_terms <> 'CURRENT' then
2670 open c_fund_sched_exist(l_loan_id);
2671 fetch c_fund_sched_exist into l_fund_sched_count;
2672 close c_fund_sched_exist;
2673
2674 if l_fund_sched_count = 0 then
2675 l_original_loan_amount := p_loan_details.requested_amount;
2676 else
2677 l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
2678 end if;
2679 else
2680 l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
2681 end if;
2682
2683 l_fees_tbl.delete;
2684 l_fee_amount := 0;
2685
2686 -- filling out basis table
2687 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
2688 l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
2689 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
2690 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
2691 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
2692 l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
2693 l_fee_basis_tbl(4).fee_basis_name := 'TOTAL_UNDISB_AMT';
2694 l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
2695
2696 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
2697 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
2698 ,p_loan_id => l_loan_id
2699 ,p_installment => 0
2700 ,p_fee_basis_tbl => l_fee_basis_tbl
2701 ,p_based_on_terms => p_based_on_terms
2702 ,p_phase => 'TERM'
2703 ,x_fees_tbl => l_fees_tbl
2704 ,x_return_status => l_return_status
2705 ,x_msg_count => l_msg_count
2706 ,x_msg_data => l_msg_data);
2707
2708 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
2709 if l_return_status <> 'S' then
2710 RAISE FND_API.G_EXC_ERROR;
2711 end if;
2712
2713 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
2714
2715 for k in 1..l_fees_tbl.count loop
2716 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
2717 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
2718 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
2719 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
2720 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
2721 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
2722 end loop;
2723 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
2724
2725 if l_fee_amount > 0 then
2726 i := i + 1;
2727 l_amortization_rec.installment_number := 0;
2728 l_amortization_rec.due_date := l_loan_start_date;
2729 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
2730 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
2731 l_amortization_rec.principal_amount := 0;
2732 l_amortization_rec.interest_amount := 0;
2733 l_amortization_rec.fee_amount := l_fee_amount;
2734 l_amortization_rec.other_amount := 0;
2735 l_amortization_rec.begin_balance := l_original_loan_amount;
2736 l_amortization_rec.end_balance := l_original_loan_amount;
2737 l_amortization_rec.interest_cumulative := 0;
2738 l_amortization_rec.principal_cumulative := 0;
2739 l_amortization_rec.fees_cumulative := l_fee_amount;
2740 l_amortization_rec.other_cumulative := 0;
2741 l_amortization_rec.rate_id := 0;
2742 l_amortization_rec.SOURCE := 'PREDICTED';
2743 l_amortization_rec.total := l_fee_amount;
2744 l_amortization_rec.UNPAID_PRIN := 0;
2745 l_amortization_rec.UNPAID_INT := 0;
2746 l_amortization_rec.INTEREST_RATE := l_rate_tbl(1).annual_rate;
2747 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
2748 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
2749 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
2750 l_amortization_rec.PENAL_INT_AMOUNT := 0;
2751 l_amortization_rec.FUNDED_AMOUNT := l_original_loan_amount;
2752 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
2753 l_amortization_rec.DISBURSEMENT_AMOUNT := l_original_loan_amount;
2754 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
2755 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
2756 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
2757 l_amortization_rec.CAP_INT_AMOUNT := 0;
2758 l_amortization_rec.CAP_INT_DETAILS := null;
2759 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
2760
2761 -- add the record to the amortization table
2762 l_amortization_tbl(i) := l_amortization_rec;
2763 end if;
2764
2765 -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
2766 if p_installment_number is not null then
2767
2768 l_billing := true;
2769 if p_installment_number > 0 then
2770
2771 if p_installment_number > l_num_pay_dates then
2772 l_payment_number := l_num_pay_dates;
2773 else
2774 l_payment_number := p_installment_number;
2775 end if;
2776
2777 else
2778 l_payment_number := p_installment_number;
2779 end if;
2780
2781 else
2782
2783 l_payment_number := l_num_pay_dates;
2784
2785 end if;
2786
2787 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
2788 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
2789
2790 l_begin := 1;
2791
2792 if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
2793
2794 -- find last installment with billed principal
2795 open c_get_last_payment(l_loan_id, l_last_installment_billed);
2796 fetch c_get_last_payment into l_hidden_periodic_prin, l_last_prin_installment;
2797 close c_get_last_payment;
2798
2799 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
2800 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_prin_installment = ' || l_last_prin_installment);
2801
2802 l_begin := 0;
2803 -- find last installment with billed interest
2804 for j in REVERSE 1..l_last_installment_billed loop
2805 if l_payment_tbl(j).CONTENTS <> 'PRIN' then
2806 l_begin := j;
2807 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': installment ' || j || ' = ' || l_payment_tbl(j).CONTENTS);
2808 exit;
2809 end if;
2810 end loop;
2811
2812 l_begin_funded_amount := 0;
2813 if l_begin > 0 then
2814
2815 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2816 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_begin || '-----');
2817 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2818
2819 open c_get_funded_amount(l_loan_id, l_begin);
2820 fetch c_get_funded_amount into l_begin_funded_amount, l_prev_cap_int;
2821 close c_get_funded_amount;
2822
2823 end if;
2824 l_begin := l_begin + 1;
2825 else
2826 l_remaining_balance_theory := l_original_loan_amount;
2827 l_begin_funded_amount := 0; --l_original_loan_amount;
2828 l_end_funded_amount := l_original_loan_amount;
2829 l_prev_cap_int := 0;
2830
2831 open c_get_bill_opt(l_loan_id);
2832 fetch c_get_bill_opt into l_bill_on_appr_amounts;
2833 close c_get_bill_opt;
2834 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
2835 end if;
2836
2837 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2838 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin = ' || l_begin);
2839 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.REAMORTIZE_ON_FUNDING = ' || p_loan_details.REAMORTIZE_ON_FUNDING);
2840 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
2841
2842 l_hidden_cumul_norm_int := 0;
2843 l_hidden_cumul_add_prin_int := 0;
2844 l_hidden_cumul_add_int_int := 0;
2845 l_hidden_cumul_interest := 0;
2846 l_hidden_cumul_penal_int := 0;
2847 l_increase_amount_instal := -1;
2848
2849 if l_begin = 1 then
2850 l_prev_prin_pay_freq := '';
2851 else
2852 LNS_FIN_UTILS.fetchPayFreqRecByDate(
2853 p_FREQUENCY_SCHEDULE => l_prin_freq_schedule_tbl,
2854 p_DATE => l_payment_tbl(l_begin-1).PERIOD_DUE_DATE,
2855 x_FREQUENCY_REC => l_PRIN_FREQUENCY_REC);
2856 l_prev_prin_pay_freq := l_PRIN_FREQUENCY_REC.FREQUENCY;
2857 end if;
2858
2859 -- loop to build the amortization schedule
2860 for l_installment_number in l_begin..l_payment_number
2861 loop
2862
2863 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2864 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || ' -----');
2865 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2866
2867 i := i + 1;
2868 l_periodic_interest := 0;
2869 l_periodic_norm_int := 0;
2870 l_periodic_add_prin_int := 0;
2871 l_periodic_add_int_int := 0;
2872 l_periodic_penal_int := 0;
2873 l_periodic_principal := 0;
2874 l_fee_amount := 0;
2875 l_other_amount := 0;
2876 l_unpaid_principal := 0;
2877 l_unpaid_interest := 0;
2878 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
2879 l_detail_int_calc_flag := false;
2880 l_increased_amount := 0;
2881 l_increased_amount1 := 0;
2882 l_prev_increase_amount_instal := l_increase_amount_instal;
2883
2884 if l_fund_sched_count > 0 or p_based_on_terms = 'CURRENT' then
2885
2886 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number) then
2887
2888 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 = l_installment_number');
2889
2890 l_principal_cumulative := 0;
2891 l_interest_cumulative := 0;
2892 l_fees_cumulative := 0;
2893 l_other_cumulative := 0;
2894 l_sum_periodic_principal := 0;
2895 l_billed_principal := p_loan_details.billed_principal;
2896 l_unbilled_principal := p_loan_details.unbilled_principal;
2897 l_unpaid_principal := p_loan_details.unpaid_principal;
2898 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
2899
2900 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
2901 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
2902 l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
2903 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
2904
2905 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
2906 l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
2907 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
2908
2909 if l_end_funded_amount > l_begin_funded_amount then
2910 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
2911
2912 if l_end_funded_amount = l_begin_funded_amount_new then
2913 l_increase_amount_instal := l_installment_number;
2914 else
2915 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
2916 l_increase_amount_instal := l_installment_number + 1;
2917 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
2918 l_increase_amount_instal := l_installment_number;
2919 end if;
2920 end if;
2921
2922 elsif l_begin_funded_amount_new > l_begin_funded_amount then
2923 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new > l_begin_funded_amount');
2924 l_increase_amount_instal := l_installment_number;
2925 end if;
2926
2927 l_detail_int_calc_flag := true;
2928
2929 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
2930 l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
2931 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2932
2933 l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
2934 l_begin_funded_amount := l_begin_funded_amount_new;
2935 l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
2936 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
2937 l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal;
2938 else
2939 l_remaining_balance_theory := 0;
2940 end if;
2941
2942 elsif (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 > l_installment_number) then
2943
2944 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 > l_installment_number');
2945 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
2946 open c_get_funded_amount(l_loan_id, l_installment_number);
2947 fetch c_get_funded_amount into l_end_funded_amount, l_prev_cap_int;
2948 close c_get_funded_amount;
2949
2950 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2951 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
2952 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
2953 if l_end_funded_amount > l_begin_funded_amount then
2954 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
2955 l_detail_int_calc_flag := true;
2956
2957 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
2958 l_increase_amount_instal := l_installment_number + 1;
2959 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
2960 l_increase_amount_instal := l_installment_number;
2961 end if;
2962
2963 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
2964 l_remaining_balance_theory := l_begin_funded_amount - l_sum_periodic_principal;
2965 l_increased_amount := l_end_funded_amount - l_begin_funded_amount_new;
2966 end if;
2967 else
2968 l_remaining_balance_theory := 0;
2969 end if;
2970
2971 elsif (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 < l_installment_number) then
2972
2973 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 < l_installment_number');
2974 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
2975 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
2976 l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
2977 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2978
2979 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
2980 l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
2981 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
2982
2983 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
2984 l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
2985 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
2986
2987 if l_end_funded_amount > l_begin_funded_amount then
2988 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
2989 l_detail_int_calc_flag := true;
2990
2991 if l_end_funded_amount = l_begin_funded_amount_new then
2992 l_increase_amount_instal := l_installment_number;
2993 else
2994 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
2995 l_increase_amount_instal := l_installment_number + 1;
2996 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
2997 l_increase_amount_instal := l_installment_number;
2998 end if;
2999 end if;
3000
3001 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
3002 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
3003
3004 l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
3005 l_begin_funded_amount := l_begin_funded_amount_new;
3006 l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
3007 l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal - l_sum_periodic_principal;
3008 end if;
3009 else
3010 l_remaining_balance_theory := 0;
3011 end if;
3012
3013 end if;
3014
3015 elsif l_installment_number = 1 and l_fund_sched_count = 0 and p_based_on_terms <> 'CURRENT' then
3016 l_increased_amount := l_original_loan_amount;
3017 end if;
3018
3019 if p_loan_details.REAMORTIZE_ON_FUNDING = 'NO' then
3020 l_increase_amount_instal := -1;
3021 end if;
3022
3023 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3024
3025 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
3026 l_rate_details := getRateDetails(p_installment => l_installment_number
3027 ,p_rate_tbl => l_rate_tbl);
3028
3029 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
3030 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
3031 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
3032
3033 l_current_rate_id := l_rate_details.rate_id;
3034 l_annualized_rate := l_rate_details.annual_rate;
3035 l_interest_only_flag := l_rate_details.interest_only_flag;
3036
3037 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id = ' || l_current_rate_id);
3038 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag = ' || l_interest_only_flag);
3039 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized = ' || l_previous_annualized);
3040 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate = ' || l_annualized_rate);
3041 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
3042 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
3043 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment = ' || l_extend_from_installment);
3044 if l_detail_int_calc_flag then
3045 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = true');
3046 else
3047 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = false');
3048 end if;
3049 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount = ' || l_increased_amount);
3050 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount1 = ' || l_increased_amount1);
3051 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increase_amount_instal = ' || l_increase_amount_instal);
3052
3053 -- getting current frequency record
3054 LNS_FIN_UTILS.fetchPayFreqRecByDate(
3055 p_FREQUENCY_SCHEDULE => l_prin_freq_schedule_tbl,
3056 p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
3057 x_FREQUENCY_REC => l_PRIN_FREQUENCY_REC);
3058 l_current_prin_pay_freq := l_PRIN_FREQUENCY_REC.FREQUENCY;
3059
3060 LNS_FIN_UTILS.fetchPayFreqRecByDate(
3061 p_FREQUENCY_SCHEDULE => l_int_freq_schedule_tbl,
3062 p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
3063 x_FREQUENCY_REC => l_INT_FREQUENCY_REC);
3064 l_payment_frequency := l_INT_FREQUENCY_REC.FREQUENCY;
3065
3066 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_prin_pay_freq = ' || l_current_prin_pay_freq);
3067 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_prin_pay_freq = ' || l_prev_prin_pay_freq);
3068 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_frequency = ' || l_payment_frequency);
3069
3070 -- conditions to recalculate principal payment
3071 -- 1. 1-st installment
3072 -- 2. reamortization from installment = current installment
3073 -- 3. reamortize because loan term has been extended
3074 -- 4. hidden_periodic_prin = 0
3075 -- 5. funded amount has increased since last installment
3076 -- 6. principal payment frequency has changed since last period
3077
3078 if ((l_installment_number = 1) OR
3079 (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
3080 (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
3081 (l_hidden_periodic_prin = 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
3082 (l_prev_increase_amount_instal = l_installment_number or l_increase_amount_instal = l_installment_number) OR
3083 (l_current_prin_pay_freq <> l_prev_prin_pay_freq))
3084 then
3085
3086 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- RE-calculating periodic principal payment');
3087
3088 l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number) + l_prin_intervals_diff;
3089 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_num_prin_payments = ' || l_num_prin_payments);
3090
3091 l_remaining_balance := l_remaining_balance_theory + l_increased_amount1;
3092
3093 l_hidden_periodic_prin := lns_financials.calculateEPPayment(p_loan_amount => l_remaining_balance
3094 ,p_num_intervals => l_num_prin_payments
3095 ,p_ending_balance=> l_balloon_amount
3096 ,p_pay_in_arrears=> l_prin_pay_in_arrears);
3097
3098 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic principal payment = ' || l_hidden_periodic_prin);
3099
3100 else
3101 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD principal payment = ' || l_hidden_periodic_prin);
3102 end if;
3103
3104 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_interest = ' || l_hidden_cumul_interest);
3105 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_norm_int = ' || l_hidden_cumul_norm_int);
3106 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_prin_int = ' || l_hidden_cumul_add_prin_int);
3107 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_int_int = ' || l_hidden_cumul_add_int_int);
3108
3109 l_norm_interest := 0;
3110 l_add_prin_interest := 0;
3111 l_add_int_interest := 0;
3112 l_penal_prin_interest := 0;
3113 l_penal_int_interest := 0;
3114 l_penal_interest := 0;
3115 l_interest := 0;
3116 l_early_pay_cr := 0;
3117 l_norm_int_detail_str := null;
3118 l_add_prin_int_detail_str := null;
3119 l_add_int_int_detail_str := null;
3120 l_penal_prin_int_detail_str := null;
3121 l_penal_int_int_detail_str := null;
3122 l_penal_int_detail_str := null;
3123 l_early_pay_cr_detail_str := null;
3124
3125 -- now we will calculate the interest due for this period
3126 if (p_based_on_terms = 'CURRENT' and l_detail_int_calc_flag = true) then
3127
3128 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
3129 LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
3130 p_calc_method => l_calc_method,
3131 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3132 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
3133 p_interest_rate => l_annualized_rate,
3134 p_day_count_method => l_day_count_method,
3135 p_payment_freq => l_payment_frequency,
3136 p_compound_freq => l_compound_freq,
3137 p_adj_amount => l_sum_periodic_principal,
3138 p_CAP_AMOUNT => l_prev_cap_int,
3139 x_norm_interest => l_norm_interest,
3140 x_norm_int_details => l_norm_int_detail_str);
3141
3142 l_norm_interest := round(l_norm_interest, l_precision);
3143
3144 if (l_installment_number-1) >= 0 and l_last_installment_billed + 1 = l_installment_number then
3145
3146 -- get additional interest start date
3147 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
3148 fetch c_get_last_bill_date into l_add_start_date;
3149 close c_get_last_bill_date;
3150
3151 -- get additional interest end date
3152 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
3153 l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
3154 else
3155 l_add_end_date := sysdate;
3156 end if;
3157
3158 if (l_installment_number-1) > 0 then
3159 l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
3160 else
3161 l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
3162 end if;
3163
3164 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
3165 -- calculate additional interest on unpaid principal
3166 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
3167 p_calc_method => l_calc_method,
3168 p_period_start_date => l_add_start_date,
3169 p_period_end_date => l_add_end_date,
3170 p_interest_rate => l_annualized_rate,
3171 p_day_count_method => l_day_count_method,
3172 p_payment_freq => l_payment_frequency,
3173 p_compound_freq => l_compound_freq,
3174 p_prev_grace_end_date => l_prev_grace_end_date,
3175 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
3176 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3177 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
3178 p_target => 'UNPAID_PRIN',
3179 x_add_interest => l_add_prin_interest,
3180 x_penal_interest => l_penal_prin_interest,
3181 x_add_int_details => l_add_prin_int_detail_str,
3182 x_penal_int_details => l_penal_prin_int_detail_str);
3183 l_add_prin_interest := round(l_add_prin_interest, l_precision);
3184
3185 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
3186 -- calculate additional interest on unpaid interest
3187 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
3188 p_calc_method => l_calc_method,
3189 p_period_start_date => l_add_start_date,
3190 p_period_end_date => l_add_end_date,
3191 p_interest_rate => l_annualized_rate,
3192 p_day_count_method => l_day_count_method,
3193 p_payment_freq => l_payment_frequency,
3194 p_compound_freq => l_compound_freq,
3195 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
3196 p_prev_grace_end_date => l_prev_grace_end_date,
3197 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3198 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
3199 p_target => 'UNPAID_INT',
3200 x_add_interest => l_add_int_interest,
3201 x_penal_interest => l_penal_int_interest,
3202 x_add_int_details => l_add_int_int_detail_str,
3203 x_penal_int_details => l_penal_int_int_detail_str);
3204 l_add_int_interest := round(l_add_int_interest, l_precision);
3205
3206 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
3207 l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
3208 else
3209 l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
3210 end if;
3211
3212 -- calculate interest credit on early payment
3213 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
3214 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => l_loan_id,
3215 p_calc_method => l_calc_method,
3216 p_installment => l_installment_number,
3217 p_interest_rate => l_previous_annualized,
3218 p_day_count_method => l_day_count_method,
3219 p_payment_freq => l_payment_frequency,
3220 p_compound_freq => l_compound_freq,
3221 x_early_pay_cr => l_early_pay_cr,
3222 x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
3223
3224 end if;
3225
3226 elsif (p_based_on_terms <> 'CURRENT' and l_detail_int_calc_flag = true and l_bill_on_appr_amounts = 'N') then
3227
3228 if (l_calc_method = 'SIMPLE') then
3229
3230 -- recalculate periodic rate for each period if day counting methodolgy varies
3231 l_periodic_rate := lns_financials.getPeriodicRate(
3232 p_payment_freq => l_payment_frequency
3233 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3234 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3235 ,p_annualized_rate => l_annualized_rate
3236 ,p_days_count_method => l_day_count_method
3237 ,p_target => 'INTEREST');
3238
3239 elsif (l_calc_method = 'COMPOUND') then
3240
3241 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
3242 ,p_payment_freq => l_payment_frequency
3243 ,p_annualized_rate => l_annualized_rate
3244 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3245 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3246 ,p_days_count_method => l_day_count_method
3247 ,p_target => 'INTEREST');
3248
3249 end if;
3250
3251 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
3252 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
3253 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
3254 ,p_calc_method => 'TARGET'
3255 ,p_phase => 'TERM'
3256 ,p_day_count_method => l_day_count_method
3257 ,p_adj_amount => l_sum_periodic_principal
3258 ,x_wtd_balance => l_wtd_balance
3259 ,x_begin_balance => l_balance1
3260 ,x_end_balance => l_balance2);
3261
3262 l_wtd_balance := l_wtd_balance + l_prev_cap_int;
3263 l_norm_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
3264 ,p_periodic_rate => l_periodic_rate
3265 ,p_compounding_period => null);
3266 l_norm_interest := round(l_norm_interest, l_precision);
3267
3268 l_norm_int_detail_str := l_norm_interest || ' (' ||
3269 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
3270 ' * Balance ' || l_wtd_balance ||
3271 ' * Rate ' || l_annualized_rate || '%)';
3272 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
3273
3274 else
3275
3276 l_remaining_balance_theory1 := l_remaining_balance_theory + l_prev_cap_int;
3277 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_theory1);
3278
3279 if (l_calc_method = 'SIMPLE') then
3280
3281 -- recalculate periodic rate for each period if day counting methodolgy varies
3282 l_periodic_rate := lns_financials.getPeriodicRate(
3283 p_payment_freq => l_payment_frequency
3284 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3285 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3286 ,p_annualized_rate => l_annualized_rate
3287 ,p_days_count_method => l_day_count_method
3288 ,p_target => 'INTEREST');
3289
3290 elsif (l_calc_method = 'COMPOUND') then
3291
3292 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
3293 ,p_payment_freq => l_payment_frequency
3294 ,p_annualized_rate => l_annualized_rate
3295 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3296 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3297 ,p_days_count_method => l_day_count_method
3298 ,p_target => 'INTEREST');
3299
3300 end if;
3301
3302 l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_theory1
3303 ,p_periodic_rate => l_periodic_rate
3304 ,p_compounding_period => null);
3305 l_norm_interest := round(l_norm_interest, l_precision);
3306
3307 l_norm_int_detail_str := l_norm_interest || ' (' ||
3308 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
3309 ' * Balance ' || l_remaining_balance_theory1 ||
3310 ' * Rate ' || l_annualized_rate || '%)';
3311 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
3312
3313 end if;
3314
3315 if l_hidden_cumul_norm_int > 0 then
3316 l_hid_cumul_norm_int_dtl_str := 'Previously Deferred Interest ' || l_hidden_cumul_norm_int ||
3317 ' +<br>Current Normal Interest ' || l_norm_int_detail_str;
3318 else
3319 l_hid_cumul_norm_int_dtl_str := 'Current Normal Interest ' || l_norm_int_detail_str;
3320 end if;
3321
3322 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
3323 l_interest := l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest - l_early_pay_cr;
3324 l_hidden_cumul_norm_int := l_hidden_cumul_norm_int + l_norm_interest;
3325 l_hidden_cumul_add_prin_int := l_hidden_cumul_add_prin_int + l_add_prin_interest;
3326 l_hidden_cumul_add_int_int := l_hidden_cumul_add_int_int + l_add_int_interest;
3327 l_hidden_cumul_interest := l_hidden_cumul_interest + l_interest;
3328 l_hidden_cumul_penal_int := l_hidden_cumul_penal_int + l_penal_interest;
3329
3330 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_norm_interest = ' || l_norm_interest);
3331 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_prin_interest = ' || l_add_prin_interest);
3332 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_interest = ' || l_add_int_interest);
3333 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
3334 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest = ' || l_interest);
3335
3336 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CONTENTS = ' || l_payment_tbl(l_installment_number).CONTENTS);
3337
3338 if (l_payment_tbl(l_installment_number).CONTENTS = 'PRIN') then
3339
3340 l_periodic_interest := 0;
3341 l_periodic_norm_int := 0;
3342 l_periodic_add_prin_int := 0;
3343 l_periodic_add_int_int := 0;
3344 l_periodic_penal_int := 0;
3345
3346 l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number);
3347
3348 if (l_remaining_balance_theory + l_increased_amount1) < l_hidden_periodic_prin then
3349 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3350 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3351 else
3352 if (l_num_prin_payments = 1) then
3353 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
3354 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal = ' || l_unbilled_principal);
3355 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3356 if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
3357 l_periodic_principal := l_unbilled_principal;
3358 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
3359 else
3360 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3361 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3362 end if;
3363 else
3364 l_periodic_principal := l_hidden_periodic_prin;
3365 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_hidden_periodic_prin');
3366 end if;
3367 end if;
3368
3369 if l_hidden_cumul_interest > 0 then
3370 l_norm_int_detail_str := l_hid_cumul_norm_int_dtl_str || ' <br>' || 'Interest is deferred';
3371 end if;
3372
3373 elsif (l_payment_tbl(l_installment_number).CONTENTS = 'INT') then
3374
3375 l_periodic_interest := l_hidden_cumul_interest;
3376 l_periodic_norm_int := l_hidden_cumul_norm_int;
3377 l_periodic_add_prin_int := l_hidden_cumul_add_prin_int;
3378 l_periodic_add_int_int := l_hidden_cumul_add_int_int;
3379 l_periodic_penal_int := l_hidden_cumul_penal_int;
3380 l_hidden_cumul_interest := 0;
3381 l_hidden_cumul_norm_int := 0;
3382 l_hidden_cumul_add_prin_int := 0;
3383 l_hidden_cumul_add_int_int := 0;
3384 l_hidden_cumul_penal_int := 0;
3385 l_periodic_principal := 0;
3386 l_norm_int_detail_str := l_hid_cumul_norm_int_dtl_str;
3387
3388 else
3389
3390 l_periodic_interest := l_hidden_cumul_interest;
3391 l_periodic_norm_int := l_hidden_cumul_norm_int;
3392 l_periodic_add_prin_int := l_hidden_cumul_add_prin_int;
3393 l_periodic_add_int_int := l_hidden_cumul_add_int_int;
3394 l_periodic_penal_int := l_hidden_cumul_penal_int;
3395 l_hidden_cumul_interest := 0;
3396 l_hidden_cumul_norm_int := 0;
3397 l_hidden_cumul_add_prin_int := 0;
3398 l_hidden_cumul_add_int_int := 0;
3399 l_hidden_cumul_penal_int := 0;
3400 l_norm_int_detail_str := l_hid_cumul_norm_int_dtl_str;
3401
3402 l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number);
3403
3404 if (l_remaining_balance_theory + l_increased_amount1) < l_hidden_periodic_prin then
3405 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3406 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3407 else
3408 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
3409 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal = ' || l_unbilled_principal);
3410 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3411 if (l_num_prin_payments = 1) then
3412 if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
3413 l_periodic_principal := l_unbilled_principal;
3414 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
3415 else
3416 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3417 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3418 end if;
3419 else
3420 l_periodic_principal := l_hidden_periodic_prin;
3421 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_hidden_periodic_prin');
3422 end if;
3423 end if;
3424
3425 end if;
3426
3427 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_norm_int = ' || l_hidden_cumul_norm_int);
3428 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_prin_int = ' || l_hidden_cumul_add_prin_int);
3429 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_int_int = ' || l_hidden_cumul_add_int_int);
3430 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_interest = ' || l_hidden_cumul_interest);
3431 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_penal_int = ' || l_hidden_cumul_penal_int);
3432 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
3433
3434 -- round int and prin and calc total
3435 l_periodic_principal := round(l_periodic_principal, l_precision);
3436 l_periodic_interest := round(l_periodic_interest, l_precision);
3437 l_periodic_payment := l_periodic_principal + l_periodic_interest;
3438
3439 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': principal = ' || l_periodic_principal);
3440 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest = ' || l_periodic_interest);
3441 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': total = ' || l_periodic_payment);
3442 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3443
3444 -- calculate balances and total payment
3445 l_begin_balance := l_remaining_balance_theory;
3446 l_end_balance := l_remaining_balance_theory - l_periodic_principal + l_increased_amount1;
3447
3448 -- check to see if this loan has been billed
3449 if l_unbilled_principal > 0 then
3450 l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
3451 end if;
3452
3453 -- build the amortization record
3454 l_amortization_rec.installment_number := l_installment_number; /* needed to calculate fees */
3455 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
3456 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
3457 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
3458 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
3459 l_amortization_rec.interest_amount := l_periodic_interest;
3460 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
3461 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
3462 l_amortization_rec.INTEREST_RATE := l_annualized_rate;
3463 l_amortization_rec.NORMAL_INT_AMOUNT := l_periodic_norm_int;
3464 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_periodic_add_prin_int;
3465 l_amortization_rec.ADD_INT_INT_AMOUNT := l_periodic_add_int_int;
3466 l_amortization_rec.PENAL_INT_AMOUNT := l_periodic_penal_int;
3467 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
3468 l_amortization_rec.DISBURSEMENT_AMOUNT := l_increased_amount;
3469 l_amortization_rec.FUNDED_AMOUNT := l_end_funded_amount;
3470 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
3471 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
3472 l_amortization_rec.EARLY_PAY_CR_AMOUNT := -l_early_pay_cr;
3473
3474 if l_amortization_rec.FUNDED_AMOUNT is null then
3475 l_amortization_rec.FUNDED_AMOUNT := 0;
3476 end if;
3477
3478 l_cap_int_detail_str := null;
3479 l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
3480 if p_loan_details.CAPITALIZE_INT = 'Y' then
3481 l_amortization_rec.begin_balance := l_begin_balance + l_prev_cap_int;
3482 if l_end_balance = 0 and l_amortization_rec.interest_amount > 0 then
3483 l_amortization_rec.end_balance := l_end_balance;
3484 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_prev_cap_int;
3485 l_amortization_rec.CAP_INT_AMOUNT := 0;
3486 l_prev_cap_int := 0;
3487 l_amortization_rec.interest_amount := l_amortization_rec.interest_amount + l_amortization_rec.PREV_CAP_INT_AMOUNT;
3488 else
3489 l_amortization_rec.end_balance := l_end_balance + l_prev_cap_int;
3490 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
3491 l_amortization_rec.CAP_INT_AMOUNT := l_prev_cap_int + l_amortization_rec.interest_amount;
3492 if l_amortization_rec.CAP_INT_AMOUNT > 0 then
3493 if l_prev_cap_int <> 0 then
3494 l_cap_int_detail_str := 'Previously Capitalized Interest ' || l_prev_cap_int;
3495 end if;
3496 if l_norm_interest <> 0 and l_hidden_cumul_interest = 0 then
3497 if l_cap_int_detail_str is not null then
3498 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3499 end if;
3500 l_cap_int_detail_str := l_cap_int_detail_str || l_norm_int_detail_str;
3501 end if;
3502 if l_add_prin_interest <> 0 then
3503 if l_cap_int_detail_str is not null then
3504 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3505 end if;
3506 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Prin ' || l_add_prin_int_detail_str;
3507 end if;
3508 if l_add_int_interest <> 0 then
3509 if l_cap_int_detail_str is not null then
3510 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3511 end if;
3512 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Interest ' || l_add_int_int_detail_str;
3513 end if;
3514 if l_penal_interest <> 0 then
3515 if l_cap_int_detail_str is not null then
3516 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3517 end if;
3518 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Penal Interest ' || l_penal_interest || ' (' || l_penal_int_detail_str || ')';
3519 end if;
3520 if l_early_pay_cr <> 0 then
3521 if l_cap_int_detail_str is not null then
3522 l_cap_int_detail_str := l_cap_int_detail_str || ' -<br>';
3523 end if;
3524 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Int Cr on Early Payment ' || l_early_pay_cr || ' (' || l_early_pay_cr_detail_str || ')';
3525 end if;
3526 end if;
3527 l_prev_cap_int := l_amortization_rec.CAP_INT_AMOUNT;
3528 if l_amortization_rec.NORMAL_INT_AMOUNT > 0 then
3529 l_norm_int_detail_str := 'Interest amount is capitalized';
3530 end if;
3531
3532 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_amortization_rec.interest_amount;
3533 l_amortization_rec.interest_amount := 0;
3534 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
3535 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
3536 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
3537 l_amortization_rec.PENAL_INT_AMOUNT := 0;
3538 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
3539
3540 l_add_prin_int_detail_str := null;
3541 l_add_int_int_detail_str := null;
3542 l_penal_prin_int_detail_str := null;
3543 l_penal_int_int_detail_str := null;
3544 l_penal_int_detail_str := null;
3545 l_early_pay_cr_detail_str := null;
3546 end if;
3547 else
3548 l_amortization_rec.begin_balance := l_begin_balance;
3549 l_amortization_rec.end_balance := l_end_balance;
3550 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
3551 l_amortization_rec.CAP_INT_AMOUNT := 0;
3552 l_prev_cap_int := 0;
3553 end if;
3554 l_amortization_rec.total := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
3555
3556 l_fees_tbl.delete;
3557 l_fee_amount := 0;
3558 l_other_amount := 0;
3559
3560 -- filling out basis table
3561 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
3562 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
3563 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
3564 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
3565 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
3566 l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
3567 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN';
3568 l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
3569 l_fee_basis_tbl(5).fee_basis_name := 'OVERDUE_PRIN_INT';
3570 l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
3571 l_fee_basis_tbl(6).fee_basis_name := 'IND_DISB_AMT';
3572 l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
3573 l_fee_basis_tbl(7).fee_basis_name := 'TOTAL_UNDISB_AMT';
3574 l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
3575 l_fee_basis_tbl(8).fee_basis_name := 'OVERDUE_INT';
3576 l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
3577 l_fee_basis_tbl(9).fee_basis_name := 'CURR_LOAN';
3578 l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
3579
3580 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
3581 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
3582 ,p_loan_id => l_loan_id
3583 ,p_installment => l_installment_number
3584 ,p_fee_basis_tbl => l_fee_basis_tbl
3585 ,p_based_on_terms => p_based_on_terms
3586 ,p_phase => 'TERM'
3587 ,x_fees_tbl => l_fees_tbl
3588 ,x_return_status => l_return_status
3589 ,x_msg_count => l_msg_count
3590 ,x_msg_data => l_msg_data);
3591
3592 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
3593 if l_return_status <> 'S' then
3594 RAISE FND_API.G_EXC_ERROR;
3595 end if;
3596
3597 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
3598
3599 for k in 1..l_fees_tbl.count loop
3600 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
3601 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
3602 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
3603 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
3604 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
3605 if l_fees_tbl(k).FEE_CATEGORY = 'MEMO' then
3606 l_other_amount := l_other_amount + l_fees_tbl(k).FEE_AMOUNT;
3607 else
3608 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
3609 end if;
3610 end loop;
3611 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for this installment = ' || l_fee_amount);
3612
3613 l_amortization_rec.fee_amount := l_fee_amount;
3614 l_amortization_rec.other_amount := l_other_amount;
3615 l_amortization_rec.total := l_amortization_rec.total + l_amortization_rec.fee_amount + l_amortization_rec.other_amount;
3616
3617 -- running totals calculated here
3618 l_principal_cumulative := l_principal_cumulative + l_amortization_rec.principal_amount;
3619 l_interest_cumulative := l_interest_cumulative + l_amortization_rec.interest_amount;
3620 l_fees_cumulative := l_fees_cumulative + l_amortization_rec.fee_amount;
3621 l_other_cumulative := l_other_cumulative + l_amortization_rec.other_amount;
3622
3623 l_amortization_rec.interest_cumulative := l_interest_cumulative;
3624 l_amortization_rec.principal_cumulative := l_principal_cumulative;
3625 l_amortization_rec.fees_cumulative := l_fees_cumulative;
3626 l_amortization_rec.other_cumulative := l_other_cumulative;
3627 l_amortization_rec.rate_id := l_current_rate_id;
3628 l_amortization_rec.SOURCE := 'PREDICTED';
3629
3630 l_amortization_rec.NORMAL_INT_DETAILS := l_norm_int_detail_str;
3631 l_amortization_rec.ADD_PRIN_INT_DETAILS := l_add_prin_int_detail_str;
3632 l_amortization_rec.ADD_INT_INT_DETAILS := l_add_int_int_detail_str;
3633 l_amortization_rec.PENAL_INT_DETAILS := l_penal_int_detail_str;
3634 l_amortization_rec.CAP_INT_DETAILS := l_cap_int_detail_str;
3635 l_amortization_rec.EARLY_PAY_CR_DETAILS := l_early_pay_cr_detail_str;
3636
3637 -- add the record to the amortization table
3638 l_amortization_tbl(i) := l_amortization_rec;
3639
3640 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
3641 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INSTALLMENT ' || l_installment_number);
3642 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
3643 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD = ' || l_amortization_rec.PERIOD);
3644 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_START_DATE = ' || l_amortization_rec.PERIOD_START_DATE);
3645 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_END_DATE = ' || l_amortization_rec.PERIOD_END_DATE);
3646 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'due date = ' || l_amortization_rec.due_date);
3647 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_principal = ' || l_amortization_rec.principal_amount);
3648 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_interest = ' || l_amortization_rec.interest_amount);
3649 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fee_amount = ' || l_amortization_rec.fee_amount);
3650 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_amount = ' || l_amortization_rec.other_amount);
3651 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'total = ' || l_amortization_rec.total);
3652 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'begin_balance = ' || l_amortization_rec.begin_balance);
3653 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'end_balance = ' || l_amortization_rec.end_balance);
3654 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'interest_cumulative = ' || l_amortization_rec.interest_cumulative);
3655 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'principal_cumulative = ' || l_amortization_rec.principal_cumulative);
3656 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fees_cumulative = ' || l_amortization_rec.fees_cumulative);
3657 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_cumulative = ' || l_amortization_rec.other_cumulative);
3658 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'current_rate_id = ' || l_amortization_rec.rate_id );
3659 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_RATE = ' || l_amortization_rec.INTEREST_RATE );
3660 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_PRIN = ' || l_amortization_rec.UNPAID_PRIN );
3661 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_INT = ' || l_amortization_rec.UNPAID_INT );
3662 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
3663 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_AMOUNT = ' || l_amortization_rec.ADD_PRIN_INT_AMOUNT );
3664 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_AMOUNT );
3665 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_AMOUNT = ' || l_amortization_rec.PENAL_INT_AMOUNT );
3666 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FUNDED_AMOUNT = ' || l_amortization_rec.FUNDED_AMOUNT );
3667 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amortization_rec.NORMAL_INT_DETAILS );
3668 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_DETAILS = ' || l_amortization_rec.ADD_PRIN_INT_DETAILS );
3669 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_DETAILS_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_DETAILS );
3670 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_DETAILS = ' || l_amortization_rec.PENAL_INT_DETAILS );
3671 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amortization_rec.PREV_CAP_INT_AMOUNT );
3672 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amortization_rec.CURR_CAP_INT_AMOUNT );
3673 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amortization_rec.CAP_INT_AMOUNT );
3674 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amortization_rec.CAP_INT_DETAILS );
3675 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_AMOUNT = ' || l_amortization_rec.EARLY_PAY_CR_AMOUNT );
3676 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_DETAILS = ' || l_amortization_rec.EARLY_PAY_CR_DETAILS );
3677 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
3678
3679 l_remaining_balance_theory := l_end_balance;
3680 l_sum_periodic_principal := l_sum_periodic_principal + l_periodic_principal;
3681
3682 l_previous_rate_id := l_current_rate_id;
3683 l_previous_annualized := l_annualized_rate;
3684 l_prev_prin_pay_freq := l_current_prin_pay_freq;
3685
3686 end loop;
3687
3688 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT IS ' || l_amortization_tbl.count);
3689 x_loan_amort_tbl := l_amortization_tbl;
3690
3691 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
3692
3693 Exception
3694 WHEN FND_API.G_EXC_ERROR THEN
3695 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
3696
3697 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
3698 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
3699
3700 WHEN OTHERS THEN
3701 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
3702
3703 end amortizeSIPLoan;
3704
3705
3706
3707 /*=========================================================================
3708 || PUBLIC PROCEDURE amortizeEPLoan
3709 ||
3710 || DESCRIPTION
3711 ||
3712 || Overview: this is the main calculation API for EP amortization
3713 || THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
3714 || 1. Amortization UI - when creating a loan
3715 || 2. Billing Engine - to generate installment bills
3716 ||
3717 || Parameter: p_loan_details = details of the loan
3718 || p_rate_schedule = rate schedule for the loan
3719 || p_installment_number => billing will pass in an installment
3720 || number to generate a billt
3721 || x_loan_amort_tbl => table of amortization records
3722 ||
3723 || Source Tables: NA
3724 ||
3725 || Target Tables: LNS_TEMP_AMORTIZATIONS
3726 ||
3727 ||
3728 || KNOWN ISSUES
3729 ||
3730 || NOTES
3731 ||
3732 || MODIFICATION HISTORY
3733 |
3734 | Date Author Description of Changes
3735 || 09/13/2007 scherkas Created
3736 || 16/01/2008 scherkas Fixed bug 6749924
3737 *=======================================================================*/
3738 procedure amortizeEPLoan(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
3739 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
3740 ,p_based_on_terms in varchar2
3741 ,p_installment_number in number
3742 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
3743 is
3744 l_return_status varchar2(1);
3745 l_msg_count NUMBER;
3746 l_msg_data VARCHAR2(32767);
3747 l_loan_id number;
3748 l_original_loan_amount number; -- loan amount
3749 l_amortized_term number;
3750 l_loan_term number;
3751 l_amortized_term_period varchar2(30);
3752 l_amortization_frequency varchar2(30);
3753 l_loan_period_number number;
3754 l_loan_period_type varchar2(30);
3755 l_first_payment_date date;
3756 l_pay_in_arrears boolean;
3757 l_payment_frequency varchar2(30);
3758 l_day_count_method varchar2(30);
3759 l_interest_comp_freq varchar2(30);
3760 l_calculation_method varchar2(30);
3761 l_reamortize_from_installment number;
3762 l_reamortize_amount number;
3763 l_annualized_rate number; -- annual rate on the loan
3764 l_intervals_remaining number;
3765 l_amortization_intervals number; -- number of intervals to amortize over
3766 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
3767 l_current_rate_id number;
3768 l_previous_rate_id number;
3769 l_precision number;
3770
3771 l_period_start_Date date;
3772 l_period_end_date date;
3773 l_periodic_rate number;
3774 l_maturity_date date;
3775 l_amortized_maturity_date date;
3776
3777 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
3778 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
3779 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
3780 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
3781 l_amortized_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
3782 l_loan_start_date date;
3783 l_num_pay_dates number; -- number of dates on installment schedule
3784 l_periodic_payment number;
3785 l_periodic_principal number;
3786 l_periodic_interest number;
3787 l_interest_based_on_amount number; -- do we calculate interest from actual or predicted remaining balance
3788 l_pay_date date;
3789 l_total_principal number;
3790 l_payment_number number;
3791 l_fee_amount number;
3792 l_fee_amount1 number;
3793 l_other_amount number;
3794 l_begin_balance number;
3795 l_end_balance number;
3796 l_unbilled_principal number;
3797 l_unpaid_principal number;
3798 l_unpaid_interest number;
3799
3800 l_remaining_balance_actual number;
3801 l_remaining_balance_theory number;
3802 l_total number;
3803 l_interest_cumulative number;
3804 l_principal_cumulative number;
3805 l_fees_cumulative number;
3806 l_other_cumulative number;
3807 i number;
3808 l_installment_number number;
3809 l_billing boolean; -- switch to notify if billing is calling API
3810 l_api_name varchar2(20);
3811 l_last_installment_billed number;
3812 l_rate_to_calculate number;
3813 l_previous_annualized number;
3814 l_previous_interest_only_flag varchar2(1);
3815 l_interest_only_flag varchar2(1);
3816 l_calc_method varchar2(30);
3817 l_compound_freq varchar2(30);
3818 l_non_ro_intervals number;
3819 l_prev_periodic_principal number;
3820 l_intervals_diff number;
3821 l_remaining_balance_actual1 number;
3822 l_extend_from_installment number;
3823 l_orig_num_install number;
3824 l_first_installment_billed number;
3825 l_begin number;
3826 l_norm_interest number;
3827 l_add_prin_interest number;
3828 l_add_int_interest number;
3829 l_add_start_date date;
3830 l_add_end_date date;
3831 l_penal_prin_interest number;
3832 l_penal_int_interest number;
3833 l_penal_interest number;
3834 l_prev_grace_end_date date;
3835 l_raw_rate number;
3836 l_balloon_amount number;
3837 l_remaining_balance number;
3838 l_disb_header_id number;
3839 l_billed varchar2(1);
3840 n number;
3841 l_sum_periodic_principal number;
3842 l_date1 date;
3843 l_billed_principal number;
3844 l_detail_int_calc_flag boolean;
3845 l_increased_amount number;
3846 l_increased_amount1 number;
3847 l_begin_funded_amount number;
3848 l_end_funded_amount number;
3849 l_increase_amount_instal number;
3850 l_prev_increase_amount_instal number;
3851 l_begin_funded_amount_new number;
3852 l_fund_sched_count number;
3853 l_wtd_balance number;
3854 l_balance1 number;
3855 l_balance2 number;
3856 l_remaining_balance_theory1 number;
3857 l_prev_cap_int number;
3858 l_early_pay_cr number;
3859 l_bill_on_appr_amounts varchar2(1);
3860
3861 l_norm_int_detail_str varchar2(2000);
3862 l_add_prin_int_detail_str varchar2(2000);
3863 l_add_int_int_detail_str varchar2(2000);
3864 l_penal_prin_int_detail_str varchar2(2000);
3865 l_penal_int_int_detail_str varchar2(2000);
3866 l_penal_int_detail_str varchar2(2000);
3867 l_cap_int_detail_str varchar2(2000);
3868 l_early_pay_cr_detail_str varchar2(2000);
3869
3870 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
3871 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
3872 l_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
3873 l_FREQUENCY_REC LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
3874 l_prev_payment_frequency varchar2(30);
3875
3876 -- get last bill date
3877 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
3878 select ACTIVITY_DATE
3879 from LNS_PRIN_TRX_ACTIVITIES_V
3880 where loan_id = p_loan_id
3881 and PAYMENT_NUMBER = p_installment_number
3882 and PARENT_AMORTIZATION_ID is null
3883 and ACTIVITY_CODE in ('BILLING', 'START');
3884
3885 -- get last billed principal info
3886 cursor c_get_last_payment(p_loan_id number, p_installment_number number) is
3887 select PRINCIPAL_AMOUNT, FUNDED_AMOUNT, nvl(CAP_INT_AMOUNT, 0)
3888 from lns_amortization_scheds
3889 where loan_id = p_loan_id
3890 and PAYMENT_NUMBER > 0
3891 and PAYMENT_NUMBER <= p_installment_number
3892 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
3893 and PARENT_AMORTIZATION_ID is null
3894 and REAMORTIZE_TO_INSTALLMENT is null
3895 --and PRINCIPAL_AMOUNT > 0
3896 and nvl(PHASE, 'TERM') = 'TERM'
3897 order by PAYMENT_NUMBER desc;
3898
3899 cursor c_fund_sched_exist(p_loan_id number) is
3900 select decode(loan.loan_class_code,
3901 'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
3902 'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
3903 from lns_loan_headers_all loan
3904 where loan.loan_id = p_loan_id;
3905
3906 cursor c_get_bill_opt(p_loan_id number) is
3907 select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
3908 from lns_loan_headers_all
3909 where loan_id = p_loan_id;
3910
3911 begin
3912
3913 -- initialize all variables
3914 l_original_loan_amount := 0; -- loan amount
3915 l_loan_period_number := 0;
3916 l_previous_rate_id := -1;
3917 l_previous_annualized := -1;
3918 l_previous_interest_only_flag := 'N'; -- default to regular interest + principal
3919 l_periodic_payment := 0;
3920 l_periodic_principal := 0;
3921 l_periodic_interest := 0;
3922 l_balloon_amount := 0;
3923 l_total_principal := 0;
3924 l_payment_number := 0;
3925 l_fee_amount := 0;
3926 l_other_amount := 0;
3927 l_begin_balance := 0;
3928 l_unbilled_principal := 0;
3929 l_unpaid_principal := 0;
3930 l_remaining_balance_actual := 0;
3931 l_remaining_balance_theory := 0;
3932 l_total := 0;
3933 l_interest_cumulative := 0;
3934 l_principal_cumulative := 0;
3935 l_fees_cumulative := 0;
3936 l_other_cumulative := 0;
3937 i := 0;
3938 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
3939 l_rate_to_calculate := 0;
3940 l_billing := false; -- switch to notify if billing is calling API
3941 l_api_name := 'amortizeEPLoan MAIN';
3942
3943 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
3944 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
3945 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
3946
3947 l_loan_term := p_loan_details.loan_term;
3948 l_amortized_term := p_loan_details.amortized_term;
3949 l_amortized_term_period := p_loan_details.amortized_term_period;
3950 l_amortization_frequency := p_loan_details.amortization_frequency;
3951 l_payment_frequency := p_loan_details.payment_frequency;
3952 l_first_payment_date := p_loan_details.first_payment_date;
3953 l_original_loan_amount := p_loan_details.requested_amount; --funded_amount;
3954 l_remaining_balance_actual := p_loan_details.remaining_balance;
3955 l_remaining_balance_actual1 := p_loan_details.remaining_balance;
3956 l_maturity_date := p_loan_details.maturity_date;
3957 l_balloon_amount := p_loan_details.balloon_payment_amount;
3958 l_last_installment_billed := p_loan_details.last_installment_billed;
3959 l_day_count_method := p_loan_details.day_count_method;
3960 l_loan_start_date := p_loan_details.loan_start_date;
3961 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
3962 l_precision := p_loan_details.currency_precision;
3963 l_reamortize_from_installment := p_loan_details.reamortize_from_installment;
3964 l_reamortize_amount := p_loan_details.reamortize_amount;
3965 l_loan_id := p_loan_details.loan_id;
3966 l_calc_method := p_loan_details.CALCULATION_METHOD;
3967 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
3968 l_extend_from_installment := p_loan_details.EXTEND_FROM_INSTALLMENT;
3969 l_orig_num_install := p_loan_details.ORIG_NUMBER_INSTALLMENTS;
3970
3971 -- get the interest rate schedule
3972 l_rate_tbl := p_rate_schedule;
3973 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
3974
3975 -- get payment schedule
3976 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
3977
3978 l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
3979 P_LOAN_ID => l_loan_id,
3980 P_PHASE => 'TERM',
3981 P_COMPONENT => 'PRIN_INT');
3982
3983 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
3984 p_loan_start_date => l_loan_start_date,
3985 p_loan_maturity_date => l_maturity_date,
3986 p_freq_schedule_tbl => l_freq_schedule_tbl);
3987 /*
3988 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
3989 ,p_loan_maturity_date => l_maturity_date
3990 ,p_first_pay_date => l_first_payment_date
3991 ,p_num_intervals => null --l_intervals
3992 ,p_interval_type => l_payment_frequency
3993 ,p_pay_in_arrears => l_pay_in_arrears);
3994 */
3995 l_num_pay_dates := l_payment_tbl.count;
3996 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
3997
3998 if l_loan_term <> l_amortized_term then
3999
4000 -- get amortize maturity date
4001 l_amortized_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term => l_amortized_term
4002 ,p_term_period => l_amortized_term_period
4003 ,p_frequency => l_payment_frequency
4004 ,p_start_date => l_loan_start_date);
4005 -- get amortize payment schedule
4006 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting amortize payment schedule');
4007
4008 l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
4009 P_LOAN_ID => l_loan_id,
4010 P_PHASE => 'TERM',
4011 P_COMPONENT => 'PRIN_INT');
4012
4013 l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
4014 p_loan_start_date => l_loan_start_date,
4015 p_loan_maturity_date => l_amortized_maturity_date,
4016 p_freq_schedule_tbl => l_freq_schedule_tbl);
4017 /*
4018 l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
4019 ,p_loan_maturity_date => l_amortized_maturity_date
4020 ,p_first_pay_date => l_first_payment_date
4021 ,p_num_intervals => null --l_intervals
4022 ,p_interval_type => l_payment_frequency
4023 ,p_pay_in_arrears => l_pay_in_arrears);
4024 */
4025 l_amortization_intervals := l_amortized_payment_tbl.count;
4026 else
4027 l_amortization_intervals := l_num_pay_dates;
4028 end if;
4029 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- amortize payment schedule count: ' || l_amortization_intervals);
4030
4031 l_intervals_diff := l_amortization_intervals - l_num_pay_dates;
4032
4033 if p_based_on_terms <> 'CURRENT' then
4034 open c_fund_sched_exist(l_loan_id);
4035 fetch c_fund_sched_exist into l_fund_sched_count;
4036 close c_fund_sched_exist;
4037
4038 if l_fund_sched_count = 0 then
4039 l_original_loan_amount := p_loan_details.requested_amount;
4040 else
4041 l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
4042 end if;
4043 else
4044 l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
4045 end if;
4046
4047 l_fees_tbl.delete;
4048 l_fee_amount := 0;
4049
4050 -- filling out basis table
4051 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
4052 l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
4053 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
4054 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
4055 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
4056 l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
4057 l_fee_basis_tbl(4).fee_basis_name := 'TOTAL_UNDISB_AMT';
4058 l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
4059
4060 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
4061 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
4062 ,p_loan_id => l_loan_id
4063 ,p_installment => 0
4064 ,p_fee_basis_tbl => l_fee_basis_tbl
4065 ,p_based_on_terms => p_based_on_terms
4066 ,p_phase => 'TERM'
4067 ,x_fees_tbl => l_fees_tbl
4068 ,x_return_status => l_return_status
4069 ,x_msg_count => l_msg_count
4070 ,x_msg_data => l_msg_data);
4071
4072 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
4073 if l_return_status <> 'S' then
4074 RAISE FND_API.G_EXC_ERROR;
4075 end if;
4076
4077 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
4078
4079 for k in 1..l_fees_tbl.count loop
4080 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
4081 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
4082 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
4083 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
4084 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
4085 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
4086 end loop;
4087 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
4088
4089
4090 if l_fee_amount > 0 then
4091 i := i + 1;
4092 l_amortization_rec.installment_number := 0;
4093 l_amortization_rec.due_date := l_loan_start_date;
4094 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
4095 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
4096 l_amortization_rec.principal_amount := 0;
4097 l_amortization_rec.interest_amount := 0;
4098 l_amortization_rec.fee_amount := l_fee_amount;
4099 l_amortization_rec.other_amount := 0;
4100 l_amortization_rec.begin_balance := l_original_loan_amount;
4101 l_amortization_rec.end_balance := l_original_loan_amount;
4102 l_amortization_rec.interest_cumulative := 0;
4103 l_amortization_rec.principal_cumulative := 0;
4104 l_amortization_rec.fees_cumulative := l_fee_amount;
4105 l_amortization_rec.other_cumulative := 0;
4106 l_amortization_rec.rate_id := 0;
4107 l_amortization_rec.SOURCE := 'PREDICTED';
4108 l_amortization_rec.total := l_fee_amount;
4109 l_amortization_rec.UNPAID_PRIN := 0;
4110 l_amortization_rec.UNPAID_INT := 0;
4111 l_amortization_rec.INTEREST_RATE := l_rate_tbl(1).annual_rate;
4112 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
4113 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
4114 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
4115 l_amortization_rec.PENAL_INT_AMOUNT := 0;
4116 l_amortization_rec.FUNDED_AMOUNT := l_original_loan_amount;
4117 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
4118 l_amortization_rec.DISBURSEMENT_AMOUNT := l_original_loan_amount;
4119 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
4120 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
4121 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
4122 l_amortization_rec.CAP_INT_AMOUNT := 0;
4123 l_amortization_rec.CAP_INT_DETAILS := null;
4124 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
4125
4126 -- add the record to the amortization table
4127 l_amortization_tbl(i) := l_amortization_rec;
4128 end if;
4129
4130 -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
4131 if p_installment_number is not null then
4132
4133 l_billing := true;
4134 if p_installment_number > 0 then
4135
4136 if p_installment_number > l_num_pay_dates then
4137 l_payment_number := l_num_pay_dates;
4138 else
4139 l_payment_number := p_installment_number;
4140 end if;
4141
4142 else
4143 l_payment_number := p_installment_number;
4144 end if;
4145
4146 else
4147
4148 l_payment_number := l_num_pay_dates;
4149
4150 end if;
4151
4152 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
4153 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
4154
4155 l_begin := 1;
4156
4157 if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
4158
4159 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4160 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_last_installment_billed || '-----');
4161 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4162
4163 l_periodic_principal := null;
4164 open c_get_last_payment(l_loan_id, l_last_installment_billed);
4165 fetch c_get_last_payment into l_periodic_principal, l_begin_funded_amount, l_prev_cap_int;
4166 close c_get_last_payment;
4167
4168 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic principal = ' || l_periodic_principal);
4169 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
4170 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
4171
4172 if l_periodic_principal is not null then
4173
4174 l_prev_periodic_principal := l_periodic_principal;
4175 l_begin := l_last_installment_billed + 1;
4176
4177 if l_rate_tbl.count = 1 then
4178 l_previous_annualized := l_rate_tbl(1).annual_rate;
4179 l_previous_interest_only_flag := l_rate_tbl(1).interest_only_flag;
4180 else
4181 l_rate_details := lns_financials.getRateDetails(p_installment => l_last_installment_billed
4182 ,p_rate_tbl => l_rate_tbl);
4183 l_previous_annualized := l_rate_details.annual_rate;
4184 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
4185 end if;
4186
4187 end if;
4188
4189 else
4190 l_remaining_balance_theory := l_original_loan_amount;
4191 l_begin_funded_amount := 0; --l_original_loan_amount;
4192 l_end_funded_amount := l_original_loan_amount;
4193 l_prev_cap_int := 0;
4194
4195 open c_get_bill_opt(l_loan_id);
4196 fetch c_get_bill_opt into l_bill_on_appr_amounts;
4197 close c_get_bill_opt;
4198 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
4199 end if;
4200
4201 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin = ' || l_begin);
4202 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.REAMORTIZE_ON_FUNDING = ' || p_loan_details.REAMORTIZE_ON_FUNDING);
4203 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
4204
4205 l_increase_amount_instal := -1;
4206
4207 if l_begin = 1 then
4208 l_prev_payment_frequency := '';
4209 else
4210 LNS_FIN_UTILS.fetchPayFreqRecByDate(
4211 p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
4212 p_DATE => l_payment_tbl(l_begin-1).PERIOD_DUE_DATE,
4213 x_FREQUENCY_REC => l_FREQUENCY_REC);
4214 l_prev_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
4215 end if;
4216
4217 -- loop to build the amortization schedule
4218 for l_installment_number in l_begin..l_payment_number
4219 loop
4220
4221 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4222 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || '-----');
4223 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4224
4225 i := i + 1;
4226 l_periodic_interest := 0;
4227 -- l_periodic_principal := 0;
4228 l_fee_amount := 0;
4229 l_other_amount := 0;
4230 l_unpaid_principal := 0;
4231 l_unpaid_interest := 0;
4232 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
4233 l_detail_int_calc_flag := false;
4234 l_increased_amount := 0;
4235 l_increased_amount1 := 0;
4236 l_prev_increase_amount_instal := l_increase_amount_instal;
4237
4238 if l_fund_sched_count > 0 or p_based_on_terms = 'CURRENT' then
4239
4240 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number) then
4241
4242 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 = l_installment_number');
4243
4244 l_principal_cumulative := 0;
4245 l_interest_cumulative := 0;
4246 l_fees_cumulative := 0;
4247 l_other_cumulative := 0;
4248 l_sum_periodic_principal := 0;
4249 l_billed_principal := p_loan_details.billed_principal;
4250 l_unbilled_principal := p_loan_details.unbilled_principal;
4251 l_unpaid_principal := p_loan_details.unpaid_principal;
4252 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
4253
4254 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
4255 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
4256 l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
4257 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
4258
4259 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
4260 l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
4261 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
4262
4263 if l_end_funded_amount > l_begin_funded_amount_new then
4264 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
4265
4266 if l_end_funded_amount = l_begin_funded_amount_new then
4267 l_increase_amount_instal := l_installment_number;
4268 else
4269 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
4270 l_increase_amount_instal := l_installment_number + 1;
4271 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
4272 l_increase_amount_instal := l_installment_number;
4273 end if;
4274 end if;
4275
4276 elsif l_begin_funded_amount_new > l_begin_funded_amount then
4277 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new > l_begin_funded_amount');
4278 l_increase_amount_instal := l_installment_number;
4279 end if;
4280
4281 l_detail_int_calc_flag := true;
4282
4283 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
4284 l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
4285 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
4286
4287 l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
4288 l_begin_funded_amount := l_begin_funded_amount_new;
4289 l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
4290 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
4291 l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal;
4292 else
4293 l_remaining_balance_theory := 0;
4294 end if;
4295
4296 else
4297
4298 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 < l_installment_number');
4299 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
4300 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
4301 l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
4302 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
4303
4304 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
4305 l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
4306 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
4307
4308 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
4309 l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
4310 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
4311
4312 if l_end_funded_amount > l_begin_funded_amount then
4313 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
4314 l_detail_int_calc_flag := true;
4315
4316 if l_end_funded_amount = l_begin_funded_amount_new then
4317 l_increase_amount_instal := l_installment_number;
4318 else
4319 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
4320 l_increase_amount_instal := l_installment_number + 1;
4321 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
4322 l_increase_amount_instal := l_installment_number;
4323 end if;
4324 end if;
4325
4326 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
4327 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
4328
4329 l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
4330 l_begin_funded_amount := l_begin_funded_amount_new;
4331 l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
4332 l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal - l_sum_periodic_principal;
4333 end if;
4334 else
4335 l_remaining_balance_theory := 0;
4336 end if;
4337
4338 end if;
4339
4340 elsif l_installment_number = 1 and l_fund_sched_count = 0 and p_based_on_terms <> 'CURRENT' then
4341 l_increased_amount := l_original_loan_amount;
4342 end if;
4343
4344 if p_loan_details.REAMORTIZE_ON_FUNDING = 'NO' then
4345 l_increase_amount_instal := -1;
4346 end if;
4347
4348 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
4349
4350 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
4351 l_rate_details := getRateDetails(p_installment => l_installment_number
4352 ,p_rate_tbl => l_rate_tbl);
4353
4354 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
4355 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
4356 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
4357
4358 l_current_rate_id := l_rate_details.rate_id;
4359 l_annualized_rate := l_rate_details.annual_rate;
4360 l_interest_only_flag := l_rate_details.interest_only_flag;
4361
4362 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_rate_id = ' || l_previous_rate_id);
4363 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id = ' || l_current_rate_id);
4364 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized = ' || l_previous_annualized);
4365 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate = ' || l_annualized_rate);
4366 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_interest_only_flag = ' || l_previous_interest_only_flag);
4367 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag = ' || l_interest_only_flag);
4368 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
4369 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment = ' || l_extend_from_installment);
4370 if l_detail_int_calc_flag then
4371 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = true');
4372 else
4373 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = false');
4374 end if;
4375 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount = ' || l_increased_amount);
4376 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount1 = ' || l_increased_amount1);
4377 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increase_amount_instal = ' || l_increase_amount_instal);
4378
4379 -- getting current frequency record
4380 LNS_FIN_UTILS.fetchPayFreqRecByDate(
4381 p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
4382 p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
4383 x_FREQUENCY_REC => l_FREQUENCY_REC);
4384 l_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
4385
4386 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_payment_frequency = ' || l_prev_payment_frequency);
4387 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_frequency = ' || l_payment_frequency);
4388
4389 -- conditions to recalculate principal payment
4390 -- 1. 1-st installment
4391 -- 2. reamortization from installment = current installment
4392 -- 3. reamortize because loan term has been extended
4393 -- 4. emerging from interest only period
4394 -- 5. funded amount has increased since last installment
4395
4396 if ((l_installment_number = 1) OR
4397 (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
4398 (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
4399 (l_previous_interest_only_flag = 'Y' and l_interest_only_flag = 'N' and l_prev_periodic_principal = 0) OR
4400 (l_prev_increase_amount_instal = l_installment_number or l_increase_amount_instal = l_installment_number) OR
4401 (l_payment_frequency <> l_prev_payment_frequency))
4402 then
4403
4404 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- RE-calculating periodic principal payment');
4405
4406 -- fix for bug 6599682: EQUALLY SPREAD PRINCIPAL FROM IO PERIODS FOR EPRP LOANS
4407 l_non_ro_intervals := get_num_non_ro_instal(l_rate_tbl, l_installment_number, l_orig_num_install) + l_intervals_diff;
4408
4409 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_non_ro_intervals = ' || l_non_ro_intervals);
4410 l_remaining_balance := l_remaining_balance_theory + l_increased_amount1;
4411
4412 l_periodic_principal := lns_financials.calculateEPPayment(p_loan_amount => l_remaining_balance
4413 ,p_num_intervals => l_non_ro_intervals
4414 --,p_num_intervals => l_amortization_intervals
4415 ,p_ending_balance=> l_balloon_amount
4416 ,p_pay_in_arrears=> l_pay_in_arrears);
4417 l_prev_periodic_principal := l_periodic_principal;
4418
4419 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic principal = ' || l_periodic_principal);
4420
4421 else
4422 l_periodic_principal := l_prev_periodic_principal;
4423 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD periodic principal = ' || l_periodic_principal);
4424 end if;
4425
4426 l_norm_interest := 0;
4427 l_add_prin_interest := 0;
4428 l_add_int_interest := 0;
4429 l_penal_prin_interest := 0;
4430 l_penal_int_interest := 0;
4431 l_penal_interest := 0;
4432 l_early_pay_cr := 0;
4433 l_norm_int_detail_str := null;
4434 l_add_prin_int_detail_str := null;
4435 l_add_int_int_detail_str := null;
4436 l_penal_prin_int_detail_str := null;
4437 l_penal_int_int_detail_str := null;
4438 l_penal_int_detail_str := null;
4439 l_early_pay_cr_detail_str := null;
4440
4441 -- now we will caculate the interest due for this period
4442 if (p_based_on_terms = 'CURRENT' and l_detail_int_calc_flag = true) then
4443
4444 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
4445 LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
4446 p_calc_method => l_calc_method,
4447 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4448 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
4449 p_interest_rate => l_annualized_rate,
4450 p_day_count_method => l_day_count_method,
4451 p_payment_freq => l_payment_frequency,
4452 p_compound_freq => l_compound_freq,
4453 p_adj_amount => l_sum_periodic_principal,
4454 p_CAP_AMOUNT => l_prev_cap_int,
4455 x_norm_interest => l_norm_interest,
4456 x_norm_int_details => l_norm_int_detail_str);
4457
4458 l_norm_interest := round(l_norm_interest, l_precision);
4459
4460 if (l_installment_number-1) >= 0 and l_last_installment_billed + 1 = l_installment_number then
4461
4462 -- get additional interest start date
4463 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
4464 fetch c_get_last_bill_date into l_add_start_date;
4465 close c_get_last_bill_date;
4466
4467 -- get additional interest end date
4468 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
4469 l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
4470 else
4471 l_add_end_date := sysdate;
4472 end if;
4473
4474 if (l_installment_number-1) > 0 then
4475 l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
4476 else
4477 l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
4478 end if;
4479
4480 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
4481 -- calculate additional interest on unpaid principal
4482 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
4483 p_calc_method => l_calc_method,
4484 p_period_start_date => l_add_start_date,
4485 p_period_end_date => l_add_end_date,
4486 p_interest_rate => l_annualized_rate,
4487 p_day_count_method => l_day_count_method,
4488 p_payment_freq => l_payment_frequency,
4489 p_compound_freq => l_compound_freq,
4490 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
4491 p_prev_grace_end_date => l_prev_grace_end_date,
4492 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4493 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
4494 p_target => 'UNPAID_PRIN',
4495 x_add_interest => l_add_prin_interest,
4496 x_penal_interest => l_penal_prin_interest,
4497 x_add_int_details => l_add_prin_int_detail_str,
4498 x_penal_int_details => l_penal_prin_int_detail_str);
4499 l_add_prin_interest := round(l_add_prin_interest, l_precision);
4500
4501 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
4502 -- calculate additional interest on unpaid interest
4503 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
4504 p_calc_method => l_calc_method,
4505 p_period_start_date => l_add_start_date,
4506 p_period_end_date => l_add_end_date,
4507 p_interest_rate => l_annualized_rate,
4508 p_day_count_method => l_day_count_method,
4509 p_payment_freq => l_payment_frequency,
4510 p_compound_freq => l_compound_freq,
4511 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
4512 p_prev_grace_end_date => l_prev_grace_end_date,
4513 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4514 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
4515 p_target => 'UNPAID_INT',
4516 x_add_interest => l_add_int_interest,
4517 x_penal_interest => l_penal_int_interest,
4518 x_add_int_details => l_add_int_int_detail_str,
4519 x_penal_int_details => l_penal_int_int_detail_str);
4520 l_add_int_interest := round(l_add_int_interest, l_precision);
4521
4522 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
4523 l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
4524 else
4525 l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
4526 end if;
4527
4528 -- calculate interest credit on early payment
4529 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
4530 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => l_loan_id,
4531 p_calc_method => l_calc_method,
4532 p_installment => l_installment_number,
4533 p_interest_rate => l_previous_annualized,
4534 p_day_count_method => l_day_count_method,
4535 p_payment_freq => l_payment_frequency,
4536 p_compound_freq => l_compound_freq,
4537 x_early_pay_cr => l_early_pay_cr,
4538 x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
4539
4540 end if;
4541
4542 elsif (p_based_on_terms <> 'CURRENT' and l_detail_int_calc_flag = true and l_bill_on_appr_amounts = 'N') then
4543
4544 if (l_calc_method = 'SIMPLE') then
4545
4546 l_periodic_rate := lns_financials.getPeriodicRate(
4547 p_payment_freq => l_payment_frequency
4548 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4549 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4550 ,p_annualized_rate => l_annualized_rate
4551 ,p_days_count_method => l_day_count_method
4552 ,p_target => 'INTEREST');
4553
4554 elsif (l_calc_method = 'COMPOUND') then
4555
4556 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
4557 ,p_payment_freq => l_payment_frequency
4558 ,p_annualized_rate => l_annualized_rate
4559 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4560 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4561 ,p_days_count_method => l_day_count_method
4562 ,p_target => 'INTEREST');
4563
4564 end if;
4565
4566 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
4567 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
4568 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
4569 ,p_calc_method => 'TARGET'
4570 ,p_phase => 'TERM'
4571 ,p_day_count_method => l_day_count_method
4572 ,p_adj_amount => l_sum_periodic_principal
4573 ,x_wtd_balance => l_wtd_balance
4574 ,x_begin_balance => l_balance1
4575 ,x_end_balance => l_balance2);
4576
4577 l_wtd_balance := l_wtd_balance + l_prev_cap_int;
4578 l_norm_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
4579 ,p_periodic_rate => l_periodic_rate
4580 ,p_compounding_period => null);
4581 l_norm_interest := round(l_norm_interest, l_precision);
4582
4583 l_norm_int_detail_str := l_norm_interest || ' (' ||
4584 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
4585 ' * Balance ' || l_wtd_balance ||
4586 ' * Rate ' || l_annualized_rate || '%)';
4587 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
4588
4589 else
4590
4591 l_remaining_balance_theory1 := l_remaining_balance_theory + l_prev_cap_int;
4592 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_theory1);
4593
4594 if (l_calc_method = 'SIMPLE') then
4595
4596 l_periodic_rate := lns_financials.getPeriodicRate(
4597 p_payment_freq => l_payment_frequency
4598 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4599 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4600 ,p_annualized_rate => l_annualized_rate
4601 ,p_days_count_method => l_day_count_method
4602 ,p_target => 'INTEREST');
4603
4604 elsif (l_calc_method = 'COMPOUND') then
4605
4606 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
4607 ,p_payment_freq => l_payment_frequency
4608 ,p_annualized_rate => l_annualized_rate
4609 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4610 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4611 ,p_days_count_method => l_day_count_method
4612 ,p_target => 'INTEREST');
4613
4614 end if;
4615
4616 l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_theory1
4617 ,p_periodic_rate => l_periodic_rate
4618 ,p_compounding_period => null);
4619 l_norm_interest := round(l_norm_interest, l_precision);
4620
4621 l_norm_int_detail_str := l_norm_interest || ' (' ||
4622 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
4623 ' * Balance ' || l_remaining_balance_theory1 ||
4624 ' * Rate ' || l_annualized_rate || '%)';
4625 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
4626
4627 end if;
4628
4629 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
4630 l_periodic_interest := round(l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest - l_early_pay_cr, l_precision);
4631
4632 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal = ' || l_periodic_principal);
4633 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
4634 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
4635 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_intervals_remaining = ' || l_intervals_remaining);
4636 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled_principal = ' || l_unbilled_principal);
4637
4638 if l_interest_only_flag <> 'Y' or l_intervals_remaining = 1 then
4639
4640 if (l_remaining_balance_theory + l_increased_amount1) < l_periodic_principal or l_intervals_remaining = 1 then
4641 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
4642 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
4643 end if;
4644
4645 else
4646 -- we are in an interest only period
4647 l_periodic_principal := 0;
4648
4649 end if;
4650
4651 l_periodic_principal := round(l_periodic_principal, l_precision);
4652 l_periodic_payment := l_periodic_principal + l_periodic_interest;
4653
4654 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
4655 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_payment = ' || l_periodic_payment);
4656
4657 -- calculate balances
4658 l_begin_balance := l_remaining_balance_theory;
4659 l_end_balance := l_remaining_balance_theory - l_periodic_principal + l_increased_amount1;
4660
4661 -- check to see if this loan has been billed
4662 if l_unbilled_principal > 0 then
4663 l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
4664 end if;
4665
4666 -- build the amortization record
4667 l_amortization_rec.installment_number := l_installment_number; /* needed to calculate fees */
4668 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
4669 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
4670 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
4671 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
4672 l_amortization_rec.interest_amount := l_periodic_interest;
4673 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
4674 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
4675 l_amortization_rec.INTEREST_RATE := l_annualized_rate;
4676 l_amortization_rec.NORMAL_INT_AMOUNT := l_norm_interest;
4677 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_add_prin_interest;
4678 l_amortization_rec.ADD_INT_INT_AMOUNT := l_add_int_interest;
4679 l_amortization_rec.PENAL_INT_AMOUNT := l_penal_interest;
4680 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
4681 l_amortization_rec.DISBURSEMENT_AMOUNT := l_increased_amount;
4682 l_amortization_rec.FUNDED_AMOUNT := l_end_funded_amount;
4683 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
4684 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
4685 l_amortization_rec.EARLY_PAY_CR_AMOUNT := -l_early_pay_cr;
4686
4687 if l_amortization_rec.FUNDED_AMOUNT is null then
4688 l_amortization_rec.FUNDED_AMOUNT := 0;
4689 end if;
4690
4691 l_cap_int_detail_str := null;
4692 l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
4693 if p_loan_details.CAPITALIZE_INT = 'Y' then
4694 l_amortization_rec.begin_balance := l_begin_balance + l_prev_cap_int;
4695 if l_end_balance = 0 and l_amortization_rec.interest_amount > 0 then
4696 l_amortization_rec.end_balance := l_end_balance;
4697 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_prev_cap_int;
4698 l_amortization_rec.CAP_INT_AMOUNT := 0;
4699 l_prev_cap_int := 0;
4700 l_amortization_rec.interest_amount := l_amortization_rec.interest_amount + l_amortization_rec.PREV_CAP_INT_AMOUNT;
4701 else
4702 l_amortization_rec.end_balance := l_end_balance + l_prev_cap_int;
4703 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
4704 l_amortization_rec.CAP_INT_AMOUNT := l_prev_cap_int + l_amortization_rec.interest_amount;
4705 if l_amortization_rec.CAP_INT_AMOUNT > 0 then
4706 if l_prev_cap_int <> 0 then
4707 l_cap_int_detail_str := 'Previously Capitalized Interest ' || l_prev_cap_int;
4708 end if;
4709 if l_norm_interest <> 0 then
4710 if l_cap_int_detail_str is not null then
4711 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4712 end if;
4713 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Normal Interest ' || l_norm_int_detail_str;
4714 end if;
4715 if l_add_prin_interest <> 0 then
4716 if l_cap_int_detail_str is not null then
4717 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4718 end if;
4719 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Prin ' || l_add_prin_int_detail_str;
4720 end if;
4721 if l_add_int_interest <> 0 then
4722 if l_cap_int_detail_str is not null then
4723 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4724 end if;
4725 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Interest ' || l_add_int_int_detail_str;
4726 end if;
4727 if l_penal_interest <> 0 then
4728 if l_cap_int_detail_str is not null then
4729 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4730 end if;
4731 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Penal Interest ' || l_penal_interest || ' (' || l_penal_int_detail_str || ')';
4732 end if;
4733 if l_early_pay_cr <> 0 then
4734 if l_cap_int_detail_str is not null then
4735 l_cap_int_detail_str := l_cap_int_detail_str || ' -<br>';
4736 end if;
4737 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Int Cr on Early Payment ' || l_early_pay_cr || ' (' || l_early_pay_cr_detail_str || ')';
4738 end if;
4739 end if;
4740 l_prev_cap_int := l_amortization_rec.CAP_INT_AMOUNT;
4741 if l_amortization_rec.NORMAL_INT_AMOUNT > 0 then
4742 l_norm_int_detail_str := 'Interest amount is capitalized';
4743 end if;
4744
4745 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_amortization_rec.interest_amount;
4746 l_amortization_rec.interest_amount := 0;
4747 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
4748 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
4749 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
4750 l_amortization_rec.PENAL_INT_AMOUNT := 0;
4751 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
4752
4753 l_add_prin_int_detail_str := null;
4754 l_add_int_int_detail_str := null;
4755 l_penal_prin_int_detail_str := null;
4756 l_penal_int_int_detail_str := null;
4757 l_penal_int_detail_str := null;
4758 l_early_pay_cr_detail_str := null;
4759 end if;
4760 else
4761 l_amortization_rec.begin_balance := l_begin_balance;
4762 l_amortization_rec.end_balance := l_end_balance;
4763 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
4764 l_amortization_rec.CAP_INT_AMOUNT := 0;
4765 l_prev_cap_int := 0;
4766 end if;
4767 l_amortization_rec.total := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
4768
4769 l_fees_tbl.delete;
4770 l_fee_amount := 0;
4771 l_other_amount := 0;
4772
4773 -- filling out basis table
4774 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
4775 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
4776 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
4777 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
4778 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
4779 l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
4780 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN';
4781 l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
4782 l_fee_basis_tbl(5).fee_basis_name := 'OVERDUE_PRIN_INT';
4783 l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
4784 l_fee_basis_tbl(6).fee_basis_name := 'IND_DISB_AMT';
4785 l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
4786 l_fee_basis_tbl(7).fee_basis_name := 'TOTAL_UNDISB_AMT';
4787 l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
4788 l_fee_basis_tbl(8).fee_basis_name := 'OVERDUE_INT';
4789 l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
4790 l_fee_basis_tbl(9).fee_basis_name := 'CURR_LOAN';
4791 l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
4792
4793 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
4794 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
4795 ,p_loan_id => l_loan_id
4796 ,p_installment => l_installment_number
4797 ,p_fee_basis_tbl => l_fee_basis_tbl
4798 ,p_based_on_terms => p_based_on_terms
4799 ,p_phase => 'TERM'
4800 ,x_fees_tbl => l_fees_tbl
4801 ,x_return_status => l_return_status
4802 ,x_msg_count => l_msg_count
4803 ,x_msg_data => l_msg_data);
4804
4805 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
4806 if l_return_status <> 'S' then
4807 RAISE FND_API.G_EXC_ERROR;
4808 end if;
4809
4810 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
4811
4812 for k in 1..l_fees_tbl.count loop
4813 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
4814 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
4815 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
4816 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
4817 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
4818 if l_fees_tbl(k).FEE_CATEGORY = 'MEMO' then
4819 l_other_amount := l_other_amount + l_fees_tbl(k).FEE_AMOUNT;
4820 else
4821 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
4822 end if;
4823 end loop;
4824
4825 l_amortization_rec.fee_amount := l_fee_amount;
4826 l_amortization_rec.other_amount := l_other_amount;
4827 l_amortization_rec.total := l_amortization_rec.total + l_amortization_rec.fee_amount + l_amortization_rec.other_amount;
4828
4829 -- running totals calculated here
4830 l_principal_cumulative := l_principal_cumulative + l_amortization_rec.principal_amount;
4831 l_interest_cumulative := l_interest_cumulative + l_amortization_rec.interest_amount;
4832 l_fees_cumulative := l_fees_cumulative + l_amortization_rec.fee_amount;
4833 l_other_cumulative := l_other_cumulative + l_amortization_rec.other_amount;
4834
4835 l_amortization_rec.interest_cumulative := l_interest_cumulative;
4836 l_amortization_rec.principal_cumulative := l_principal_cumulative;
4837 l_amortization_rec.fees_cumulative := l_fees_cumulative;
4838 l_amortization_rec.other_cumulative := l_other_cumulative;
4839 l_amortization_rec.rate_id := l_current_rate_id;
4840 l_amortization_rec.SOURCE := 'PREDICTED';
4841
4842 l_amortization_rec.NORMAL_INT_DETAILS := l_norm_int_detail_str;
4843 l_amortization_rec.ADD_PRIN_INT_DETAILS := l_add_prin_int_detail_str;
4844 l_amortization_rec.ADD_INT_INT_DETAILS := l_add_int_int_detail_str;
4845 l_amortization_rec.PENAL_INT_DETAILS := l_penal_int_detail_str;
4846 l_amortization_rec.CAP_INT_DETAILS := l_cap_int_detail_str;
4847 l_amortization_rec.EARLY_PAY_CR_DETAILS := l_early_pay_cr_detail_str;
4848
4849 -- add the record to the amortization table
4850 l_amortization_tbl(i) := l_amortization_rec;
4851
4852 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
4853 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INSTALLMENT ' || l_installment_number);
4854 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4855 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD = ' || l_amortization_rec.PERIOD);
4856 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_START_DATE = ' || l_amortization_rec.PERIOD_START_DATE);
4857 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_END_DATE = ' || l_amortization_rec.PERIOD_END_DATE);
4858 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'due date = ' || l_amortization_rec.due_date);
4859 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_principal = ' || l_amortization_rec.principal_amount);
4860 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_interest = ' || l_amortization_rec.interest_amount);
4861 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fee_amount = ' || l_amortization_rec.fee_amount);
4862 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_amount = ' || l_amortization_rec.other_amount);
4863 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'total = ' || l_amortization_rec.total);
4864 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'begin_balance = ' || l_amortization_rec.begin_balance);
4865 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'end_balance = ' || l_amortization_rec.end_balance);
4866 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'interest_cumulative = ' || l_amortization_rec.interest_cumulative);
4867 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'principal_cumulative = ' || l_amortization_rec.principal_cumulative);
4868 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fees_cumulative = ' || l_amortization_rec.fees_cumulative);
4869 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_cumulative = ' || l_amortization_rec.other_cumulative);
4870 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'current_rate_id = ' || l_amortization_rec.rate_id );
4871 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_RATE = ' || l_amortization_rec.INTEREST_RATE );
4872 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_PRIN = ' || l_amortization_rec.UNPAID_PRIN );
4873 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_INT = ' || l_amortization_rec.UNPAID_INT );
4874 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
4875 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_AMOUNT = ' || l_amortization_rec.ADD_PRIN_INT_AMOUNT );
4876 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_AMOUNT );
4877 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_AMOUNT = ' || l_amortization_rec.PENAL_INT_AMOUNT );
4878 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FUNDED_AMOUNT = ' || l_amortization_rec.FUNDED_AMOUNT );
4879 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amortization_rec.NORMAL_INT_DETAILS );
4880 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_DETAILS = ' || l_amortization_rec.ADD_PRIN_INT_DETAILS );
4881 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_DETAILS_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_DETAILS );
4882 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_DETAILS = ' || l_amortization_rec.PENAL_INT_DETAILS );
4883 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amortization_rec.PREV_CAP_INT_AMOUNT );
4884 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amortization_rec.CURR_CAP_INT_AMOUNT );
4885 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amortization_rec.CAP_INT_AMOUNT );
4886 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amortization_rec.CAP_INT_DETAILS );
4887 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_AMOUNT = ' || l_amortization_rec.EARLY_PAY_CR_AMOUNT );
4888 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_DETAILS = ' || l_amortization_rec.EARLY_PAY_CR_DETAILS );
4889 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
4890
4891 l_remaining_balance_theory := l_end_balance;
4892 l_sum_periodic_principal := l_sum_periodic_principal + l_periodic_principal;
4893
4894 l_previous_interest_only_flag := l_interest_only_flag;
4895 l_previous_rate_id := l_current_rate_id;
4896 l_previous_annualized := l_annualized_rate;
4897 l_prev_payment_frequency := l_payment_frequency;
4898
4899 end loop;
4900
4901 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT = ' || l_amortization_tbl.count);
4902 x_loan_amort_tbl := l_amortization_tbl;
4903
4904 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
4905
4906 Exception
4907 WHEN FND_API.G_EXC_ERROR THEN
4908 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
4909
4910 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
4911 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
4912
4913 WHEN OTHERS THEN
4914 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
4915
4916 end amortizeEPLoan;
4917
4918
4919
4920
4921 /*=========================================================================
4922 || PUBLIC PROCEDURE amortizeLoan
4923 ||
4924 || DESCRIPTION
4925 ||
4926 || Overview: procedure will run an amortization
4927 || this is the main calculation API for amortization
4928 || THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
4929 || 1. Amortization UI - when creating a loan
4930 || 2. Billing Engine - to generate installment bills
4931 ||
4932 || Parameter: p_loan_details = details of the loan
4933 || p_rate_schedule = rate schedule for the loan
4934 || p_installment_number => billing will pass in an installment
4935 || number to generate a billt
4936 || x_loan_amort_tbl => table of amortization records
4937 ||
4938 || Source Tables: NA
4939 ||
4940 || Target Tables:
4941 ||
4942 ||
4943 || KNOWN ISSUES
4944 ||
4945 || NOTES
4946 ||
4947 || MODIFICATION HISTORY
4948 || Date Author Description of Changes
4949 || 12/12/2003 11:35AM raverma Created
4950 || 2/26/2004 raverma coded in multiple rates
4951 || 10/28/2004 raverma added interest only flag
4952 || 06/20/2008 scherkas Synch amortizeLoan procedure with LNS_FINANCIALS 115.112 version
4953 *=======================================================================*/
4954 procedure amortizeLoan(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
4955 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
4956 ,p_based_on_terms in varchar2
4957 ,p_installment_number in number
4958 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
4959 is
4960 l_return_status varchar2(1);
4961 l_msg_count NUMBER;
4962 l_msg_data VARCHAR2(32767);
4963 l_loan_id number;
4964 l_original_loan_amount number; -- loan amount
4965 l_balloon_amount number;
4966 l_amortized_amount number; -- amount of loan less balloon amount
4967 l_loan_term number;
4968 l_amortized_term number;
4969 l_amortized_term_period varchar2(30);
4970 l_amortization_frequency varchar2(30);
4971 l_first_payment_date date;
4972 l_pay_in_arrears boolean;
4973 l_payment_frequency varchar2(30);
4974 l_day_count_method varchar2(30);
4975 l_interest_comp_freq varchar2(30);
4976 l_reamortize_from_installment number;
4977 l_reamortize_amount number;
4978 l_annualized_rate number; -- annual rate on the loan
4979 l_raw_rate number; --
4980 l_intervals_remaining number;
4981 l_amortization_intervals_orig number;
4982 l_amortization_intervals number; -- number of intervals to amortize over
4983 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
4984 l_current_rate_id number;
4985 l_previous_rate_id number;
4986 l_precision number;
4987 l_rate_type varchar2(30);
4988 l_open_rate_change_frequency varchar2(30);
4989 l_open_index_rate_id number;
4990 l_open_ceiling_rate number;
4991 l_open_floor_rate number;
4992 l_term_rate_change_frequency varchar2(30);
4993 l_term_index_rate_id number;
4994 l_term_ceiling_rate number;
4995 l_term_floor_rate number;
4996
4997 l_period_start_Date date;
4998 l_period_end_date date;
4999 l_periodic_rate number;
5000 l_maturity_date date;
5001 l_amortized_maturity_date date;
5002
5003 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
5004 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
5005 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
5006 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
5007 l_amortized_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
5008 l_loan_start_date date;
5009 l_num_pay_dates number; -- number of dates on installment schedule
5010 l_periodic_payment number;
5011 l_periodic_principal number;
5012 l_periodic_interest number;
5013 l_total_principal number;
5014 l_payment_number number;
5015 l_fee_amount number;
5016 l_fee_amount1 number;
5017 l_other_amount number;
5018 l_begin_balance number;
5019 l_end_balance number;
5020 l_unbilled_principal number;
5021 l_unpaid_principal number;
5022 l_unpaid_interest number;
5023
5024 l_remaining_balance_actual number;
5025 l_remaining_balance_theory number;
5026 l_total number;
5027 l_interest_cumulative number;
5028 l_principal_cumulative number;
5029 l_fees_cumulative number;
5030 l_other_cumulative number;
5031 i number;
5032 l_installment_number number;
5033 l_billing boolean; -- switch to notify if billing is calling API
5034 l_api_name varchar2(20);
5035 l_last_installment_billed number;
5036 l_rate_to_calculate number;
5037 l_previous_annualized number;
5038 l_previous_interest_only_flag varchar2(1);
5039 l_interest_only_flag varchar2(1);
5040 l_calc_method varchar2(30);
5041 l_compound_freq varchar2(30);
5042 l_remaining_balance_actual1 number;
5043 l_ending_balance number;
5044 l_due_date date;
5045 l_begin number;
5046 l_installment_number1 number;
5047 l_norm_interest number;
5048 l_add_prin_interest number;
5049 l_add_int_interest number;
5050 l_add_start_date date;
5051 l_add_end_date date;
5052 l_penal_prin_interest number;
5053 l_penal_int_interest number;
5054 l_penal_interest number;
5055 l_first_installment_billed number;
5056 l_extend_from_installment number;
5057 l_remaining_balance number;
5058 l_prev_grace_end_date date;
5059 l_disb_header_id number;
5060 l_billed varchar2(1);
5061 n number;
5062 l_sum_periodic_principal number;
5063 l_date1 date;
5064 l_billed_principal number;
5065 l_detail_int_calc_flag boolean;
5066 l_increased_amount number;
5067 l_increased_amount1 number;
5068 l_begin_funded_amount number;
5069 l_end_funded_amount number;
5070 l_increase_amount_instal number;
5071 l_prev_increase_amount_instal number;
5072 l_begin_funded_amount_new number;
5073 l_fund_sched_count number;
5074 l_wtd_balance number;
5075 l_balance1 number;
5076 l_balance2 number;
5077 l_remaining_balance_theory1 number;
5078 l_prev_cap_int number;
5079 l_early_pay_cr number;
5080 l_add_int_amount number;
5081 l_amortization_schedule_id number;
5082 l_bill_on_appr_amounts varchar2(1);
5083
5084 l_norm_int_detail_str varchar2(2000);
5085 l_add_prin_int_detail_str varchar2(2000);
5086 l_add_int_int_detail_str varchar2(2000);
5087 l_penal_prin_int_detail_str varchar2(2000);
5088 l_penal_int_int_detail_str varchar2(2000);
5089 l_penal_int_detail_str varchar2(2000);
5090 l_cap_int_detail_str varchar2(2000);
5091 l_early_pay_cr_detail_str varchar2(2000);
5092
5093 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
5094 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
5095 l_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
5096 l_FREQUENCY_REC LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
5097 l_prev_payment_frequency varchar2(30);
5098
5099 -- get last bill date
5100 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
5101 select ACTIVITY_DATE
5102 from LNS_PRIN_TRX_ACTIVITIES_V
5103 where loan_id = p_loan_id
5104 and PAYMENT_NUMBER = p_installment_number
5105 and PARENT_AMORTIZATION_ID is null
5106 and ACTIVITY_CODE in ('BILLING', 'START');
5107
5108 -- get last billed payment info
5109 cursor c_get_last_payment(p_loan_id number, p_installment_number number) is
5110 select (PRINCIPAL_AMOUNT + INTEREST_AMOUNT + nvl(CURR_CAP_INT_AMOUNT, 0)),
5111 nvl(FUNDED_AMOUNT, 0),
5112 nvl(CAP_INT_AMOUNT, 0),
5113 amortization_schedule_id
5114 from lns_amortization_scheds
5115 where loan_id = p_loan_id
5116 and PAYMENT_NUMBER > 0
5117 and PAYMENT_NUMBER = p_installment_number
5118 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
5119 and PARENT_AMORTIZATION_ID is null
5120 and REAMORTIZE_TO_INSTALLMENT is null
5121 --and PRINCIPAL_AMOUNT > 0
5122 and nvl(PHASE, 'TERM') = 'TERM';
5123 --order by PAYMENT_NUMBER desc;
5124
5125 -- get first billed installment number
5126 cursor c_first_billed_instal(p_loan_id number) is
5127 select min(PAYMENT_NUMBER)
5128 from LNS_AMORTIZATION_SCHEDS
5129 where loan_id = p_loan_id
5130 and PAYMENT_NUMBER > 0
5131 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
5132 and PARENT_AMORTIZATION_ID is null
5133 and nvl(PHASE, 'TERM') = 'TERM';
5134
5135 cursor c_fund_sched_exist(p_loan_id number) is
5136 select decode(loan.loan_class_code,
5137 'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
5138 'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
5139 from lns_loan_headers_all loan
5140 where loan.loan_id = p_loan_id;
5141
5142 -- get sum of all add int for last billed installment
5143 cursor c_add_int(p_loan_id number, p_amortization_schedule_id number) is
5144 select nvl(sum(am_lines.amount), 0)
5145 from lns_amortization_lines am_lines,
5146 RA_CUSTOMER_TRX_LINES_ALL trx_lines
5147 where am_lines.loan_id = p_loan_id
5148 and am_lines.amortization_schedule_id = p_amortization_schedule_id
5149 and am_lines.line_type = 'INT'
5150 and am_lines.cust_trx_line_id = trx_lines.CUSTOMER_TRX_LINE_ID
5151 and trx_lines.description not like '%Normal Interest%';
5152
5153 cursor c_get_bill_opt(p_loan_id number) is
5154 select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
5155 from lns_loan_headers_all
5156 where loan_id = p_loan_id;
5157
5158 begin
5159
5160 -- initialize all variables
5161 l_original_loan_amount := 0; -- loan amount
5162 l_amortized_amount := 0;
5163 l_previous_rate_id := -1;
5164 l_previous_annualized := -1;
5165 l_previous_interest_only_flag := 'N'; -- default to regular interest + principal
5166 l_periodic_payment := 0;
5167 l_periodic_principal := 0;
5168 l_periodic_interest := 0;
5169 l_balloon_amount := 0;
5170 l_total_principal := 0;
5171 l_payment_number := 0;
5172 l_fee_amount := 0;
5173 l_other_amount := 0;
5174 l_begin_balance := 0;
5175 l_unbilled_principal := 0;
5176 l_billed_principal := 0;
5177 l_unpaid_principal := 0;
5178 l_remaining_balance_actual := 0;
5179 l_remaining_balance_theory := 0;
5180 l_total := 0;
5181 l_interest_cumulative := 0;
5182 l_principal_cumulative := 0;
5183 l_fees_cumulative := 0;
5184 l_other_cumulative := 0;
5185 i := 0;
5186 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
5187 l_rate_to_calculate := 0;
5188 l_billing := false; -- switch to notify if billing is calling API
5189 l_sum_periodic_principal := 0;
5190 l_api_name := 'amortizeLoan MAIN';
5191
5192 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
5193 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
5194 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
5195
5196 l_loan_term := p_loan_details.loan_term;
5197 l_amortized_amount := p_loan_details.amortized_amount;
5198 l_amortized_term := p_loan_details.amortized_term;
5199 l_amortized_term_period := p_loan_details.amortized_term_period;
5200 l_amortization_frequency := p_loan_details.amortization_frequency;
5201 l_balloon_amount := p_loan_details.balloon_payment_amount;
5202 l_day_count_method := p_loan_details.day_count_method;
5203 l_first_payment_date := p_loan_details.first_payment_date;
5204 l_loan_id := p_loan_details.loan_id;
5205 l_last_installment_billed := p_loan_details.last_installment_billed;
5206 l_loan_start_date := p_loan_details.loan_start_date;
5207 l_maturity_date := p_loan_details.maturity_date;
5208 l_rate_type := p_loan_details.rate_type;
5209 l_open_rate_change_frequency := p_loan_details.open_rate_chg_freq;
5210 l_open_index_rate_id := p_loan_details.open_index_rate_id;
5211 l_open_ceiling_rate := p_loan_details.open_ceiling_rate;
5212 l_open_floor_rate := p_loan_details.open_floor_rate;
5213 l_original_loan_amount := p_loan_details.requested_amount;
5214 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
5215 l_payment_frequency := p_loan_details.payment_frequency;
5216 l_precision := p_loan_details.currency_precision;
5217 l_reamortize_from_installment := p_loan_details.reamortize_from_installment;
5218 l_reamortize_amount := p_loan_details.reamortize_amount;
5219 l_remaining_balance_actual := p_loan_details.remaining_balance;
5220 l_remaining_balance_actual1 := p_loan_details.remaining_balance;
5221 l_term_rate_change_frequency := p_loan_details.term_rate_chg_freq;
5222 l_term_index_rate_id := p_loan_details.term_index_rate_id;
5223 l_term_ceiling_rate := p_loan_details.term_ceiling_rate;
5224 l_term_floor_rate := p_loan_details.term_floor_rate;
5225 l_calc_method := p_loan_details.CALCULATION_METHOD;
5226 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
5227 l_extend_from_installment := p_loan_details.EXTEND_FROM_INSTALLMENT;
5228
5229 -- get the interest rate schedule
5230 l_rate_tbl := p_rate_schedule;
5231 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
5232
5233 -- get payment schedule
5234 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
5235
5236 l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
5237 P_LOAN_ID => l_loan_id,
5238 P_PHASE => 'TERM',
5239 P_COMPONENT => 'PRIN_INT');
5240
5241 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
5242 p_loan_start_date => l_loan_start_date,
5243 p_loan_maturity_date => l_maturity_date,
5244 p_freq_schedule_tbl => l_freq_schedule_tbl);
5245 /*
5246 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
5247 ,p_loan_maturity_date => l_maturity_date
5248 ,p_first_pay_date => l_first_payment_date
5249 ,p_num_intervals => null --l_intervals
5250 ,p_interval_type => l_payment_frequency
5251 ,p_pay_in_arrears => l_pay_in_arrears);
5252 */
5253 l_num_pay_dates := l_payment_tbl.count;
5254 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
5255
5256 if l_loan_term <> l_amortized_term then
5257
5258 -- get amortize maturity date
5259 l_amortized_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term => l_amortized_term
5260 ,p_term_period => l_amortized_term_period
5261 ,p_frequency => l_payment_frequency
5262 ,p_start_date => l_loan_start_date);
5263 -- get amortize payment schedule
5264 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting amortize payment schedule');
5265
5266 l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
5267 P_LOAN_ID => l_loan_id,
5268 P_PHASE => 'TERM',
5269 P_COMPONENT => 'PRIN_INT');
5270
5271 l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
5272 p_loan_start_date => l_loan_start_date,
5273 p_loan_maturity_date => l_amortized_maturity_date,
5274 p_freq_schedule_tbl => l_freq_schedule_tbl);
5275 /*
5276 l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
5277 ,p_loan_maturity_date => l_amortized_maturity_date
5278 ,p_first_pay_date => l_first_payment_date
5279 ,p_num_intervals => null --l_intervals
5280 ,p_interval_type => l_payment_frequency
5281 ,p_pay_in_arrears => l_pay_in_arrears);
5282 */
5283 l_amortization_intervals := l_amortized_payment_tbl.count;
5284 else
5285 l_amortization_intervals := l_num_pay_dates;
5286 end if;
5287 l_amortization_intervals_orig := l_amortization_intervals;
5288 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- amortize payment schedule count = ' || l_amortization_intervals);
5289
5290 if p_based_on_terms <> 'CURRENT' then
5291 open c_fund_sched_exist(l_loan_id);
5292 fetch c_fund_sched_exist into l_fund_sched_count;
5293 close c_fund_sched_exist;
5294
5295 if l_fund_sched_count = 0 then
5296 l_original_loan_amount := p_loan_details.requested_amount;
5297 else
5298 l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
5299 end if;
5300 else
5301 l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
5302 end if;
5303
5304 l_fees_tbl.delete;
5305 l_fee_amount := 0;
5306
5307 -- filling out basis table
5308 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
5309 l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
5310 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
5311 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
5312 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
5313 l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
5314 l_fee_basis_tbl(4).fee_basis_name := 'TOTAL_UNDISB_AMT';
5315 l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
5316
5317 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
5318 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
5319 ,p_loan_id => l_loan_id
5320 ,p_installment => 0
5321 ,p_fee_basis_tbl => l_fee_basis_tbl
5322 ,p_based_on_terms => p_based_on_terms
5323 ,p_phase => 'TERM'
5324 ,x_fees_tbl => l_fees_tbl
5325 ,x_return_status => l_return_status
5326 ,x_msg_count => l_msg_count
5327 ,x_msg_data => l_msg_data);
5328
5329 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
5330 if l_return_status <> 'S' then
5331 RAISE FND_API.G_EXC_ERROR;
5332 end if;
5333
5334 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
5335
5336 for k in 1..l_fees_tbl.count loop
5337 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
5338 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
5339 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
5340 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
5341 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
5342 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
5343 end loop;
5344 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
5345
5346 if l_fee_amount > 0 then
5347 i := i + 1;
5348 l_amortization_rec.installment_number := 0;
5349 l_amortization_rec.due_date := l_loan_start_date;
5350 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
5351 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
5352 l_amortization_rec.principal_amount := 0;
5353 l_amortization_rec.interest_amount := 0;
5354 l_amortization_rec.fee_amount := l_fee_amount;
5355 l_amortization_rec.other_amount := 0;
5356 l_amortization_rec.begin_balance := l_original_loan_amount;
5357 l_amortization_rec.end_balance := l_original_loan_amount;
5358 l_amortization_rec.interest_cumulative := 0;
5359 l_amortization_rec.principal_cumulative := 0;
5360 l_amortization_rec.fees_cumulative := l_fee_amount;
5361 l_amortization_rec.other_cumulative := 0;
5362 l_amortization_rec.rate_id := 0;
5363 l_amortization_rec.SOURCE := 'PREDICTED';
5364 l_amortization_rec.total := l_fee_amount;
5365 l_amortization_rec.UNPAID_PRIN := 0;
5366 l_amortization_rec.UNPAID_INT := 0;
5367 l_amortization_rec.INTEREST_RATE := l_rate_tbl(1).annual_rate;
5368 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
5369 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
5370 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
5371 l_amortization_rec.PENAL_INT_AMOUNT := 0;
5372 l_amortization_rec.FUNDED_AMOUNT := l_original_loan_amount;
5373 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
5374 l_amortization_rec.DISBURSEMENT_AMOUNT := l_original_loan_amount;
5375 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
5376 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
5377 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
5378 l_amortization_rec.CAP_INT_AMOUNT := 0;
5379 l_amortization_rec.CAP_INT_DETAILS := null;
5380 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
5381
5382 -- add the record to the amortization table
5383 l_amortization_tbl(i) := l_amortization_rec;
5384 end if;
5385
5386 -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
5387 if p_installment_number is not null then
5388 -- we are billing
5389
5390 l_billing := true;
5391 if p_installment_number > 0 then
5392
5393 if p_installment_number > l_num_pay_dates then
5394 l_payment_number := l_num_pay_dates;
5395 else
5396 l_payment_number := p_installment_number;
5397 end if;
5398
5399 else
5400 l_payment_number := p_installment_number;
5401 end if;
5402
5403 else -- we are not billing, go thru entire amortization
5404
5405 l_payment_number := l_num_pay_dates;
5406
5407 end if;
5408
5409 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
5410 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
5411
5412 l_begin := 1;
5413
5414 if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
5415
5416 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5417 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_last_installment_billed || '-----');
5418 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5419
5420 l_periodic_payment := null;
5421 open c_get_last_payment(l_loan_id, l_last_installment_billed);
5422 fetch c_get_last_payment into l_periodic_payment, l_begin_funded_amount, l_prev_cap_int, l_amortization_schedule_id;
5423 close c_get_last_payment;
5424 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
5425 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
5426 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_amortization_schedule_id = ' || l_amortization_schedule_id);
5427
5428 if p_loan_details.FLUCTUATE_EQ_PAY_AMOUNT = 'Y' then
5429 open c_add_int(l_loan_id, l_amortization_schedule_id);
5430 fetch c_add_int into l_add_int_amount;
5431 close c_add_int;
5432 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_amount = ' || l_add_int_amount);
5433 l_periodic_payment := l_periodic_payment - l_add_int_amount;
5434 end if;
5435
5436 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic payment = ' || l_periodic_payment);
5437
5438 if l_periodic_payment is not null then
5439
5440 l_begin := l_last_installment_billed + 1;
5441
5442 if l_rate_tbl.count = 1 then
5443 l_previous_annualized := l_rate_tbl(1).annual_rate;
5444 l_previous_interest_only_flag := l_rate_tbl(1).interest_only_flag;
5445 else
5446 l_rate_details := lns_financials.getRateDetails(p_installment => l_last_installment_billed
5447 ,p_rate_tbl => l_rate_tbl);
5448 l_previous_annualized := l_rate_details.annual_rate;
5449 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
5450 end if;
5451
5452 end if;
5453
5454 else
5455 l_remaining_balance_theory := l_original_loan_amount;
5456 l_begin_funded_amount := 0; --l_original_loan_amount;
5457 l_end_funded_amount := l_original_loan_amount;
5458 l_prev_cap_int := 0;
5459
5460 open c_get_bill_opt(l_loan_id);
5461 fetch c_get_bill_opt into l_bill_on_appr_amounts;
5462 close c_get_bill_opt;
5463 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
5464 end if;
5465
5466 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin = ' || l_begin);
5467 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.REAMORTIZE_ON_FUNDING = ' || p_loan_details.REAMORTIZE_ON_FUNDING);
5468 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
5469
5470 l_increase_amount_instal := -1;
5471
5472 if l_begin = 1 then
5473 l_prev_payment_frequency := '';
5474 else
5475 LNS_FIN_UTILS.fetchPayFreqRecByDate(
5476 p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
5477 p_DATE => l_payment_tbl(l_begin-1).PERIOD_DUE_DATE,
5478 x_FREQUENCY_REC => l_FREQUENCY_REC);
5479 l_prev_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
5480 end if;
5481
5482 -- loop to build the amortization schedule
5483 for l_installment_number in l_begin..l_payment_number
5484 loop
5485
5486 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5487 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || ' -----');
5488 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5489
5490 i := i + 1;
5491 l_periodic_interest := 0;
5492 l_periodic_principal := 0;
5493 l_fee_amount := 0;
5494 l_other_amount := 0;
5495 l_unpaid_principal := 0;
5496 l_unpaid_interest := 0;
5497 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
5498 l_detail_int_calc_flag := false;
5499 l_increased_amount := 0;
5500 l_increased_amount1 := 0;
5501 l_prev_increase_amount_instal := l_increase_amount_instal;
5502
5503 if l_fund_sched_count > 0 or p_based_on_terms = 'CURRENT' then
5504
5505 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number) then
5506
5507 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 = l_installment_number');
5508
5509 l_principal_cumulative := 0;
5510 l_interest_cumulative := 0;
5511 l_fees_cumulative := 0;
5512 l_other_cumulative := 0;
5513 l_sum_periodic_principal := 0;
5514 l_billed_principal := p_loan_details.billed_principal;
5515 l_unbilled_principal := p_loan_details.unbilled_principal;
5516 l_unpaid_principal := p_loan_details.unpaid_principal;
5517 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
5518
5519 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
5520 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
5521 l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
5522 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
5523
5524 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
5525 l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
5526 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
5527
5528 if l_end_funded_amount > l_begin_funded_amount then
5529 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
5530
5531 if l_end_funded_amount = l_begin_funded_amount_new then
5532 l_increase_amount_instal := l_installment_number;
5533 else
5534 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
5535 l_increase_amount_instal := l_installment_number + 1;
5536 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
5537 l_increase_amount_instal := l_installment_number;
5538 end if;
5539 end if;
5540
5541 elsif l_begin_funded_amount_new > l_begin_funded_amount then
5542 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new > l_begin_funded_amount');
5543 l_increase_amount_instal := l_installment_number;
5544 end if;
5545
5546 l_detail_int_calc_flag := true;
5547
5548 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
5549 l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
5550 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
5551
5552 l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
5553 l_begin_funded_amount := l_begin_funded_amount_new;
5554 l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
5555 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
5556 l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal;
5557 else
5558 l_remaining_balance_theory := 0;
5559 end if;
5560
5561 else
5562
5563 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 < l_installment_number');
5564 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
5565 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
5566 l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
5567 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
5568
5569 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
5570 l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
5571 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
5572
5573 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
5574 l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
5575 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
5576
5577 if l_end_funded_amount > l_begin_funded_amount then
5578 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
5579 l_detail_int_calc_flag := true;
5580
5581 if l_end_funded_amount = l_begin_funded_amount_new then
5582 l_increase_amount_instal := l_installment_number;
5583 else
5584 if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
5585 l_increase_amount_instal := l_installment_number + 1;
5586 elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
5587 l_increase_amount_instal := l_installment_number;
5588 end if;
5589 end if;
5590
5591 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
5592 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
5593
5594 l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
5595 l_begin_funded_amount := l_begin_funded_amount_new;
5596 l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
5597 l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal - l_sum_periodic_principal;
5598 end if;
5599 else
5600 l_remaining_balance_theory := 0;
5601 end if;
5602
5603 end if;
5604
5605 elsif l_installment_number = 1 and l_fund_sched_count = 0 and p_based_on_terms <> 'CURRENT' then
5606 l_increased_amount := l_original_loan_amount;
5607 end if;
5608
5609 if p_loan_details.REAMORTIZE_ON_FUNDING = 'NO' then
5610 l_increase_amount_instal := -1;
5611 end if;
5612
5613 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
5614
5615 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
5616 l_rate_details := getRateDetails(p_installment => l_installment_number
5617 ,p_rate_tbl => l_rate_tbl);
5618
5619 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
5620 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
5621 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
5622
5623 -- get the rate details only need to get it once if a single interest rate exists
5624 l_current_rate_id := l_rate_details.rate_id;
5625 l_annualized_rate := l_rate_details.annual_rate;
5626 l_interest_only_flag := l_rate_details.interest_only_flag;
5627
5628 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_rate_id = ' || l_previous_rate_id);
5629 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id = ' || l_current_rate_id);
5630 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized = ' || l_previous_annualized);
5631 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate = ' || l_annualized_rate);
5632 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_interest_only_flag = ' || l_previous_interest_only_flag);
5633 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag = ' || l_interest_only_flag);
5634 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
5635 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment = ' || l_extend_from_installment);
5636 if l_detail_int_calc_flag then
5637 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = true');
5638 else
5639 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = false');
5640 end if;
5641 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount = ' || l_increased_amount);
5642 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount1 = ' || l_increased_amount1);
5643 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increase_amount_instal = ' || l_increase_amount_instal);
5644
5645 -- getting current frequency record
5646 LNS_FIN_UTILS.fetchPayFreqRecByDate(
5647 p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
5648 p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
5649 x_FREQUENCY_REC => l_FREQUENCY_REC);
5650 l_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
5651
5652 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_payment_frequency = ' || l_prev_payment_frequency);
5653 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_frequency = ' || l_payment_frequency);
5654
5655 -- conditions to recalculate payment
5656 -- 1. 1-st installment
5657 -- 2. previous interest rate <> current interest rate
5658 -- 3. reamortization from installment = current installment
5659 -- 4. emerging from interest only period
5660 -- 5. reamortize because loan term has been extended
5661 -- 6. funded amount has increased since last installment
5662
5663 if ((l_installment_number = 1) OR
5664 (l_annualized_rate <> l_previous_annualized) OR
5665 (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
5666 (l_previous_interest_only_flag = 'Y' and l_interest_only_flag = 'N') OR
5667 (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
5668 (l_prev_increase_amount_instal = l_installment_number or l_increase_amount_instal = l_installment_number) OR
5669 (l_payment_frequency <> l_prev_payment_frequency))
5670 then
5671
5672 -- we need to recalculate the payment_amount
5673 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': RE-calculating periodic payment');
5674 l_amortization_intervals := l_amortization_intervals_orig - l_installment_number + 1;
5675
5676 if (l_calc_method = 'SIMPLE') then
5677
5678 l_rate_to_calculate := lns_financials.getPeriodicRate(
5679 p_payment_freq => l_payment_frequency
5680 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5681 ,p_period_end_date => l_maturity_date
5682 ,p_annualized_rate => l_annualized_rate
5683 ,p_days_count_method => l_day_count_method
5684 ,p_target => 'PAYMENT');
5685
5686 elsif (l_calc_method = 'COMPOUND') then
5687
5688 l_rate_to_calculate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5689 ,p_payment_freq => l_payment_frequency
5690 ,p_annualized_rate => l_annualized_rate
5691 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5692 ,p_period_end_date => l_maturity_date
5693 ,p_days_count_method => l_day_count_method
5694 ,p_target => 'PAYMENT');
5695
5696 end if;
5697
5698 -- we need to calculate payment ONCE per interest rate change
5699 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_rate_to_calculate = ' || l_rate_to_calculate);
5700 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_amortization_intervals = ' || l_amortization_intervals);
5701
5702 l_remaining_balance := l_remaining_balance_theory + l_increased_amount1;
5703
5704 if l_rate_details.rate_id = l_rate_tbl(1).rate_id then
5705 l_periodic_payment := lns_financials.calculatePayment(p_loan_amount => l_remaining_balance
5706 ,p_periodic_rate => l_rate_to_calculate
5707 ,p_num_intervals => l_amortization_intervals
5708 ,p_ending_balance=> l_balloon_amount
5709 ,p_pay_in_arrears=> l_pay_in_arrears);
5710 else
5711 l_periodic_payment := lns_financials.calculatePayment(p_loan_amount => l_remaining_balance
5712 ,p_periodic_rate => l_rate_to_calculate
5713 ,p_num_intervals => l_amortization_intervals
5714 ,p_ending_balance=> l_balloon_amount
5715 ,p_pay_in_arrears=> true);
5716 end if;
5717
5718 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic payment = ' || l_periodic_payment);
5719
5720 else
5721 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD periodic payment = ' || l_periodic_payment);
5722 end if;
5723
5724 l_norm_interest := 0;
5725 l_add_prin_interest := 0;
5726 l_add_int_interest := 0;
5727 l_penal_prin_interest := 0;
5728 l_penal_int_interest := 0;
5729 l_penal_interest := 0;
5730 l_early_pay_cr := 0;
5731 l_norm_int_detail_str := null;
5732 l_add_prin_int_detail_str := null;
5733 l_add_int_int_detail_str := null;
5734 l_penal_prin_int_detail_str := null;
5735 l_penal_int_int_detail_str := null;
5736 l_penal_int_detail_str := null;
5737 l_early_pay_cr_detail_str := null;
5738
5739 -- now we will caculate the interest due for this period
5740 if (p_based_on_terms = 'CURRENT' and l_detail_int_calc_flag = true) then
5741
5742 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
5743 LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
5744 p_calc_method => l_calc_method,
5745 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5746 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
5747 p_interest_rate => l_annualized_rate,
5748 p_day_count_method => l_day_count_method,
5749 p_payment_freq => l_payment_frequency,
5750 p_compound_freq => l_compound_freq,
5751 p_adj_amount => l_sum_periodic_principal,
5752 p_CAP_AMOUNT => l_prev_cap_int,
5753 x_norm_interest => l_norm_interest,
5754 x_norm_int_details => l_norm_int_detail_str);
5755
5756 l_norm_interest := round(l_norm_interest, l_precision);
5757
5758 if (l_installment_number-1) >= 0 and l_last_installment_billed + 1 = l_installment_number then
5759
5760 -- get additional interest start date
5761 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
5762 fetch c_get_last_bill_date into l_add_start_date;
5763 close c_get_last_bill_date;
5764
5765 -- get additional interest end date
5766 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
5767 l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
5768 else
5769 l_add_end_date := sysdate;
5770 end if;
5771
5772 if (l_installment_number-1) > 0 then
5773 l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
5774 else
5775 l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
5776 end if;
5777
5778 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
5779 -- calculate additional interest on unpaid principal
5780 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
5781 p_calc_method => l_calc_method,
5782 p_period_start_date => l_add_start_date,
5783 p_period_end_date => l_add_end_date,
5784 p_interest_rate => l_annualized_rate,
5785 p_day_count_method => l_day_count_method,
5786 p_payment_freq => l_payment_frequency,
5787 p_compound_freq => l_compound_freq,
5788 p_prev_grace_end_date => l_prev_grace_end_date,
5789 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
5790 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5791 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
5792 p_target => 'UNPAID_PRIN',
5793 x_add_interest => l_add_prin_interest,
5794 x_penal_interest => l_penal_prin_interest,
5795 x_add_int_details => l_add_prin_int_detail_str,
5796 x_penal_int_details => l_penal_prin_int_detail_str);
5797 l_add_prin_interest := round(l_add_prin_interest, l_precision);
5798
5799 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
5800 -- calculate additional interest on unpaid interest
5801 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
5802 p_calc_method => l_calc_method,
5803 p_period_start_date => l_add_start_date,
5804 p_period_end_date => l_add_end_date,
5805 p_interest_rate => l_annualized_rate,
5806 p_day_count_method => l_day_count_method,
5807 p_payment_freq => l_payment_frequency,
5808 p_compound_freq => l_compound_freq,
5809 p_prev_grace_end_date => l_prev_grace_end_date,
5810 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
5811 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5812 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
5813 p_target => 'UNPAID_INT',
5814 x_add_interest => l_add_int_interest,
5815 x_penal_interest => l_penal_int_interest,
5816 x_add_int_details => l_add_int_int_detail_str,
5817 x_penal_int_details => l_penal_int_int_detail_str);
5818 l_add_int_interest := round(l_add_int_interest, l_precision);
5819
5820 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
5821 l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
5822 else
5823 l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
5824 end if;
5825
5826 -- calculate interest credit on early payment
5827 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
5828 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => l_loan_id,
5829 p_calc_method => l_calc_method,
5830 p_installment => l_installment_number,
5831 p_interest_rate => l_previous_annualized,
5832 p_day_count_method => l_day_count_method,
5833 p_payment_freq => l_payment_frequency,
5834 p_compound_freq => l_compound_freq,
5835 x_early_pay_cr => l_early_pay_cr,
5836 x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
5837
5838 end if;
5839
5840 elsif (p_based_on_terms <> 'CURRENT' and l_detail_int_calc_flag = true and l_bill_on_appr_amounts = 'N') then
5841
5842 if (l_calc_method = 'SIMPLE') then
5843
5844 l_periodic_rate := lns_financials.getPeriodicRate(
5845 p_payment_freq => l_payment_frequency
5846 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5847 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5848 ,p_annualized_rate => l_annualized_rate
5849 ,p_days_count_method => l_day_count_method
5850 ,p_target => 'INTEREST');
5851
5852 elsif (l_calc_method = 'COMPOUND') then
5853
5854 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5855 ,p_payment_freq => l_payment_frequency
5856 ,p_annualized_rate => l_annualized_rate
5857 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5858 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5859 ,p_days_count_method => l_day_count_method
5860 ,p_target => 'INTEREST');
5861
5862 end if;
5863
5864 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
5865 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
5866 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
5867 ,p_calc_method => 'TARGET'
5868 ,p_phase => 'TERM'
5869 ,p_day_count_method => l_day_count_method
5870 ,p_adj_amount => l_sum_periodic_principal
5871 ,x_wtd_balance => l_wtd_balance
5872 ,x_begin_balance => l_balance1
5873 ,x_end_balance => l_balance2);
5874
5875 l_wtd_balance := l_wtd_balance + l_prev_cap_int;
5876 l_norm_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
5877 ,p_periodic_rate => l_periodic_rate
5878 ,p_compounding_period => null);
5879 l_norm_interest := round(l_norm_interest, l_precision);
5880
5881 l_norm_int_detail_str := l_norm_interest || ' (' ||
5882 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
5883 ' * Balance ' || l_wtd_balance ||
5884 ' * Rate ' || l_annualized_rate || '%)';
5885 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
5886
5887 else
5888
5889 l_remaining_balance_theory1 := l_remaining_balance_theory + l_prev_cap_int;
5890 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_theory1);
5891
5892 if (l_calc_method = 'SIMPLE') then
5893
5894 l_periodic_rate := lns_financials.getPeriodicRate(
5895 p_payment_freq => l_payment_frequency
5896 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5897 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5898 ,p_annualized_rate => l_annualized_rate
5899 ,p_days_count_method => l_day_count_method
5900 ,p_target => 'INTEREST');
5901
5902 elsif (l_calc_method = 'COMPOUND') then
5903
5904 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5905 ,p_payment_freq => l_payment_frequency
5906 ,p_annualized_rate => l_annualized_rate
5907 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5908 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5909 ,p_days_count_method => l_day_count_method
5910 ,p_target => 'INTEREST');
5911
5912 end if;
5913
5914 l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_theory1
5915 ,p_periodic_rate => l_periodic_rate
5916 ,p_compounding_period => null);
5917
5918 l_norm_interest := round(l_norm_interest, l_precision);
5919
5920 l_norm_int_detail_str := l_norm_interest || ' (' ||
5921 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
5922 ' * Balance ' || l_remaining_balance_theory1 ||
5923 ' * Rate ' || l_annualized_rate || '%)';
5924 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
5925
5926 end if;
5927
5928 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
5929 l_periodic_interest := round(l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest - l_early_pay_cr, l_precision);
5930
5931 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_payment = ' || l_periodic_payment);
5932 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
5933 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
5934 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_intervals_remaining = ' || l_intervals_remaining);
5935 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled_principal = ' || l_unbilled_principal);
5936
5937 -- check to see if we are in an interest only period
5938 -- if this is the case then the periodic_principal = 0
5939 -- there is a chance that the loan negatively amortizes
5940 if l_interest_only_flag <> 'Y' or l_intervals_remaining = 1 then
5941
5942 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculating principal due');
5943
5944 if p_loan_details.FLUCTUATE_EQ_PAY_AMOUNT = 'N' then -- Include additional interest into Equal Payment
5945 l_periodic_principal := l_periodic_payment - l_periodic_interest;
5946 else -- DONT Include additional interest into Equal Payment
5947 l_periodic_principal := l_periodic_payment - l_norm_interest;
5948 end if;
5949
5950 l_periodic_principal := round(l_periodic_principal, l_precision);
5951 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal = ' || l_periodic_principal);
5952
5953 -- this is temporary according to not letting amortizations go negative
5954 if l_periodic_principal < 0 then
5955 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': DISALLOW NEGATIVE AMORTIZATION');
5956 l_periodic_principal := 0;
5957 end if;
5958
5959 -- make sure the final installment gets the remaining balance on the loan irregardless
5960 if (l_remaining_balance_theory + l_increased_amount1) < l_periodic_principal then
5961 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
5962 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
5963 else
5964 if l_intervals_remaining = 1 then
5965 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
5966 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal = ' || l_unbilled_principal);
5967 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
5968 if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
5969 l_periodic_principal := l_unbilled_principal;
5970 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
5971 else
5972 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
5973 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
5974 end if;
5975 end if;
5976 end if;
5977
5978 else
5979 -- we are in an interest only period
5980 l_periodic_principal := 0;
5981
5982 end if;
5983
5984 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
5985 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': principal = ' || l_periodic_principal);
5986
5987 -- calculate balances
5988 l_begin_balance := l_remaining_balance_theory;
5989 l_end_balance := l_remaining_balance_theory - l_periodic_principal + l_increased_amount1;
5990
5991 -- check to see if this loan has been billed
5992 if l_unbilled_principal > 0 then
5993 l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
5994 end if;
5995
5996 -- build the amortization record
5997 l_amortization_rec.installment_number := l_installment_number; /* needed to calculate fees */
5998 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
5999 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
6000 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
6001 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
6002 l_amortization_rec.interest_amount := l_periodic_interest;
6003 l_amortization_rec.rate_id := l_current_rate_id;
6004 l_amortization_rec.rate_unadj := l_annualized_rate;
6005 l_amortization_rec.RATE_CHANGE_FREQ := p_loan_details.TERM_RATE_CHG_FREQ;
6006 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
6007 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
6008 l_amortization_rec.INTEREST_RATE := l_annualized_rate;
6009 l_amortization_rec.NORMAL_INT_AMOUNT := l_norm_interest;
6010 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_add_prin_interest;
6011 l_amortization_rec.ADD_INT_INT_AMOUNT := l_add_int_interest;
6012 l_amortization_rec.PENAL_INT_AMOUNT := l_penal_interest;
6013 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
6014 l_amortization_rec.DISBURSEMENT_AMOUNT := l_increased_amount;
6015 l_amortization_rec.FUNDED_AMOUNT := l_end_funded_amount;
6016 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
6017 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
6018 l_amortization_rec.EARLY_PAY_CR_AMOUNT := -l_early_pay_cr;
6019
6020 if l_amortization_rec.FUNDED_AMOUNT is null then
6021 l_amortization_rec.FUNDED_AMOUNT := 0;
6022 end if;
6023
6024 l_cap_int_detail_str := null;
6025 l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
6026 if p_loan_details.CAPITALIZE_INT = 'Y' then
6027 l_amortization_rec.begin_balance := l_begin_balance + l_prev_cap_int;
6028 if l_end_balance = 0 and l_amortization_rec.interest_amount > 0 then
6029 l_amortization_rec.end_balance := l_end_balance;
6030 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_prev_cap_int;
6031 l_amortization_rec.CAP_INT_AMOUNT := 0;
6032 l_prev_cap_int := 0;
6033 l_amortization_rec.interest_amount := l_amortization_rec.interest_amount + l_amortization_rec.PREV_CAP_INT_AMOUNT;
6034 else
6035 l_amortization_rec.end_balance := l_end_balance + l_prev_cap_int;
6036 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
6037 l_amortization_rec.CAP_INT_AMOUNT := l_prev_cap_int + l_amortization_rec.interest_amount;
6038 if l_amortization_rec.CAP_INT_AMOUNT > 0 then
6039 if l_prev_cap_int <> 0 then
6040 l_cap_int_detail_str := 'Previously Capitalized Interest ' || l_prev_cap_int;
6041 end if;
6042 if l_norm_interest <> 0 then
6043 if l_cap_int_detail_str is not null then
6044 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6045 end if;
6046 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Normal Interest ' || l_norm_int_detail_str;
6047 end if;
6048 if l_add_prin_interest <> 0 then
6049 if l_cap_int_detail_str is not null then
6050 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6051 end if;
6052 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Prin ' || l_add_prin_int_detail_str;
6053 end if;
6054 if l_add_int_interest <> 0 then
6055 if l_cap_int_detail_str is not null then
6056 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6057 end if;
6058 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Interest ' || l_add_int_int_detail_str;
6059 end if;
6060 if l_penal_interest <> 0 then
6061 if l_cap_int_detail_str is not null then
6062 l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6063 end if;
6064 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Penal Interest ' || l_penal_interest || ' (' || l_penal_int_detail_str || ')';
6065 end if;
6066 if l_early_pay_cr <> 0 then
6067 if l_cap_int_detail_str is not null then
6068 l_cap_int_detail_str := l_cap_int_detail_str || ' -<br>';
6069 end if;
6070 l_cap_int_detail_str := l_cap_int_detail_str || 'Current Int Cr on Early Payment ' || l_early_pay_cr || ' (' || l_early_pay_cr_detail_str || ')';
6071 end if;
6072 end if;
6073 l_prev_cap_int := l_amortization_rec.CAP_INT_AMOUNT;
6074 if l_amortization_rec.NORMAL_INT_AMOUNT > 0 then
6075 l_norm_int_detail_str := 'Interest amount is capitalized';
6076 end if;
6077
6078 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_amortization_rec.interest_amount;
6079 l_amortization_rec.interest_amount := 0;
6080 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
6081 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
6082 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
6083 l_amortization_rec.PENAL_INT_AMOUNT := 0;
6084 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
6085
6086 l_add_prin_int_detail_str := null;
6087 l_add_int_int_detail_str := null;
6088 l_penal_prin_int_detail_str := null;
6089 l_penal_int_int_detail_str := null;
6090 l_penal_int_detail_str := null;
6091 l_early_pay_cr_detail_str := null;
6092 end if;
6093 else
6094 l_amortization_rec.begin_balance := l_begin_balance;
6095 l_amortization_rec.end_balance := l_end_balance;
6096 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
6097 l_amortization_rec.CAP_INT_AMOUNT := 0;
6098 l_prev_cap_int := 0;
6099 end if;
6100 l_amortization_rec.total := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
6101
6102 l_fees_tbl.delete;
6103 l_fee_amount := 0;
6104 l_other_amount := 0;
6105
6106 -- filling out basis table
6107 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
6108 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
6109 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
6110 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
6111 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
6112 l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
6113 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN';
6114 l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
6115 l_fee_basis_tbl(5).fee_basis_name := 'OVERDUE_PRIN_INT';
6116 l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
6117 l_fee_basis_tbl(6).fee_basis_name := 'IND_DISB_AMT';
6118 l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
6119 l_fee_basis_tbl(7).fee_basis_name := 'TOTAL_UNDISB_AMT';
6120 l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
6121 l_fee_basis_tbl(8).fee_basis_name := 'OVERDUE_INT';
6122 l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
6123 l_fee_basis_tbl(9).fee_basis_name := 'CURR_LOAN';
6124 l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
6125
6126 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
6127 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
6128 ,p_loan_id => l_loan_id
6129 ,p_installment => l_installment_number
6130 ,p_fee_basis_tbl => l_fee_basis_tbl
6131 ,p_based_on_terms => p_based_on_terms
6132 ,p_phase => 'TERM'
6133 ,x_fees_tbl => l_fees_tbl
6134 ,x_return_status => l_return_status
6135 ,x_msg_count => l_msg_count
6136 ,x_msg_data => l_msg_data);
6137
6138 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
6139 if l_return_status <> 'S' then
6140 RAISE FND_API.G_EXC_ERROR;
6141 end if;
6142
6143 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
6144
6145 for k in 1..l_fees_tbl.count loop
6146 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
6147 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
6148 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
6149 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
6150 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
6151 if l_fees_tbl(k).FEE_CATEGORY = 'MEMO' then
6152 l_other_amount := l_other_amount + l_fees_tbl(k).FEE_AMOUNT;
6153 else
6154 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
6155 end if;
6156 end loop;
6157
6158 l_amortization_rec.fee_amount := l_fee_amount;
6159 l_amortization_rec.other_amount := l_other_amount;
6160 l_amortization_rec.total := l_amortization_rec.total + l_amortization_rec.fee_amount + l_amortization_rec.other_amount;
6161
6162 -- running totals calculated here
6163 l_principal_cumulative := l_principal_cumulative + l_amortization_rec.principal_amount;
6164 l_interest_cumulative := l_interest_cumulative + l_amortization_rec.interest_amount;
6165 l_fees_cumulative := l_fees_cumulative + l_amortization_rec.fee_amount;
6166 l_other_cumulative := l_other_cumulative + l_amortization_rec.other_amount;
6167
6168 l_amortization_rec.interest_cumulative := l_interest_cumulative;
6169 l_amortization_rec.principal_cumulative := l_principal_cumulative;
6170 l_amortization_rec.fees_cumulative := l_fees_cumulative;
6171 l_amortization_rec.other_cumulative := l_other_cumulative;
6172 l_amortization_rec.rate_id := l_current_rate_id;
6173 l_amortization_rec.SOURCE := 'PREDICTED';
6174
6175 l_amortization_rec.NORMAL_INT_DETAILS := l_norm_int_detail_str;
6176 l_amortization_rec.ADD_PRIN_INT_DETAILS := l_add_prin_int_detail_str;
6177 l_amortization_rec.ADD_INT_INT_DETAILS := l_add_int_int_detail_str;
6178 l_amortization_rec.PENAL_INT_DETAILS := l_penal_int_detail_str;
6179 l_amortization_rec.CAP_INT_DETAILS := l_cap_int_detail_str;
6180 l_amortization_rec.EARLY_PAY_CR_DETAILS := l_early_pay_cr_detail_str;
6181
6182 -- add the record to the amortization table
6183 l_amortization_tbl(i) := l_amortization_rec;
6184
6185 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
6186 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INSTALLMENT ' || l_installment_number);
6187 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
6188 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD = ' || l_amortization_rec.PERIOD);
6189 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_START_DATE = ' || l_amortization_rec.PERIOD_START_DATE);
6190 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_END_DATE = ' || l_amortization_rec.PERIOD_END_DATE);
6191 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'due date = ' || l_amortization_rec.due_date);
6192 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_principal = ' || l_amortization_rec.principal_amount);
6193 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_interest = ' || l_amortization_rec.interest_amount);
6194 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fee_amount = ' || l_amortization_rec.fee_amount);
6195 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_amount = ' || l_amortization_rec.other_amount);
6196 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'total = ' || l_amortization_rec.total);
6197 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'begin_balance = ' || l_amortization_rec.begin_balance);
6198 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'end_balance = ' || l_amortization_rec.end_balance);
6199 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'interest_cumulative = ' || l_amortization_rec.interest_cumulative);
6200 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'principal_cumulative = ' || l_amortization_rec.principal_cumulative);
6201 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fees_cumulative = ' || l_amortization_rec.fees_cumulative);
6202 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_cumulative = ' || l_amortization_rec.other_cumulative);
6203 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'current_rate_id = ' || l_amortization_rec.rate_id );
6204 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_RATE = ' || l_amortization_rec.INTEREST_RATE );
6205 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_PRIN = ' || l_amortization_rec.UNPAID_PRIN );
6206 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_INT = ' || l_amortization_rec.UNPAID_INT );
6207 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
6208 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_AMOUNT = ' || l_amortization_rec.ADD_PRIN_INT_AMOUNT );
6209 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_AMOUNT );
6210 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_AMOUNT = ' || l_amortization_rec.PENAL_INT_AMOUNT );
6211 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FUNDED_AMOUNT = ' || l_amortization_rec.FUNDED_AMOUNT );
6212 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amortization_rec.NORMAL_INT_DETAILS );
6213 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_DETAILS = ' || l_amortization_rec.ADD_PRIN_INT_DETAILS );
6214 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_DETAILS_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_DETAILS );
6215 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_DETAILS = ' || l_amortization_rec.PENAL_INT_DETAILS );
6216 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amortization_rec.PREV_CAP_INT_AMOUNT );
6217 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amortization_rec.CURR_CAP_INT_AMOUNT );
6218 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amortization_rec.CAP_INT_AMOUNT );
6219 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amortization_rec.CAP_INT_DETAILS );
6220 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_AMOUNT = ' || l_amortization_rec.EARLY_PAY_CR_AMOUNT );
6221 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_DETAILS = ' || l_amortization_rec.EARLY_PAY_CR_DETAILS );
6222 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
6223
6224 l_remaining_balance_theory := l_end_balance;
6225 l_sum_periodic_principal := l_sum_periodic_principal + l_periodic_principal;
6226
6227 l_previous_interest_only_flag := l_interest_only_flag;
6228 l_previous_rate_id := l_current_rate_id;
6229 l_previous_annualized := l_annualized_rate;
6230 l_prev_payment_frequency := l_payment_frequency;
6231
6232 end loop;
6233
6234 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT = ' || l_amortization_tbl.count);
6235 x_loan_amort_tbl := l_amortization_tbl;
6236
6237 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6238
6239 Exception
6240 WHEN FND_API.G_EXC_ERROR THEN
6241 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6242
6243 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6244 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
6245
6246 WHEN OTHERS THEN
6247 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6248
6249 end amortizeLoan;
6250
6251 /*=========================================================================
6252 || PUBLIC PROCEDURE amortizeLoan
6253 ||
6254 || DESCRIPTION
6255 ||
6256 || Overview: amortizes a loan
6257 || this api assumes the loan information is in the
6258 || Loans DataModel
6259 ||
6260 || Parameter: p_loan_id => Loan ID
6261 ||
6262 || Source Tables: NA
6263 ||
6264 || Target Tables: NA
6265 ||
6266 || Return value: x_loan_amort_tbl table of amortization_records
6267 ||
6268 || KNOWN ISSUES
6269 ||
6270 || NOTES
6271 ||
6272 || MODIFICATION HISTORY
6273 || Date Author Description of Changes
6274 || 12/09/2003 1:51PM raverma Created
6275 || 04/07/2004 raverma alter so we dont need to loop thru
6276 || whole amortization
6277 *=======================================================================*/
6278 procedure amortizeLoan (p_loan_Id in number
6279 ,p_based_on_terms in varchar2
6280 ,p_installment_number in number
6281 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
6282
6283 is
6284 l_loan_details LOAN_DETAILS_REC;
6285 l_amortization_tbl amortization_tbl;
6286 l_rate_tbl RATE_SCHEDULE_TBL;
6287 l_api_name varchar2(20);
6288 begin
6289
6290 l_api_name := 'amortizeLoan';
6291 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6292 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
6293 ,p_based_on_terms => p_based_on_terms
6294 ,p_phase => 'TERM');
6295
6296 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
6297
6298 if (l_loan_details.PAYMENT_CALC_METHOD = 'EQUAL_PRINCIPAL') then
6299
6300 lns_financials.amortizeEPLoan(p_loan_details => l_loan_details
6301 ,p_rate_schedule => l_rate_tbl
6302 ,p_based_on_terms => p_based_on_terms
6303 ,p_installment_number => p_installment_number
6304 ,x_loan_amort_tbl => l_amortization_tbl);
6305
6306 elsif (l_loan_details.PAYMENT_CALC_METHOD = 'SEPARATE_SCHEDULES') then
6307
6308 lns_financials.amortizeSIPLoan(p_loan_details => l_loan_details
6309 ,p_rate_schedule => l_rate_tbl
6310 ,p_based_on_terms => p_based_on_terms
6311 ,p_installment_number => p_installment_number
6312 ,x_loan_amort_tbl => l_amortization_tbl);
6313
6314 elsif (l_loan_details.PAYMENT_CALC_METHOD = 'EQUAL_PAYMENT') then
6315
6316 lns_financials.amortizeLoan(p_loan_details => l_loan_details
6317 ,p_rate_schedule => l_rate_tbl
6318 ,p_based_on_terms => p_based_on_terms
6319 ,p_installment_number => p_installment_number
6320 ,x_loan_amort_tbl => l_amortization_tbl);
6321
6322 end if;
6323
6324 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' Tbl count is ' || l_amortization_tbl.count);
6325
6326 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6327 x_loan_amort_tbl := l_amortization_tbl;
6328 Exception
6329 When others then
6330 null;
6331
6332 end amortizeLoan;
6333
6334 /*=========================================================================
6335 || PUBLIC PROCEDURE loanProjection
6336 ||
6337 || DESCRIPTION
6338 ||
6339 || Overview: procedure will project an open ended loan
6340 || 1. Amortization UI - when creating a loan
6341 || 2. Billing Engine - to generate bills
6342 ||
6343 || Parameter: p_loan_details = details of the loan
6344 || p_rate_schedule = rate schedule for the loan
6345 || x_loan_amort_tbl => table of loan records
6346 ||
6347 || Source Tables: NA
6348 ||
6349 || Target Tables:
6350 ||
6351 ||
6352 || KNOWN ISSUES
6353 || Currently only support single rate
6354 || NOTES
6355 ||
6356 || MODIFICATION HISTORY
6357 || Date Author Description of Changes
6358 || 07/20/2005 11:35AM raverma Created
6359 *=======================================================================*/
6360 procedure loanProjection(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
6361 ,p_based_on_terms in varchar2
6362 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
6363 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
6364 is
6365 l_return_status varchar2(1);
6366 l_msg_count NUMBER;
6367 l_msg_data VARCHAR2(32767);
6368 -- loan_details
6369 l_loan_id number;
6370 l_original_loan_amount number; -- loan amount
6371 l_first_payment_date date;
6372 l_pay_in_arrears boolean;
6373 l_payment_frequency varchar2(30);
6374 l_day_count_method varchar2(30);
6375 l_intervals_original number;
6376 l_intervals number;
6377 l_intervals_remaining number;
6378 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
6379 l_precision number;
6380
6381 l_period_start_Date date;
6382 l_period_end_date date;
6383 l_periodic_rate number;
6384 l_maturity_date date;
6385
6386 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
6387 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
6388 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
6389 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
6390 l_loan_start_date date;
6391 l_num_pay_dates number; -- number of dates on installment schedule
6392 l_periodic_payment number;
6393 l_periodic_principal number;
6394 l_periodic_interest number;
6395 l_total_principal number;
6396 l_payment_number number;
6397 l_fee_amount number;
6398 l_begin_balance number;
6399 l_end_balance number;
6400 l_unbilled_principal number;
6401 l_unpaid_principal number;
6402 --l_open_rate_type varchar2(30);
6403 l_open_rate_change_frequency varchar2(30);
6404 l_open_index_rate_id number;
6405 l_open_index_date date;
6406 l_open_ceiling_rate number;
6407 l_open_floor_rate number;
6408 l_unpaid_interest number;
6409
6410 l_wtd_balance number;
6411 l_total number;
6412 l_interest_cumulative number;
6413 l_principal_cumulative number;
6414 l_fees_cumulative number;
6415 i number; -- for installments
6416 k number; -- for disbursements
6417 l_installment_number number;
6418 l_api_name varchar2(20);
6419 l_last_installment_billed number;
6420 l_rate_to_calculate number;
6421 l_disb_header_id number;
6422 l_disb_amount number;
6423 l_total_disbursed number;
6424 l_calc_method varchar2(30);
6425 l_compound_freq varchar2(30);
6426 l_annualized_rate number;
6427 l_billed varchar2(1);
6428 n number;
6429 l_norm_int_detail_str varchar2(2000);
6430 l_prev_end_balance number;
6431
6432 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
6433 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
6434 l_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
6435
6436 cursor c_total_disbursed(p_loan_id number, p_from_date date, p_to_date date) is
6437 select nvl(sum(header_amount), 0)
6438 from lns_disb_headers
6439 where loan_id = p_loan_id
6440 and trunc(payment_request_date) >= p_from_date
6441 and trunc(payment_request_date) < p_to_date;
6442
6443 begin
6444
6445 -- initialize all variables
6446 l_original_loan_amount := 0; -- loan amount
6447 l_periodic_payment := 0;
6448 l_periodic_principal := 0;
6449 l_periodic_interest := 0;
6450 l_total_principal := 0;
6451 l_payment_number := 0;
6452 l_fee_amount := 0;
6453 l_begin_balance := 0;
6454 l_unbilled_principal := 0;
6455 l_unpaid_principal := 0;
6456 l_total := 0;
6457 l_interest_cumulative := 0;
6458 l_principal_cumulative := 0;
6459 l_fees_cumulative := 0;
6460 i := 0;
6461 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
6462 l_rate_to_calculate := 0;
6463 l_total_disbursed := 0;
6464 l_api_name := 'loanProjection';
6465
6466 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6467
6468 l_payment_frequency := p_loan_details.payment_frequency;
6469 l_first_payment_date := p_loan_details.first_payment_date;
6470 l_original_loan_amount := p_loan_details.requested_amount; --funded_amount;
6471 l_maturity_date := p_loan_details.maturity_date;
6472 l_intervals := p_loan_details.number_installments;
6473 l_last_installment_billed := p_loan_details.last_installment_billed;
6474 l_day_count_method := p_loan_details.day_count_method;
6475 l_loan_start_date := p_loan_details.loan_start_date;
6476 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
6477 l_precision := p_loan_details.currency_precision;
6478 l_loan_id := p_loan_details.loan_id;
6479 -- use the projected rate which should be the last calculated rate on the loan
6480 l_periodic_rate := p_loan_details.OPEN_PROJECTED_INTEREST_RATE;
6481 l_calc_method := p_loan_details.CALCULATION_METHOD;
6482 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
6483 l_unpaid_principal := p_loan_details.unpaid_principal;
6484 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
6485
6486 -- get the interest rate schedule
6487 l_rate_tbl := p_rate_schedule;
6488 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
6489
6490 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- p_based_on_terms = ' || p_based_on_terms);
6491
6492 -- get payment schedule
6493 -- this will return the acutal dates that payments will be due on
6494 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
6495
6496 l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
6497 P_LOAN_ID => l_loan_id,
6498 P_PHASE => 'OPEN',
6499 P_COMPONENT => 'PRIN_INT');
6500
6501 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
6502 p_loan_start_date => l_loan_start_date,
6503 p_loan_maturity_date => l_maturity_date,
6504 p_freq_schedule_tbl => l_freq_schedule_tbl);
6505 /*
6506 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
6507 ,p_loan_maturity_date => l_maturity_date
6508 ,p_first_pay_date => l_first_payment_date
6509 ,p_num_intervals => l_intervals
6510 ,p_interval_type => l_payment_frequency
6511 ,p_pay_in_arrears => l_pay_in_arrears);
6512 */
6513 l_num_pay_dates := l_payment_tbl.count;
6514 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
6515
6516 begin
6517 if p_based_on_terms = 'CURRENT' then
6518
6519 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
6520 ,p_from_date => l_loan_start_date
6521 ,p_to_date => l_loan_start_date
6522 ,p_calc_method => 'ACTUAL'
6523 ,p_phase => 'OPEN'
6524 ,p_day_count_method => l_day_count_method
6525 ,p_adj_amount => 0
6526 ,x_wtd_balance => l_wtd_balance
6527 ,x_begin_balance => l_begin_balance
6528 ,x_end_balance => l_end_balance);
6529
6530 else
6531
6532 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
6533 ,p_from_date => l_loan_start_date
6534 ,p_to_date => l_loan_start_date
6535 ,p_calc_method => 'TARGET'
6536 ,p_phase => 'OPEN'
6537 ,p_day_count_method => l_day_count_method
6538 ,p_adj_amount => 0
6539 ,x_wtd_balance => l_wtd_balance
6540 ,x_begin_balance => l_begin_balance
6541 ,x_end_balance => l_end_balance);
6542
6543 end if;
6544 exception
6545 when others then
6546 FND_MESSAGE.SET_NAME('LNS', 'LNS_COMPUTE_BALANCE_ERROR');
6547 FND_MSG_PUB.ADD;
6548 LogMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
6549 RAISE FND_API.G_EXC_ERROR;
6550 end;
6551
6552 l_fees_tbl.delete;
6553 l_fee_amount := 0;
6554
6555 -- filling out basis table
6556 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
6557 l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
6558 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
6559 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
6560 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
6561 l_fee_basis_tbl(3).fee_basis_amount := l_end_balance;
6562 l_fee_basis_tbl(4).fee_basis_name := 'TOTAL_UNDISB_AMT';
6563 l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_end_balance;
6564
6565 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
6566 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
6567 ,p_loan_id => l_loan_id
6568 ,p_installment => 0
6569 ,p_fee_basis_tbl => l_fee_basis_tbl
6570 ,p_based_on_terms => p_based_on_terms
6571 ,p_phase => 'OPEN'
6572 ,x_fees_tbl => l_fees_tbl
6573 ,x_return_status => l_return_status
6574 ,x_msg_count => l_msg_count
6575 ,x_msg_data => l_msg_data);
6576
6577 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
6578 if l_return_status <> 'S' then
6579 RAISE FND_API.G_EXC_ERROR;
6580 end if;
6581
6582 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
6583
6584 for k in 1..l_fees_tbl.count loop
6585 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
6586 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
6587 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
6588 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
6589 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
6590 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
6591 end loop;
6592 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
6593
6594 if l_fee_amount > 0 then
6595
6596 i := i + 1;
6597 l_amortization_rec.installment_number := 0;
6598 l_amortization_rec.due_date := l_loan_start_date;
6599 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
6600 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
6601 l_amortization_rec.principal_amount := 0;
6602 l_amortization_rec.interest_amount := 0;
6603 l_amortization_rec.fee_amount := l_fee_amount;
6604 l_amortization_rec.other_amount := 0;
6605 l_amortization_rec.begin_balance := l_begin_balance;
6606 l_amortization_rec.end_balance := l_end_balance;
6607 l_amortization_rec.interest_cumulative := 0;
6608 l_amortization_rec.principal_cumulative := 0;
6609 l_amortization_rec.fees_cumulative := l_fee_amount;
6610 l_amortization_rec.other_cumulative := 0;
6611 l_amortization_rec.rate_id := 0;
6612 l_amortization_rec.SOURCE := 'PREDICTED';
6613 -- add the record to the amortization table
6614 l_amortization_rec.total := l_fee_amount;
6615 l_amortization_rec.UNPAID_PRIN := 0;
6616 l_amortization_rec.UNPAID_INT := 0;
6617 l_amortization_rec.INTEREST_RATE := l_rate_tbl(1).annual_rate;
6618 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
6619 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
6620 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
6621 l_amortization_rec.PENAL_INT_AMOUNT := 0;
6622 l_amortization_rec.NORMAL_INT_DETAILS := null;
6623 l_amortization_rec.ADD_PRIN_INT_DETAILS := null;
6624 l_amortization_rec.ADD_INT_INT_DETAILS := null;
6625 l_amortization_rec.PENAL_INT_DETAILS := null;
6626 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
6627 l_amortization_rec.DISBURSEMENT_AMOUNT := l_end_balance;
6628 l_amortization_rec.FUNDED_AMOUNT := l_end_balance;
6629 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
6630 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
6631 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
6632 l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
6633 l_amortization_rec.CAP_INT_AMOUNT := 0;
6634 l_amortization_rec.CAP_INT_DETAILS := null;
6635 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
6636
6637 l_amortization_tbl(i) := l_amortization_rec;
6638 end if;
6639
6640 l_prev_end_balance := 0;
6641 -- loop to build the amortization schedule
6642 for l_installment_number in 1..l_num_pay_dates
6643 loop
6644
6645 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' -----CALCULATING -----> installment #' || l_installment_number);
6646 i := i + 1;
6647 l_periodic_interest := 0;
6648 l_fee_amount := 0;
6649 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
6650 l_norm_int_detail_str := null;
6651
6652 -- get the weighted balance for the period
6653 begin
6654 if p_based_on_terms = 'CURRENT' then
6655
6656 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
6657 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
6658 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
6659 ,p_calc_method => 'ACTUAL'
6660 ,p_phase => 'OPEN'
6661 ,p_day_count_method => l_day_count_method
6662 ,p_adj_amount => 0
6663 ,x_wtd_balance => l_wtd_balance
6664 ,x_begin_balance => l_begin_balance
6665 ,x_end_balance => l_end_balance);
6666
6667 else
6668
6669 lns_financials.getWeightedBalance(p_loan_id => l_loan_id
6670 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
6671 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
6672 ,p_calc_method => 'TARGET'
6673 ,p_phase => 'OPEN'
6674 ,p_day_count_method => l_day_count_method
6675 ,p_adj_amount => 0
6676 ,x_wtd_balance => l_wtd_balance
6677 ,x_begin_balance => l_begin_balance
6678 ,x_end_balance => l_end_balance);
6679
6680 end if;
6681 exception
6682 when others then
6683 FND_MESSAGE.SET_NAME('LNS', 'LNS_COMPUTE_BALANCE_ERROR');
6684 FND_MSG_PUB.ADD;
6685 LogMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
6686 RAISE FND_API.G_EXC_ERROR;
6687 end;
6688
6689 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - l_wtd_balance = ' || l_wtd_balance);
6690
6691 -- now we will caculate the interest due for this period
6692 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_wtd_balance);
6693
6694 l_rate_details := getRateDetails(p_installment => l_installment_number
6695 ,p_rate_tbl => l_rate_tbl);
6696
6697 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
6698 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
6699 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
6700
6701 l_annualized_rate := l_rate_details.annual_rate;
6702
6703 -- recalculate periodic rate for each period if day counting methodolgy varies
6704 if (l_calc_method = 'SIMPLE') then
6705
6706 l_periodic_rate := lns_financials.getPeriodicRate(
6707 p_payment_freq => l_payment_frequency
6708 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
6709 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
6710 ,p_annualized_rate => l_annualized_rate
6711 ,p_days_count_method => l_day_count_method
6712 ,p_target => 'INTEREST');
6713
6714 elsif (l_calc_method = 'COMPOUND') then
6715
6716 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
6717 ,p_payment_freq => l_payment_frequency
6718 ,p_annualized_rate => l_annualized_rate --p_loan_details.OPEN_PROJECTED_INTEREST_RATE
6719 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
6720 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
6721 ,p_days_count_method => l_day_count_method
6722 ,p_target => 'INTEREST');
6723
6724 end if;
6725 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate rate = ' || l_periodic_rate);
6726
6727 -- if we are going to compound, then based on compounding the amount should be passed to calculateInterest call here.
6728 -- how do we determine what the amount to compound on
6729 -- for example: compound daily at .5% over 30 day period
6730 l_periodic_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
6731 ,p_periodic_rate => l_periodic_rate
6732 ,p_compounding_period => null);
6733
6734 l_periodic_interest := round(l_periodic_interest, l_precision);
6735 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
6736
6737 l_norm_int_detail_str :=
6738 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
6739 ' * Balance ' || l_wtd_balance ||
6740 ' * Rate ' || l_annualized_rate || '%';
6741 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
6742
6743 --mark
6744 if l_installment_number = p_loan_details.number_installments and
6745 (p_loan_details.OPEN_TO_TERM_FLAG = 'N' OR p_loan_details.SECONDARY_STATUS = 'REMAINING_DISB_CANCELLED') then
6746 l_periodic_principal := p_loan_details.funded_amount;
6747 else
6748 l_periodic_principal := 0;
6749 end if;
6750
6751 -- rest of the record can be built after fees are calculated
6752 l_amortization_rec.installment_number := l_installment_number;
6753 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
6754 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
6755 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
6756 l_amortization_rec.principal_amount := l_periodic_principal;
6757 l_amortization_rec.interest_amount := l_periodic_interest;
6758 l_amortization_rec.begin_balance := l_begin_balance;
6759 l_amortization_rec.end_balance := l_end_balance;
6760 l_amortization_rec.other_amount := 0;
6761 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
6762 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
6763 l_amortization_rec.INTEREST_RATE := l_annualized_rate; --p_loan_details.OPEN_PROJECTED_INTEREST_RATE;
6764 l_amortization_rec.NORMAL_INT_AMOUNT := l_periodic_interest;
6765 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
6766 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
6767 l_amortization_rec.PENAL_INT_AMOUNT := 0;
6768 l_amortization_rec.NORMAL_INT_DETAILS := l_norm_int_detail_str;
6769 l_amortization_rec.ADD_PRIN_INT_DETAILS := null;
6770 l_amortization_rec.ADD_INT_INT_DETAILS := null;
6771 l_amortization_rec.PENAL_INT_DETAILS := null;
6772 l_amortization_rec.PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
6773 l_amortization_rec.DISBURSEMENT_AMOUNT := l_end_balance - l_prev_end_balance;
6774 l_amortization_rec.FUNDED_AMOUNT := l_end_balance;
6775 l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
6776 l_amortization_rec.DEFERRED_INT_AMOUNT := 0;
6777 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
6778 l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
6779 l_amortization_rec.CAP_INT_AMOUNT := 0;
6780 l_amortization_rec.CAP_INT_DETAILS := null;
6781 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
6782
6783 if l_amortization_rec.FUNDED_AMOUNT is null then
6784 l_amortization_rec.FUNDED_AMOUNT := 0;
6785 end if;
6786
6787 l_fees_tbl.delete;
6788 l_fee_amount := 0;
6789
6790 -- filling out basis table
6791 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
6792 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
6793 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
6794 l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
6795 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
6796 l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
6797 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN';
6798 l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
6799 l_fee_basis_tbl(5).fee_basis_name := 'OVERDUE_PRIN_INT';
6800 l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
6801 l_fee_basis_tbl(6).fee_basis_name := 'IND_DISB_AMT';
6802 l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
6803 l_fee_basis_tbl(7).fee_basis_name := 'TOTAL_UNDISB_AMT';
6804 l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
6805 l_fee_basis_tbl(8).fee_basis_name := 'OVERDUE_INT';
6806 l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
6807 l_fee_basis_tbl(9).fee_basis_name := 'CURR_LOAN';
6808 l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
6809
6810 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
6811 LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list => FND_API.G_FALSE
6812 ,p_loan_id => l_loan_id
6813 ,p_installment => l_installment_number
6814 ,p_fee_basis_tbl => l_fee_basis_tbl
6815 ,p_based_on_terms => p_based_on_terms
6816 ,p_phase => 'OPEN'
6817 ,x_fees_tbl => l_fees_tbl
6818 ,x_return_status => l_return_status
6819 ,x_msg_count => l_msg_count
6820 ,x_msg_data => l_msg_data);
6821
6822 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
6823 if l_return_status <> 'S' then
6824 RAISE FND_API.G_EXC_ERROR;
6825 end if;
6826
6827 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
6828
6829 for k in 1..l_fees_tbl.count loop
6830 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
6831 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
6832 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
6833 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
6834 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
6835 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
6836 end loop;
6837 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for this installment = ' || l_fee_amount);
6838
6839 l_total := l_fee_amount + l_periodic_principal + l_periodic_interest;
6840 l_amortization_rec.total := l_total;
6841 l_amortization_rec.fee_amount := l_fee_amount;
6842 l_prev_end_balance := l_end_balance;
6843
6844 -- running totals calculated here
6845 --l_principal_cumulative := l_principal_cumulative + l_periodic_principal;
6846 l_interest_cumulative := l_interest_cumulative + l_periodic_interest;
6847 l_fees_cumulative := l_fees_cumulative + l_fee_amount;
6848
6849 l_amortization_rec.interest_cumulative := l_interest_cumulative;
6850 l_amortization_rec.principal_cumulative := l_principal_cumulative;
6851 l_amortization_rec.fees_cumulative := l_fees_cumulative;
6852 l_amortization_rec.SOURCE := 'PREDICTED';
6853
6854 -- add the record to the amortization table
6855 l_amortization_tbl(i) := l_amortization_rec;
6856
6857 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: due date ' || l_amortization_rec.due_date);
6858 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_principal ' || l_amortization_rec.principal_amount);
6859 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_interest ' || l_amortization_rec.interest_amount);
6860 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fee_amount is ' || l_amortization_rec.fee_amount);
6861 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: total is ' || l_amortization_rec.fee_amount);
6862 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: begin_balance is ' || l_amortization_rec.begin_balance);
6863 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: end_balance is ' || l_amortization_rec.end_balance);
6864 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: interest_cumulative is ' || l_amortization_rec.interest_cumulative);
6865 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: principal_cumulative is ' || l_amortization_rec.principal_cumulative);
6866 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fees_cumulative is ' || l_amortization_rec.fees_cumulative);
6867 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
6868
6869 end loop;
6870 --printAmortizationTable(p_amort_tbl => l_amortization_tbl);
6871
6872 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT = ' || l_amortization_tbl.count);
6873 x_loan_amort_tbl := l_amortization_tbl;
6874
6875 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6876
6877 Exception
6878 WHEN FND_API.G_EXC_ERROR THEN
6879 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6880
6881 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6882 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
6883
6884 WHEN OTHERS THEN
6885 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6886
6887 end loanProjection;
6888
6889 /*=========================================================================
6890 || PUBLIC PROCEDURE runLoanProjection
6891 ||
6892 || DESCRIPTION
6893 ||
6894 || Overview: procedure will run a loan projection ||
6895 || Parameter: loan_id
6896 ||
6897 || Source Tables: LNS_LOAN_HEADERS, LNS_TERMS, LNS_RATE_SCHEDULES,
6898 || LNS_DISB_HEADERS, LNS_DISB_LINES
6899 ||
6900 || Target Tables: None
6901 ||
6902 || Return value: x_amort_tbl is table of amortization records
6903 ||
6904 || KNOWN ISSUES
6905 ||
6906 || NOTES
6907 ||
6908 || MODIFICATION HISTORY
6909 || Date Author Description of Changes
6910 || 07/18/2005 11:35AM raverma Created
6911 || 08/29/2005 raverma throw error if invalid dates
6912 *=======================================================================*/
6913 procedure runOpenProjection(p_init_msg_list IN VARCHAR2
6914 ,p_loan_ID IN NUMBER
6915 ,p_based_on_terms IN VARCHAR2
6916 ,x_amort_tbl OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_TBL
6917 ,x_return_status OUT NOCOPY VARCHAR2
6918 ,x_msg_count OUT NOCOPY NUMBER
6919 ,x_msg_data OUT NOCOPY VARCHAR2)
6920 is
6921
6922 l_api_name varchar2(25);
6923 l_api_version_number number;
6924 l_return_status VARCHAR2(1);
6925 l_msg_count NUMBER;
6926 l_msg_data VARCHAR2(32767);
6927
6928 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
6929 l_amort_tbl2 LNS_FINANCIALS.AMORTIZATION_TBL;
6930 l_total_amortization LNS_FINANCIALS.AMORTIZATION_REC;
6931 b_showActual boolean := false;
6932 l_last_installment_billed number;
6933
6934 l_num_records number;
6935 i number;
6936 m number;
6937 l_records_to_copy number;
6938 l_num_installments number;
6939 l_num_rows number;
6940 l_manual_fee_amount number;
6941 l_records_to_destroy number;
6942 l_start_date number;
6943 l_funded_amount number;
6944 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
6945 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
6946 l_disb_amount number;
6947 l_invalid_disb number;
6948
6949 cursor c_disbursements(p_loan_id number) is
6950 select nvl(sum(header_amount), 0)
6951 from lns_disb_headers
6952 where loan_id = p_loan_id;
6953
6954 BEGIN
6955 -- Standard Start of API savepoint
6956 SAVEPOINT runLoanProjection_PVT;
6957 l_api_name := 'runLoanProjection';
6958 i := 0;
6959 l_manual_fee_amount := 0;
6960
6961 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6962
6963 -- Initialize message list IF p_init_msg_list is set to TRUE.
6964 IF FND_API.to_Boolean( p_init_msg_list ) THEN
6965 FND_MSG_PUB.initialize;
6966 END IF;
6967
6968 -- Initialize API return status to SUCCESS
6969 x_return_status := FND_API.G_RET_STS_SUCCESS;
6970
6971 --
6972 -- Api body
6973 -- ----------------------------------------------------------------
6974 -- validate loan_id
6975 lns_utility_pub.validate_any_id(p_api_version => 1.0
6976 ,p_init_msg_list => p_init_msg_list
6977 ,x_msg_count => l_msg_count
6978 ,x_msg_data => l_msg_data
6979 ,x_return_status => l_return_status
6980 ,p_col_id => p_loan_id
6981 ,p_col_name => 'LOAN_ID'
6982 ,p_table_name => 'LNS_LOAN_HEADERS_ALL');
6983
6984 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
6985 FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
6986 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
6987 FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
6988 FND_MSG_PUB.ADD;
6989 RAISE FND_API.G_EXC_ERROR;
6990 end if;
6991
6992 -- check if disbursements exist and is amount > 0 as per karthik instructions
6993 open c_disbursements(p_loan_id);
6994 fetch c_disbursements into l_disb_amount;
6995 close c_disbursements;
6996
6997 if l_invalid_disb > 0 then
6998 FND_MESSAGE.SET_NAME('LNS', 'LNS_DISB_REQ_DATE_ERR');
6999 FND_MSG_PUB.ADD;
7000 RAISE FND_API.G_EXC_ERROR;
7001 end if;
7002
7003 if l_disb_amount > 0 then
7004 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'OPEN');
7005 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
7006 ,p_based_on_terms => p_based_on_terms
7007 ,p_phase => 'OPEN');
7008
7009 -- call projection API
7010 lns_financials.loanProjection(p_loan_details => l_loan_details
7011 ,p_based_on_terms => p_based_on_terms
7012 ,p_rate_schedule => l_rate_tbl
7013 ,x_loan_amort_tbl => l_amort_tbl);
7014
7015 -- delete predicted records based on ORIGINAL amortization
7016 if p_based_on_terms = 'CURRENT' and
7017 l_loan_details.LOAN_STATUS NOT IN ('INCOMPLETE','DELETED','REJECTED','PENDING','APPROVED')
7018 then
7019 l_num_records := l_amort_tbl.count;
7020 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - amortization returns # records '|| l_num_records);
7021 l_last_installment_billed := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER_EXT_3(p_loan_id, 'OPEN');
7022 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - last installment billed '|| l_last_installment_billed);
7023
7024 -- copy the records not billed to a temp collection
7025 m := 0;
7026 for i in 1..l_num_records
7027 loop
7028 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - copying record ' || i);
7029 if l_amort_tbl(i).installment_number > l_last_installment_billed then
7030 m := m + 1;
7031 l_amort_tbl2(m) := l_amort_tbl(i);
7032 end if;
7033 end loop;
7034
7035 -- copy back to original table
7036 l_amort_tbl.delete;
7037 m := 0;
7038 for i in 1..l_amort_tbl2.count
7039 loop
7040 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - re-copying record ' || i);
7041 m := m + 1;
7042 l_amort_tbl(m) := l_amort_tbl2(i);
7043 end loop;
7044 end if;
7045 end if; -- disb amount > 0
7046 x_amort_tbl := l_amort_tbl;
7047 --
7048 -- End of API body
7049 --
7050
7051 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7052
7053 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7054
7055 EXCEPTION
7056 WHEN FND_API.G_EXC_ERROR THEN
7057 ROLLBACK TO runLoanProjection_PVT;
7058 x_return_status := FND_API.G_RET_STS_ERROR;
7059 x_msg_count := l_msg_count;
7060 x_msg_data := l_msg_data;
7061 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7062 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7063
7064 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
7065 ROLLBACK TO runLoanProjection_PVT;
7066 x_return_status := FND_API.G_RET_STS_ERROR;
7067 x_msg_count := l_msg_count;
7068 x_msg_data := l_msg_data;
7069 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7070 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7071
7072 WHEN OTHERS THEN
7073 ROLLBACK TO runLoanProjection_PVT;
7074 x_return_status := FND_API.G_RET_STS_ERROR;
7075 x_msg_count := l_msg_count;
7076 x_msg_data := l_msg_data;
7077 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7078 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7079
7080 END runOpenProjection;
7081
7082 ---------------------------------------------------------------------------
7083 --- rate routines
7084 ---------------------------------------------------------------------------
7085 /*=========================================================================
7086 || PUBLIC PROCEDURE getRateSchedule - R12
7087 ||
7088 || DESCRIPTION
7089 ||
7090 || Overview: this api is used to get the rate schedule for a loan
7091 ||
7092 || Parameter: loan_id,
7093 || p_phase 'OPEN' or 'TERM'
7094 ||
7095 || Source Tables: LNS_RATE_SCHEDULES, LNS_TERMS, LNS_LOAN_HEADER_ALL
7096 ||
7097 || Target Tables: NA
7098 ||
7099 || Return value: rate_schedule_tbl which is defined as
7100 || TYPE INTEREST_RATE_REC IS RECORD(
7101 || BEGIN_DATE DATE,
7102 || END_DATE DATE,
7103 || ANNUAL_RATE NUMBER);
7104 || TYPE RATE_SCHEDULE_TBL IS TABLE OF INTEREST_RATE_REC INDEX BY BINARY_INTEGER;
7105 ||
7106 || KNOWN ISSUES
7107 ||
7108 || NOTES
7109 || NOTE: INSTALLMENT_NUMBER WILL NOT GET YOU THE GIVEN INSTALLMENT
7110 || NUMBER CORRESPONDING ON THE LOAN AMORTIZATION SCHEDULE
7111 ||
7112 || MODIFICATION HISTORY
7113 || Date Author Description of Changes
7114 || 07/18/2005 6:42PM raverma Created
7115 *=======================================================================*/
7116 function getRateSchedule(p_loan_id in number
7117 ,p_phase in varchar2) return LNS_FINANCIALS.RATE_SCHEDULE_TBL
7118 is
7119
7120 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
7121 l_rate_id number;
7122 l_annual_rate number;
7123 l_spread number;
7124 l_start_date date;
7125 l_begin_installment number;
7126 l_end_installment number;
7127 l_interest_only_flag varchar2(1);
7128 l_floating_flag varchar2(1);
7129 l_end_date date;
7130 i number;
7131 l_api_name varchar2(20);
7132
7133 cursor c_rate_schedule (p_loan_id number, p_phase varchar2)
7134 is
7135 select rate_id
7136 ,current_interest_rate
7137 ,nvl(spread, 0)
7138 ,trunc(start_date_active)
7139 ,trunc(end_date_active)
7140 ,begin_installment_number
7141 ,end_installment_number
7142 ,nvl(interest_only_flag, 'N')
7143 ,nvl(floating_flag, 'N')
7144 from lns_loan_headers_all h,
7145 lns_terms t,
7146 lns_rate_schedules rs
7147 where h.loan_id = p_loan_id
7148 and h.loan_id = t.loan_id
7149 and t.term_id = rs.term_id
7150 and rs.end_date_active is null
7151 and nvl(phase, 'TERM') = p_phase
7152 order by begin_installment_number
7153 ,start_date_active;
7154
7155 begin
7156
7157 i := 0;
7158 l_api_name := 'getRateSchedule';
7159 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7160
7161 Begin
7162 OPEN c_rate_schedule(p_loan_id, p_phase);
7163 LOOP
7164 i := i + 1;
7165 FETCH c_rate_schedule INTO
7166 l_rate_id
7167 ,l_annual_rate
7168 ,l_spread
7169 ,l_start_date
7170 ,l_end_date
7171 ,l_begin_installment
7172 ,l_end_installment
7173 ,l_interest_only_flag
7174 ,l_floating_flag;
7175 EXIT WHEN c_rate_schedule%NOTFOUND;
7176 l_rate_tbl(i).rate_id := l_rate_id;
7177 l_rate_tbl(i).annual_rate := l_annual_rate;
7178 l_rate_tbl(i).spread := l_spread;
7179 l_rate_tbl(i).begin_date := l_start_date;
7180 l_rate_tbl(i).end_date := l_end_date;
7181 l_rate_tbl(i).begin_installment_number := l_begin_installment;
7182 l_rate_tbl(i).end_installment_number := l_end_installment;
7183 l_rate_tbl(i).interest_only_flag := l_interest_only_flag;
7184 l_rate_tbl(i).FLOATING_FLAG := l_floating_flag;
7185 END LOOP;
7186 Exception
7187 When No_Data_Found then
7188 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_RATES');
7189 FND_MSG_PUB.Add;
7190 RAISE FND_API.G_EXC_ERROR;
7191 End;
7192
7193 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7194
7195 return l_rate_tbl;
7196
7197 Exception
7198 WHEN FND_API.G_EXC_ERROR THEN
7199 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7200
7201 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
7202 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
7203
7204 WHEN OTHERS THEN
7205 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7206
7207 end getRateSchedule;
7208
7209 /*=========================================================================
7210 || PUBLIC PROCEDURE getWeightedRate
7211 ||
7212 || DESCRIPTION
7213 ||
7214 || Overview: Calculates the weighted average interest rate for a period
7215 || of time for a table of rates
7216 ||
7217 || Parameter: p_start_date => date to begin periodic rate (last interest accrual date for loan payoff)
7218 || p_end_date => date to end periodic rate
7219 || p_rate_tbl => table of rate schedules
7220 ||
7221 || Source Tables: NA
7222 ||
7223 || Target Tables: NA
7224 ||
7225 || Return value: Annualized Rate weighted by rates
7226 ||
7227 || KNOWN ISSUES
7228 || rounding? only works to the daily level
7229 || days count method is unclear? (see function intervalsInPeriod)
7230 || any dates left out will be assumed to be interest rate of 0
7231 ||
7232 || there are 9 scenarios possible:
7233 ||
7234 || P_Start_Date p_End_date
7235 || +------------------------------------+ (time line to get periodic rate)
7236 ||
7237 || Scen 1: (rate tbl matches exactly)
7238 || +------------------------------------+ (time line to get periodic rate)
7239 || +------------------------------------+ (rate table time line)
7240 ||
7241 || Scen 2: (rate tbl further than end date)
7242 || +------------------------------------+ (time line to get periodic rate)
7243 || +------------------------------------------+ (rate table time line)
7244 ||
7245 || Scen 3: (rate tbl shorter than end date)
7246 || +------------------------------------+ (time line to get periodic rate)
7247 || +-------------------------------+ (rate table time line)
7248 ||
7249 || Scen 4: (rate tbl before start date)
7250 || +------------------------------------+ (time line to get periodic rate)
7251 || +----------------------------------------+ (rate table time line)
7252 ||
7253 || Scen 5: (rate tbl before start date)
7254 || +------------------------------------+ (time line to get periodic rate)
7255 || +----------------------------------------+ (rate table time line)
7256 ||
7257 || Scen 6: (rate tbl after start date)
7258 || +------------------------------------+ (time line to get periodic rate)
7259 || +-------------------------------+ (rate table time line)
7260 ||
7261 || Scen 7: (rate tbl is shorter than period)
7262 || +------------------------------------+ (time line to get periodic rate)
7263 || +-------------------------+ (rate table time line)
7264 ||
7265 || Scen 8: (rate tbl is longer than period)
7266 || +------------------------------------+ (time line to get periodic rate)
7267 || +-------------------------------------------------------+ (rate table time line)
7268 ||
7269 || Scen 9: (rate tbl is not contiguous)
7270 || +------------------------------------+ (time line to get periodic rate)
7271 || +--+ +---+ +------+ +-----+ (rate table time line)
7272 ||
7273 ||
7274 || only scenarios 3, 6, 7, 9 do we have periods to assume that rate is = 0
7275 || in all other scenarios the rate table covers the period of time allotted
7276 ||
7277 || also, it is assumed that the rate table is a contiguous period of time
7278 ||
7279 || NOTES
7280 ||
7281 || there are implicit assumptions that CANNOT be made when calculating
7282 || wtd avg interest for a given period.
7283 || for example, you cannot simply put in a
7284 || [ (# days @ rate 1 X rate 1) +
7285 || (# days @ rate 2 X rate 2) +
7286 || (# days @ rate 3 X rate 3) + ]
7287 || / total # days in rate schedule
7288 || because we may have p_start_date > rate 1 start date and
7289 || p_end_date < rate 3 end date
7290 ||
7291 ||
7292 || MODIFICATION HISTORY
7293 || Date Author Description of Changes
7294 || 2/09/2003 1:51PM raverma Created
7295 ||
7296 *=======================================================================*/
7297 function getWeightedRate(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
7298 ,p_start_date in date
7299 ,p_end_date in date
7300 ,p_rate_tbl in LNS_FINANCIALS.RATE_SCHEDULE_TBL) return number
7301 is
7302 l_api_name varchar2(25);
7303 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
7304 l_pay_dates LNS_FINANCIALS.DATE_TBL;
7305 l_days_at_rate number;
7306 l_weighted_rate number;
7307 l_running_weight number;
7308 l_total_days number;
7309 l_num_pay_dates number;
7310 l_period_start_date date;
7311 l_period_end_date date;
7312 --l_pay_in_arrears boolean;
7313 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
7314 l_exit_loop boolean;
7315 l_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
7316 l_int_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
7317 l_prin_freq_schedule_tbl LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
7318
7319 begin
7320
7321 l_api_name := 'getWeightedRate';
7322 l_days_at_rate := 0;
7323 l_weighted_rate := 0;
7324 l_running_weight := 0;
7325 l_total_days := 0;
7326 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7327 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' start date ' || p_start_date);
7328 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' end date ' || p_end_date);
7329 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate table count ' || p_rate_tbl.count);
7330
7331 if p_loan_details.custom_schedule = 'N' then
7332
7333 if p_loan_details.PAYMENT_CALC_METHOD = 'SEPARATE_SCHEDULES' then
7334
7335 l_int_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
7336 P_LOAN_ID => p_loan_details.LOAN_ID,
7337 P_PHASE => 'TERM',
7338 P_COMPONENT => 'INT');
7339
7340 l_prin_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
7341 P_LOAN_ID => p_loan_details.LOAN_ID,
7342 P_PHASE => 'TERM',
7343 P_COMPONENT => 'PRIN');
7344
7345 l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
7346 p_loan_start_date => p_loan_details.loan_start_date,
7347 p_loan_maturity_date => p_loan_details.maturity_date,
7348 p_prin_freq_schedule_tbl => l_prin_freq_schedule_tbl,
7349 p_int_freq_schedule_tbl => l_int_freq_schedule_tbl);
7350 /*
7351 l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
7352 p_loan_start_date => p_loan_details.loan_start_date
7353 ,p_loan_maturity_date => p_loan_details.maturity_date
7354 ,p_int_first_pay_date => p_loan_details.first_payment_date
7355 ,p_int_num_intervals => p_loan_details.number_installments
7356 ,p_int_interval_type => p_loan_details.payment_frequency
7357 ,p_int_pay_in_arrears => p_loan_details.pay_in_arrears_boolean
7358 ,p_prin_first_pay_date => p_loan_details.PRIN_FIRST_PAY_DATE
7359 ,p_prin_num_intervals => p_loan_details.PRIN_NUMBER_INSTALLMENTS
7360 ,p_prin_interval_type => p_loan_details.PRIN_PAYMENT_FREQUENCY
7361 ,p_prin_pay_in_arrears => p_loan_details.PRIN_PAY_IN_ARREARS_BOOL);
7362 */
7363 else
7364
7365 l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
7366 P_LOAN_ID => p_loan_details.LOAN_ID,
7367 P_PHASE => 'TERM',
7368 P_COMPONENT => 'PRIN_INT');
7369
7370 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
7371 p_loan_start_date => p_loan_details.loan_start_date,
7372 p_loan_maturity_date => p_loan_details.maturity_date,
7373 p_freq_schedule_tbl => l_freq_schedule_tbl);
7374 /*
7375 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => p_loan_details.loan_start_date
7376 ,p_loan_maturity_date => p_loan_details.maturity_date
7377 ,p_first_pay_date => p_loan_details.first_payment_date
7378 ,p_num_intervals => p_loan_details.number_installments
7379 ,p_interval_type => p_loan_details.payment_frequency
7380 ,p_pay_in_arrears => p_loan_details.pay_in_arrears_boolean);
7381 */
7382 end if;
7383
7384 else
7385
7386 -- build custom payment schedule
7387 l_payment_tbl := LNS_CUSTOM_PUB.buildCustomPaySchedule(p_loan_details.LOAN_ID);
7388
7389 end if;
7390
7391 l_num_pay_dates := l_payment_tbl.count;
7392 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' num pay dates is ' || l_num_pay_dates);
7393 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' num installments is ' || p_loan_details.number_installments);
7394
7395 -- for k in 1..p_loan_details.number_installments
7396 for k in 1..l_num_pay_dates
7397 loop
7398
7399 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Period: ' || k);
7400 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' period start is ' || l_payment_tbl(k).period_begin_date);
7401 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' period end is ' || l_payment_tbl(k).period_end_date);
7402 -- check to see if this period is covered in the time
7403
7404 l_exit_loop := false;
7405 l_period_start_date := null;
7406 if p_start_date >= l_payment_tbl(k).period_begin_date and
7407 p_start_date < l_payment_tbl(k).period_end_date then
7408 l_period_start_date := p_start_date;
7409 elsif p_start_date < l_payment_tbl(k).period_begin_date and
7410 p_start_date < l_payment_tbl(k).period_end_date then
7411 l_period_start_date := l_payment_tbl(k).period_begin_date;
7412 end if;
7413
7414 l_period_end_date := null;
7415 if p_end_date >= l_payment_tbl(k).period_begin_date and
7416 p_end_date <= l_payment_tbl(k).period_end_date then
7417 l_period_end_date := p_end_date;
7418 l_exit_loop := true;
7419 elsif p_end_date >= l_payment_tbl(k).period_begin_date and
7420 p_end_date > l_payment_tbl(k).period_end_date then
7421 if k = l_num_pay_dates then
7422 l_period_end_date := p_end_date;
7423 l_exit_loop := true;
7424 else
7425 l_period_end_date := l_payment_tbl(k).period_end_date;
7426 end if;
7427 end if;
7428
7429 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_period_start_date: ' || l_period_start_date);
7430 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_period_end_date: ' || l_period_end_date);
7431
7432 if l_period_start_date is not null and l_period_end_date is not null then
7433
7434 l_days_at_rate := LNS_FIN_UTILS.getDayCount(p_start_date => l_period_start_date
7435 ,p_end_date => l_period_end_date
7436 ,p_day_count_method => p_loan_details.day_count_method);
7437 l_rate_details := getRateDetails(p_installment => k
7438 ,p_rate_tbl => p_rate_tbl);
7439
7440 l_total_days := l_total_days + l_days_at_rate;
7441 l_running_weight := l_running_weight + (l_rate_details.annual_rate * l_days_at_rate);
7442
7443 end if;
7444
7445 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_days_at_rate: ' || l_days_at_rate);
7446 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_rate: ' || l_rate_details.annual_rate);
7447 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_running_weight: ' || l_running_weight);
7448
7449 if l_exit_loop then
7450 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Exiting loop');
7451 exit;
7452 end if;
7453
7454 end loop;
7455
7456 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' total days is ' || l_total_days);
7457
7458 if l_total_days = 0 then
7459 l_total_days := 1;
7460 end if;
7461
7462 l_weighted_rate := l_running_weight / l_total_days;
7463 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_weighted_rate ' || l_weighted_rate);
7464
7465 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7466
7467 return l_weighted_rate;
7468
7469 end getWeightedRate;
7470
7471
7472 /*=========================================================================
7473 || PUBLIC PROCEDURE getRateDetails
7474 ||
7475 || DESCRIPTION
7476 ||
7477 || Overview: return a interest_rate_record for a given installment
7478 ||
7479 ||
7480 || Parameter: p_installment => installment to get rate details
7481 || p_rate_tbl => table of interest rates
7482 ||
7483 ||
7484 || Return value: NA
7485 ||
7486 || Source Tables: NA
7487 ||
7488 || Target Tables: NA
7489 ||
7490 || KNOWN ISSUES
7491 || if no rates can be found in set of give dates a rate of 0 is returned
7492 ||
7493 || NOTES
7494 ||
7495 || MODIFICATION HISTORY
7496 || Date Author Description of Changes
7497 || 2/24/2003 4:28PM raverma Created
7498 *=======================================================================*/
7499 function getRateDetails(p_installment IN NUMBER
7500 ,p_rate_tbl IN LNS_FINANCIALS.RATE_SCHEDULE_TBL) return LNS_FINANCIALS.INTEREST_RATE_REC
7501 is
7502 x number;
7503 l_rate number;
7504 l_rate_rec LNS_FINANCIALS.INTEREST_RATE_REC;
7505 l_api_name varchar2(25);
7506
7507 begin
7508
7509 l_rate := 0;
7510 l_api_name := 'getRateDetails2';
7511 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7512 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - installment ' || p_installment);
7513
7514 x := 1;
7515 Begin
7516 LOOP
7517 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - match row ' || x);
7518 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate ' || p_rate_tbl(x).annual_rate);
7519 l_rate := p_rate_tbl(x).annual_rate;
7520 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate 1');
7521 l_rate_rec := p_rate_tbl(x);
7522 EXIT WHEN p_installment >= p_rate_tbl(x).begin_installment_number and
7523 p_installment <= p_rate_tbl(x).end_installment_number;
7524 x := x + 1;
7525 END LOOP;
7526 Exception
7527 When No_Data_found then
7528 -- when there is not a rate for this period it is assumed to be zero (see scenarios 3, 6, 8 in comments on getWeightedRate)
7529 --l_rate := 0;
7530 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - no rate found for period');
7531 when others then
7532 l_rate := 0;
7533
7534 End;
7535
7536 if l_rate = 0 then
7537 l_rate_rec.annual_rate := 0;
7538 end if;
7539
7540 --logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7541 return l_rate_rec;
7542
7543 end getRateDetails;
7544
7545
7546 /*=========================================================================
7547 | PUBLIC PROCEDURE getRateDetails
7548 ||
7549 || DESCRIPTION
7550 ||
7551 || Overview: return a interest_rate_record for a given date
7552 ||
7553 ||
7554 || Parameter: p_date => to get rate details
7555 || p_rate_tbl => table of interest rates
7556 ||
7557 ||
7558 || Return value: NA
7559 ||
7560 || Source Tables: NA
7561 ||
7562 || Target Tables: NA
7563 ||
7564 || KNOWN ISSUES
7565 || if no rates can be found in set of give dates a rate of 0 is returned
7566 ||
7567 || NOTES
7568 ||
7569 || MODIFICATION HISTORY
7570 || Date Author Description of Changes
7571 || 2/24/2003 4:28PM raverma Created
7572 ||
7573 *=======================================================================*/
7574 function getRateDetails(p_date in date
7575 ,p_rate_tbl in LNS_FINANCIALS.RATE_SCHEDULE_TBL) return LNS_FINANCIALS.INTEREST_RATE_REC
7576 is
7577 x number;
7578 l_rate number;
7579 l_rate_rec LNS_FINANCIALS.INTEREST_RATE_REC;
7580 l_api_name varchar2(25);
7581
7582 begin
7583
7584 l_rate := 0;
7585 l_api_name := 'getRateDetails';
7586 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7587
7588 x := 1;
7589 Begin
7590 LOOP
7591 l_rate := p_rate_tbl(x).annual_rate;
7592 l_rate_rec := p_rate_tbl(x);
7593 EXIT WHEN p_date >= p_rate_tbl(x).begin_date and p_date <= p_rate_tbl(x).end_date;
7594
7595 x := x + 1;
7596 END LOOP;
7597 Exception
7598 When No_Data_found then
7599 -- when there is not a rate for this period it is assumed to be zero (see scenarios 3, 6, 8 in comments on getWeightedRate)
7600 l_rate := 0;
7601 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - no rate found for period');
7602 when others then
7603 l_rate := 0;
7604
7605 End;
7606
7607 if l_rate = 0 then
7608 l_rate_rec.annual_rate := 0;
7609 end if;
7610
7611 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7612
7613 return l_rate_rec;
7614
7615 end getRateDetails;
7616
7617 /*=========================================================================
7618 || PUBLIC PROCEDURE getLoanDetails
7619 ||
7620 || DESCRIPTION
7621 ||
7622 || Overview: return a rec_type of loan details
7623 ||
7624 || Parameter: loan_id
7625 ||
7626 || Return value: table of dates
7627 ||
7628 || Source Tables: LNS_LOAN_HEADER, LNS_TERMS, LNS_AMORTIZATION_SCHEDS
7629 ||
7630 || Target Tables: NA
7631 ||
7632 || KNOWN ISSUES
7633 ||
7634 || NOTES
7635 ||
7636 || MODIFICATION HISTORY
7637 || Date Author Description of Changes
7638 || 1/15/2004 4:28PM raverma Created
7639 || 2/26/2004 raverma add loan_maturity_Date
7640 || 3/12/2004 raverma added reamortization information
7641 || 4/15/2004 raverma added loan_status
7642 || 8/02/2004 raverma added logic to calculate num_amortization_intervals based on
7643 || theoretical amortization_maturity_date
7644 || 01/19/2007 scherkas Fixed bug 5842639
7645 *=======================================================================*/
7646 function getLoanDetails(p_loan_id in number
7647 ,p_based_on_terms in varchar2
7648 ,p_phase in varchar2) return LNS_FINANCIALS.LOAN_DETAILS_REC
7649
7650 is
7651
7652
7653 -- get the loan details assumes there is only ONE ROW in terms (TERM PHASE)
7654 CURSOR c_loan_details(p_Loan_id NUMBER, p_based_on_terms varchar2, p_phase varchar2) IS
7655 SELECT h.loan_id
7656 ,decode(p_phase, 'TERM', h.loan_term, 'OPEN', h.open_loan_term, h.loan_term) TERM
7657 ,decode(p_phase, 'TERM', h.loan_term_period, 'OPEN', h.open_loan_term_period, h.loan_term_period) TERM_PERIOD
7658 ,decode(p_phase, 'TERM', decode(h.balloon_payment_type, 'TERM', h.amortized_term, 'AMOUNT', h.loan_term, h.amortized_term), 'OPEN', h.open_loan_term) AMORT_TERM
7659 ,decode(p_phase, 'TERM', decode(h.balloon_payment_type, 'TERM', h.amortized_term_period, 'AMOUNT', h.loan_term_period, h.amortized_term_period), 'OPEN', h.open_loan_term_period) AMORT_TERM_PERIOD
7660 ,decode(h.balloon_payment_type, 'TERM', 0, 'AMOUNT', h.balloon_payment_amount, 0) BALLOON_PAYMENT_AMT
7661 ,decode(p_phase, 'TERM', t.amortization_frequency, 'OPEN', t.loan_payment_frequency) AMORT_FREQ
7662 ,decode(p_phase, 'TERM', t.loan_payment_frequency, 'OPEN', t.open_payment_frequency, t.loan_payment_frequency) PAY_FREQ
7663 ,decode(p_phase, 'TERM', trunc(h.loan_start_date), 'OPEN' , trunc(h.open_loan_start_date), trunc(h.loan_start_date)) START_DATE
7664 ,decode(p_phase, 'TERM', trunc(t.first_payment_date), 'OPEN' , trunc(t.open_first_payment_date), trunc(t.first_payment_date)) FIRST_PAY_DATE
7665 ,h.requested_amount REQUEST_AMOUNT
7666 ,h.funded_amount FUNDED_AMOUNT
7667 ,lns_financials.getRemainingBalance(p_loan_id) BALANCE
7668 --,decode(p_based_on_terms, 'CURRENT', lns_financials.getRemainingBalance(p_loan_id), 'ORIGINAL', h.requested_amount) BALANCE -- see bug #3881401
7669 ,decode(p_phase, 'TERM', trunc(h.loan_maturity_date), 'OPEN', trunc(h.open_maturity_date), trunc(h.loan_maturity_date)) MATURITY_DATE
7670 ,NVL(t.reamortize_over_payment, 'N')
7671 ,NVL(t.reamortize_under_payment, 'N')
7672 ,NVL(t.reamortize_with_interest, 'N')
7673 ,LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id, p_phase) LAST_PAY_NUM
7674 --,decode(p_based_on_terms, 'CURRENT', LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id),'ORIGINAL', 1) LAST_PAY_NUM
7675 ,decode(nvl(t.day_count_method, 'PERIODIC30_360'), 'PERIODIC30_360', '30/360', t.day_count_method) DAY_COUNT
7676 ,decode(p_phase, 'TERM', decode(trunc(t.first_payment_date) - trunc(h.loan_start_date), 0, 'N', 'Y')
7677 , 'OPEN', decode(trunc(t.open_first_payment_date) - trunc(h.open_loan_start_date), 0, 'N', 'Y')
7678 , decode(trunc(t.first_payment_date) - trunc(h.loan_start_date), 0, 'N', 'Y')) ARREARS
7679 ,nvl(h.custom_payments_flag, 'N') CUSTOM
7680 ,h.loan_status LOAN_STATUS
7681 ,h.loan_currency CURRENCY
7682 ,curr.precision PRECISION
7683 ,h.OPEN_TO_TERM_FLAG OPEN_TO_TERM_FLAG
7684 ,h.OPEN_TO_TERM_EVENT OPEN_TO_TERM_EVENT
7685 ,h.MULTIPLE_FUNDING_FLAG MULTIPLE_FUNDING_FLAG
7686 ,h.SECONDARY_STATUS SECONDARY_STATUS
7687 ,t.RATE_TYPE RATE_TYPE
7688 ,t.CEILING_RATE TERM_CEILING_RATE
7689 ,t.FLOOR_RATE TERM_FLOOR_RATE
7690 ,t.PERCENT_INCREASE TERM_PERCENT_INCREASE
7691 ,t.PERCENT_INCREASE_LIFE TERM_PERCENT_INCREASE_LIFE
7692 ,t.FIRST_PERCENT_INCREASE TERM_FIRST_PERCENT_INCREASE
7693 ,t.OPEN_PERCENT_INCREASE OPEN_PERCENT_INCREASE
7694 ,t.OPEN_PERCENT_INCREASE_LIFE OPEN_PERCENT_INCREASE_LIFE
7695 ,t.OPEN_FIRST_PERCENT_INCREASE OPEN_FIRST_PERCENT_INCREASE
7696 ,t.OPEN_CEILING_RATE OPEN_CEILING_RATE
7697 ,t.OPEN_FLOOR_RATE OPEN_FLOOR_RATE
7698 ,t.OPEN_PROJECTED_RATE OPEN_PROJECTED_RATE
7699 ,t.TERM_PROJECTED_RATE TERM_PROJECTED_RATE
7700 ,t.rate_change_frequency TERM_RATE_CHG_FREQ
7701 ,t.rate_change_frequency OPEN_RATE_CHG_FREQ
7702 ,t.INDEX_RATE_ID OPEN_INDEX_RATE_ID
7703 ,t.INDEX_RATE_ID TERM_INDEX_RATE_ID
7704 ,t.OPEN_INDEX_DATE OPEN_INDEX_DATE
7705 ,t.TERM_INDEX_DATE TERM_INDEX_DATE
7706 ,decode(p_phase, 'TERM', t.TERM_PROJECTED_RATE, t.OPEN_PROJECTED_RATE) INITIAL_INTEREST_RATE
7707 ,nvl(lns_fin_utils.getActiveRate(h.loan_id), decode(p_phase, 'TERM', t.TERM_PROJECTED_RATE, t.OPEN_PROJECTED_RATE)) LAST_INTEREST_RATE
7708 ,nvl(t.FIRST_RATE_CHANGE_DATE, t.NEXT_RATE_CHANGE_DATE) FIRST_RATE_CHANGE_DATE
7709 ,t.NEXT_RATE_CHANGE_DATE NEXT_RATE_CHANGE_DATE
7710 ,t.CALCULATION_METHOD
7711 ,t.INTEREST_COMPOUNDING_FREQ
7712 ,decode(p_phase, 'TERM', decode(p_based_on_terms,
7713 'CURRENT', decode(nvl(h.custom_payments_flag, 'N'), 'Y', nvl(t.PAYMENT_CALC_METHOD, 'CUSTOM'),
7714 'N', nvl(t.PAYMENT_CALC_METHOD, 'EQUAL_PAYMENT')),
7715 decode(nvl(h.custom_payments_flag, 'N'), 'Y', nvl(t.ORIG_PAY_CALC_METHOD, 'CUSTOM'),
7716 'N', nvl(t.PAYMENT_CALC_METHOD, 'EQUAL_PAYMENT'))
7717 ), null)
7718 ,t.ORIG_PAY_CALC_METHOD
7719 ,decode(p_phase, 'TERM', trunc(nvl(t.prin_first_pay_date, t.first_payment_date)), 'OPEN', null, trunc(nvl(t.prin_first_pay_date, t.first_payment_date)))
7720 ,nvl(t.prin_payment_frequency, t.loan_payment_frequency)
7721 ,decode(trunc(nvl(t.prin_first_pay_date, t.first_payment_date)) - trunc(h.loan_start_date), 0, 'N', 'Y') -- calculate in advance or arrears for principal
7722 ,nvl(t.PENAL_INT_RATE, 0)
7723 ,nvl(t.PENAL_INT_GRACE_DAYS, 0)
7724 ,nvl(h.CURRENT_PHASE, 'TERM')
7725 ,nvl(t.REAMORTIZE_ON_FUNDING, 'REST')
7726 ,nvl(h.ADD_REQUESTED_AMOUNT, 0)
7727 ,nvl(t.CALC_ADD_INT_UNPAID_PRIN, 'N')
7728 ,nvl(t.CALC_ADD_INT_UNPAID_INT, 'N')
7729 ,nvl(t.CAPITALIZE_INT, 'N')
7730 ,nvl(t.FLUCTUATE_EQ_PAY_AMOUNT, 'N')
7731 FROM lns_loan_headers_all h
7732 ,lns_terms t
7733 ,fnd_currencies curr
7734 WHERE h.loan_id = p_loan_id
7735 AND t.loan_id = h.loan_id
7736 AND curr.currency_code = h.loan_currency;
7737
7738 -- get reamortization information
7739 -- this is temporary place on LNS_AMORTIZATION_SCHEDS
7740 -- we should move this to LNS_TERMS when we have terms realignment
7741 -- bug# 5664316 - we only store ONE reamortization row
7742 CURSOR c_reamortization(p_Loan_id NUMBER) IS
7743 SELECT nvl(reamortization_amount, 0)
7744 ,nvl(reamortize_from_installment, 0)
7745 ,nvl(reamortize_to_installment, 0)
7746 FROM lns_loan_headers_all lnh,
7747 lns_amortization_scheds amort1
7748 WHERE lnh.loan_id = amort1.loan_id(+)
7749 AND lnh.loan_id = p_loan_id
7750 AND amort1.reamortization_amount > 0;
7751
7752 -- cursor to get the balance information for the loan
7753 -- changes as per scherkas 11-16-2005
7754 cursor c_balanceInfo(p_loan_id NUMBER, p_phase varchar2) IS
7755 select nvl(sum(amort.PRINCIPAL_AMOUNT),0) -- billed principal
7756 ,nvl(sum(amort.PRINCIPAL_REMAINING),0) -- unpaid principal
7757 ,nvl(sum(amort.INTEREST_REMAINING),0) -- unpaid interest
7758 from LNS_AM_SCHEDS_V amort
7759 where amort.Loan_id = p_loan_id
7760 and amort.REVERSED_CODE = 'N'
7761 and amort.phase = p_phase;
7762
7763 -- this cursor will get the last time the loan interest was accrued
7764 -- fix for bug 7423644: removed condition interest_trx_id is not null
7765 cursor c_last_interest_accrual(p_loan_id NUMBER) is
7766 select decode(LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(lnh.loan_id),
7767 0,
7768 decode(lnh.current_phase, 'TERM', lnh.loan_start_date, 'OPEN', lnh.open_loan_start_date),
7769 (select max(due_date)
7770 from lns_amortization_scheds
7771 where reversed_flag = 'N'
7772 and loan_id = lnh.loan_id
7773 and phase = lnh.current_phase))
7774 from lns_loan_headers lnh
7775 where lnh.loan_id = p_loan_id;
7776
7777 -- this cursor is to get the last activity date on the loan
7778 -- payoff processing will use this date
7779 cursor c_last_loan_activity(p_loan_id number) is
7780 select max(activity_date)
7781 from LNS_REC_ACT_CASH_CM_V
7782 where activity_code = 'PMT'
7783 and loan_id = p_loan_id;
7784
7785 -- begin fix for bug 6724561
7786 -- cursor to get latest extended from installment - last billed installment from the last approved loan extension
7787 cursor c_ext_from_install(p_loan_id NUMBER) IS
7788 select LAST_BILLED_INSTALLMENT
7789 from LNS_LOAN_EXTENSIONS
7790 where loan_id = p_loan_id
7791 and STATUS = 'APPROVED'
7792 order by LOAN_EXT_ID desc;
7793 -- end fix for bug 6724561
7794
7795 -- begin fix for bug 6724522
7796 -- cursor to get original loan term if loan has been extended
7797 cursor c_orig_loan_term(p_loan_id NUMBER) IS
7798 select OLD_TERM,
7799 OLD_TERM_PERIOD,
7800 OLD_BALLOON_TYPE,
7801 OLD_BALLOON_AMOUNT,
7802 OLD_AMORT_TERM,
7803 OLD_MATURITY_DATE,
7804 OLD_INSTALLMENTS
7805 from LNS_LOAN_EXTENSIONS
7806 where loan_id = p_loan_id
7807 and STATUS = 'APPROVED'
7808 order by LOAN_EXT_ID;
7809
7810 l_orig_loan_term number;
7811 l_orig_loan_period varchar2(30);
7812 l_orig_balloon_type varchar2(30);
7813 l_orig_balloon_amount number;
7814 l_orig_amort_term number;
7815 l_orig_maturity_date date;
7816 l_orig_num_install number;
7817 -- end fix for bug 6724522
7818
7819 l_billed_principal number;
7820 l_amortized_to_Date date;
7821 --l_pay_in_arrears boolean;
7822 l_loan_Details LNS_FINANCIALS.LOAN_DETAILS_REC;
7823 l_amortize_dates LNS_FIN_UTILS.DATE_TBL;
7824 l_loan_id number;
7825 l_api_name varchar2(25);
7826
7827 begin
7828
7829 l_api_name := 'getLoanDetails';
7830 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7831
7832 --l_loan_id := p_loan_id;
7833 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_loan_id: ' || p_loan_id);
7834 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_based_on_terms: ' || p_based_on_terms);
7835 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_phase: ' || p_phase);
7836
7837 OPEN c_loan_details(p_loan_id, p_based_on_terms, p_phase);
7838 FETCH c_loan_details INTO
7839 l_loan_details.loan_id
7840 ,l_loan_Details.loan_term
7841 ,l_loan_Details.loan_term_period
7842 ,l_loan_Details.amortized_term
7843 ,l_loan_Details.amortized_term_period
7844 ,l_loan_details.balloon_payment_amount
7845 ,l_loan_Details.amortization_frequency
7846 ,l_loan_Details.payment_frequency
7847 ,l_loan_Details.loan_start_date
7848 ,l_loan_Details.first_payment_date
7849 ,l_loan_Details.requested_amount
7850 ,l_loan_details.funded_amount
7851 ,l_loan_details.remaining_balance
7852 ,l_loan_details.maturity_Date
7853 ,l_loan_details.reamortize_overpay
7854 ,l_loan_details.reamortize_underpay
7855 ,l_loan_details.reamortize_with_interest
7856 ,l_loan_details.last_installment_billed
7857 ,l_loan_details.day_count_method
7858 ,l_loan_details.pay_in_arrears
7859 ,l_loan_details.custom_schedule
7860 ,l_loan_details.loan_status
7861 ,l_loan_details.loan_currency
7862 ,l_loan_details.currency_precision
7863 ,l_loan_details.OPEN_TO_TERM_FLAG
7864 ,l_loan_details.OPEN_TO_TERM_EVENT
7865 ,l_loan_details.MULTIPLE_FUNDING_FLAG
7866 ,l_loan_details.SECONDARY_STATUS
7867 ,l_loan_details.RATE_TYPE -- fixed or variable
7868 ,l_loan_details.TERM_CEILING_RATE -- term ceiling rate
7869 ,l_loan_details.TERM_FLOOR_RATE -- term floor rate
7870 ,l_loan_details.TERM_ADJ_PERCENT_INCREASE -- term percentage increase btwn adjustments
7871 ,l_loan_details.TERM_LIFE_PERCENT_INCREASE -- term lifetime max adjustment for interest
7872 ,l_loan_details.TERM_FIRST_PERCENT_INCREASE -- term first percentage increase
7873 ,l_loan_details.OPEN_ADJ_PERCENT_INCREASE -- open percentage increase btwn adjustments
7874 ,l_loan_details.OPEN_LIFE_PERCENT_INCREASE -- open lifetime max adjustment for interest
7875 ,l_loan_details.OPEN_FIRST_PERCENT_INCREASE -- open first percentage increase
7876 ,l_loan_details.OPEN_CEILING_RATE -- open ceiling rate
7877 ,l_loan_details.OPEN_FLOOR_RATE -- open floor rate
7878 ,l_loan_details.OPEN_PROJECTED_INTEREST_RATE -- open projected interest rate
7879 ,l_loan_details.TERM_PROJECTED_INTEREST_RATE -- term projected interest rate
7880 ,l_loan_details.OPEN_RATE_CHG_FREQ
7881 ,l_loan_details.TERM_RATE_CHG_FREQ
7882 ,l_loan_details.OPEN_INDEX_RATE_ID
7883 ,l_loan_details.TERM_INDEX_RATE_ID
7884 ,l_loan_details.OPEN_INDEX_DATE
7885 ,l_loan_details.TERM_INDEX_DATE
7886 ,l_loan_details.INITIAL_INTEREST_RATE -- current phase only
7887 ,l_loan_details.LAST_INTEREST_RATE -- current phase only
7888 ,l_loan_details.FIRST_RATE_CHANGE_DATE -- current phase only
7889 ,l_loan_details.NEXT_RATE_CHANGE_DATE -- current phase only
7890 ,l_loan_details.CALCULATION_METHOD
7891 ,l_loan_details.INTEREST_COMPOUNDING_FREQ
7892 ,l_loan_details.PAYMENT_CALC_METHOD
7893 ,l_loan_details.ORIG_PAY_CALC_METHOD
7894 ,l_loan_details.prin_first_pay_date
7895 ,l_loan_details.prin_payment_frequency
7896 ,l_loan_details.PRIN_PAY_IN_ARREARS
7897 ,l_loan_details.PENAL_INT_RATE
7898 ,l_loan_details.PENAL_INT_GRACE_DAYS
7899 ,l_loan_details.LOAN_PHASE
7900 ,l_loan_details.REAMORTIZE_ON_FUNDING
7901 ,l_loan_details.ADD_REQUESTED_AMOUNT
7902 ,l_loan_details.CALC_ADD_INT_UNPAID_PRIN
7903 ,l_loan_details.CALC_ADD_INT_UNPAID_INT
7904 ,l_loan_details.CAPITALIZE_INT
7905 ,l_loan_details.FLUCTUATE_EQ_PAY_AMOUNT
7906 ;
7907 close c_loan_details;
7908
7909 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate_type ' || l_loan_details.rate_type);
7910 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_ceiling_rate ' || l_loan_details.open_ceiling_rate);
7911 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_floor_rate ' || l_loan_details.open_floor_rate);
7912
7913 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': balloon_payment_amount' || l_loan_details.balloon_payment_amount);
7914
7915 -- begin fix for bug 6724522
7916 -- replacing loan terms with original data for p_based_on_terms <> 'CURRENT'
7917 if p_based_on_terms <> 'CURRENT' then
7918 open c_orig_loan_term(p_loan_id);
7919 fetch c_orig_loan_term into
7920 l_orig_loan_term,
7921 l_orig_loan_period,
7922 l_orig_balloon_type,
7923 l_orig_balloon_amount,
7924 l_orig_amort_term,
7925 l_orig_maturity_date,
7926 l_orig_num_install;
7927 close c_orig_loan_term;
7928
7929 if l_orig_loan_term is not null and
7930 l_orig_loan_period is not null and
7931 l_orig_balloon_type is not null and
7932 l_orig_balloon_amount is not null and
7933 l_orig_amort_term is not null and
7934 l_orig_maturity_date is not null and
7935 l_orig_num_install is not null
7936 then
7937 l_loan_Details.loan_term := l_orig_loan_term;
7938 l_loan_Details.loan_term_period := l_orig_loan_period;
7939 l_loan_Details.amortized_term_period := l_orig_loan_period;
7940 l_loan_Details.maturity_Date := l_orig_maturity_date;
7941 l_loan_Details.ORIG_NUMBER_INSTALLMENTS := l_orig_num_install;
7942
7943 if l_orig_balloon_type = 'TERM' then
7944 l_loan_details.balloon_payment_amount := 0;
7945 l_loan_Details.amortized_term := l_orig_amort_term;
7946 elsif l_orig_balloon_type = 'AMOUNT' then
7947 l_loan_details.balloon_payment_amount := l_orig_balloon_amount;
7948 l_loan_Details.amortized_term := l_orig_loan_term;
7949 end if;
7950 end if;
7951 end if;
7952 -- end fix for bug 6724522
7953
7954 -- begin fix for bug 6724561
7955 -- get latest extended from installment
7956 if p_based_on_terms = 'CURRENT' then
7957 open c_ext_from_install(p_loan_id);
7958 fetch c_ext_from_install into l_loan_Details.extend_from_installment;
7959 close c_ext_from_install;
7960 end if;
7961 -- end fix for bug 6724561
7962
7963 -- adding balloon amount
7964 l_loan_details.amortized_amount := l_loan_details.requested_amount - l_loan_details.balloon_payment_amount;
7965
7966 open c_last_interest_accrual(p_loan_id);
7967 fetch c_last_interest_accrual into l_loan_details.last_interest_accrual;
7968 close c_last_interest_accrual;
7969
7970 if l_loan_details.pay_in_arrears = 'Y' then
7971 l_loan_details.pay_in_arrears_boolean := true;
7972 else
7973 l_loan_details.pay_in_arrears_boolean := false;
7974 end if;
7975
7976 if l_loan_details.PRIN_PAY_IN_ARREARS = 'Y' then
7977 l_loan_details.PRIN_PAY_IN_ARREARS_BOOL := true;
7978 else
7979 l_loan_details.PRIN_PAY_IN_ARREARS_BOOL := false;
7980 end if;
7981
7982 if p_based_on_terms = 'CURRENT' then
7983 -- get reamortization information
7984 Begin
7985 -- bug# 5664316 make sure we catch no data found on EACH cursor: reamortization, activity, balanceInfo
7986 open c_reamortization(p_loan_id);
7987 fetch c_reamortization into
7988 l_loan_details.reamortize_amount
7989 ,l_loan_details.reamortize_from_installment
7990 ,l_loan_details.reamortize_to_installment;
7991 close c_reamortization;
7992 Exception
7993 when no_data_found then
7994 l_loan_details.reamortize_amount := 0;
7995 l_loan_details.reamortize_from_installment := null;
7996 l_loan_details.reamortize_to_installment := 0;
7997 End;
7998
7999 Begin
8000 open c_last_loan_activity(p_loan_id);
8001 fetch c_last_loan_activity into
8002 l_loan_details.last_activity_date;
8003 close c_last_loan_activity;
8004 Exception
8005 when no_data_found then
8006 l_loan_details.last_activity_date := null;
8007 End;
8008
8009 Begin
8010
8011 -- get balance information
8012 open c_balanceInfo(p_loan_id, p_phase);
8013 fetch c_balanceInfo into
8014 l_billed_principal
8015 ,l_loan_details.unpaid_principal
8016 ,l_loan_details.UNPAID_INTEREST;
8017 close c_balanceInfo;
8018
8019 l_loan_details.billed_principal := l_billed_principal;
8020 l_loan_details.unbilled_principal := l_loan_details.funded_amount - l_billed_principal;
8021 if l_loan_details.LOAN_PHASE = 'TERM' and l_loan_details.loan_status = 'CANCELLED' then
8022 l_loan_details.unpaid_principal := 0;
8023 l_loan_details.UNPAID_INTEREST := 0;
8024 end if;
8025
8026 Exception
8027 when no_data_found then
8028 l_loan_details.unpaid_principal := 0;
8029 l_loan_details.billed_principal := 0;
8030 l_loan_details.unbilled_principal := l_loan_details.funded_amount;
8031 l_loan_details.UNPAID_INTEREST := 0;
8032 End;
8033
8034 else
8035 l_loan_details.reamortize_amount := 0;
8036 l_loan_details.reamortize_from_installment := null;
8037 l_loan_details.reamortize_to_installment := 0;
8038 l_loan_details.last_activity_date := null;
8039 l_loan_details.unpaid_principal := 0;
8040 l_loan_details.billed_principal := 0;
8041 l_loan_details.unbilled_principal := l_loan_details.funded_amount;
8042 l_loan_details.UNPAID_INTEREST := 0;
8043 end if;
8044
8045 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '<---------- BEGIN LOAN DETAILS ------------->');
8046
8047 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortized_term: ' || l_loan_details.amortized_term);
8048 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortized_term_period: ' || l_loan_details.amortized_term_period);
8049 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization_frequency: ' || l_loan_details.amortization_frequency);
8050 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': first_payment_date: ' || l_loan_details.first_payment_date);
8051 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_start_date: ' || l_loan_details.loan_start_date);
8052 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': funded_amount: ' || l_loan_details.funded_amount);
8053 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': remaining_balance: ' || l_loan_details.remaining_balance);
8054 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': reamortize_amount: ' || l_loan_details.reamortize_amount);
8055 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': reamortize_from_installment: ' || l_loan_details.reamortize_from_installment);
8056 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': day_count_method: ' || l_loan_details.day_count_method);
8057 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': last_installment_billed: ' || l_loan_details.last_installment_billed);
8058 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': PAYMENT_CALC_METHOD: ' || l_loan_details.PAYMENT_CALC_METHOD);
8059 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATION_METHOD: ' || l_loan_details.CALCULATION_METHOD);
8060 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': INTEREST_COMPOUNDING_FREQ: ' || l_loan_details.INTEREST_COMPOUNDING_FREQ);
8061 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prin_first_pay_date: ' || l_loan_details.prin_first_pay_date);
8062 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prin_payment_frequency: ' || l_loan_details.prin_payment_frequency);
8063 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': unbilled_principal ' || l_loan_details.unbilled_principal);
8064 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': unpaid_principal ' || l_loan_details.unpaid_principal);
8065 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': UNPAID_INTEREST ' || l_loan_details.UNPAID_INTEREST);
8066 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': extend_from_installment ' || l_loan_Details.extend_from_installment);
8067 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ORIG_PAY_CALC_METHOD ' || l_loan_Details.ORIG_PAY_CALC_METHOD);
8068 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CAPITALIZE_INT ' || l_loan_Details.CAPITALIZE_INT);
8069 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLUCTUATE_EQ_PAY_AMOUNT ' || l_loan_Details.FLUCTUATE_EQ_PAY_AMOUNT);
8070
8071 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '<---------- END LOAN DETAILS --------------->');
8072 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8073
8074 return l_loan_details;
8075
8076 Exception
8077 When No_Data_Found then
8078 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - LOAN ID: ' || l_loan_id || ' not found');
8079 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_LOAN_ID');
8080 FND_MSG_PUB.Add;
8081 RAISE FND_API.G_EXC_ERROR;
8082
8083 When Others then
8084 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || 'Err: ' || sqlerrm);
8085 RAISE FND_API.G_EXC_ERROR;
8086
8087 end getLoanDetails;
8088
8089
8090 /*=========================================================================
8091 || PUBLIC PROCEDURE shiftLoan
8092 ||
8093 || DESCRIPTION
8094 ||
8095 || Overview: will shift a loans OPEN phase and/or TERM phase
8096 || where appropriate
8097 || 1. determine if any disbursements are past the open maturity date
8098 || 2. if so, get the next available maturity date,
8099 || -- this should increment by amortization frequency
8100 || 3. update the term/term period - in terms of payment frequency,
8101 || -- the term will change to X MONTHS if TERM was > MONTHS
8102 ||
8103 || Parameter: p_loan_id = loan_id
8104 ||
8105 || Source Tables: LNS_LOAN_HEADERS_ALL, LNS_DISB_HEADERS
8106 || LNS_TERMS
8107 ||
8108 || Target Tables: LNS_LOAN_HEADERS_ALL, LNS_TERMS
8109 ||
8110 || Return value: Standard Oracle API
8111 ||
8112 || MODIFICATION HISTORY
8113 || Date Author Description of Changes
8114 || 02/14/2005 11:35AM raverma Created
8115 *=======================================================================*/
8116 procedure shiftLoan(p_loan_id in number
8117 ,p_init_msg_list IN VARCHAR2
8118 ,p_commit IN VARCHAR2
8119 ,x_return_status OUT NOCOPY VARCHAR2
8120 ,x_msg_count OUT NOCOPY NUMBER
8121 ,x_msg_data OUT NOCOPY VARCHAR2)
8122
8123 is
8124
8125 l_api_name varchar2(25);
8126 l_move_maturity_date number;
8127 i number;
8128 l_old_maturity_date date;
8129 l_new_maturity_date date;
8130 l_max_pay_request_date date;
8131 l_payment_frequency varchar2(30);
8132 l_new_frequency varchar2(30);
8133 l_custom_payments_flag varchar2(1);
8134 l_current_phase varchar2(30);
8135 l_term number;
8136 l_term_period varchar2(30);
8137 l_temp varchar2(30);
8138 l_term_phase_exists varchar2(1);
8139 l_term_id number;
8140 l_initial_months number;
8141
8142 l_return_status VARCHAR2(1);
8143 l_msg_count NUMBER;
8144 l_msg_data VARCHAR2(32767);
8145 l_loan_details LOAN_DETAILS_REC;
8146 l_loan_header_rec LNS_LOAN_HEADER_PUB.loan_header_rec_type;
8147 l_term_rec LNS_TERMS_PUB.loan_term_rec_type;
8148 l_version_number number;
8149 l_terms_version_number number;
8150 l_dates_shifted_flag varchar2(1) := 'N';
8151
8152
8153 CURSOR move_maturity_date_cur(P_LOAN_ID number) IS
8154 select
8155 CASE
8156 WHEN (nvl(loan.CURRENT_PHASE, 'TERM') = 'OPEN') THEN
8157 sign(trunc(loan.OPEN_MATURITY_DATE) - (select trunc(max(PAYMENT_REQUEST_DATE)) from LNS_DISB_HEADERS where LOAN_ID = loan.LOAN_ID))
8158 WHEN (nvl(loan.CURRENT_PHASE, 'TERM') = 'TERM' and loan.MULTIPLE_FUNDING_FLAG = 'N') THEN
8159 sign(trunc(loan.LOAN_MATURITY_DATE) - (select trunc(max(PAYMENT_REQUEST_DATE)) from LNS_DISB_HEADERS where LOAN_ID = loan.LOAN_ID))
8160 ELSE
8161 1
8162 END
8163 from lns_loan_headers loan
8164 where loan.LOAN_ID = p_loan_id;
8165
8166
8167 cursor c_loan_info (p_loan_id number) is
8168 select t.open_payment_frequency
8169 ,decode(h.current_phase, 'OPEN', h.open_maturity_date, h.loan_maturity_date)
8170 ,nvl(h.custom_payments_flag, 'N')
8171 ,h.open_to_term_flag
8172 ,decode(h.current_phase, 'OPEN', h.open_loan_term, h.loan_term)
8173 ,decode(h.current_phase, 'OPEN', h.open_loan_term_period, h.loan_term_period)
8174 ,h.OBJECT_VERSION_NUMBER
8175 ,t.object_VERSION_NUMBER
8176 ,t.term_id
8177 ,h.current_phase
8178 from lns_terms t
8179 ,lns_loan_headers h
8180 where h.loan_id = p_loan_id
8181 and h.loan_id = t.loan_id;
8182
8183 cursor c_max_pay_req_date(p_loan_id number) is
8184 select max(payment_request_date)
8185 from lns_disb_headers
8186 where loan_id = p_loan_id;
8187
8188 begin
8189 -- Standard Start of API savepoint
8190 SAVEPOINT shiftLoan;
8191 l_api_name := 'shiftLoan';
8192 i := 0;
8193
8194 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8195 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
8196
8197 -- Initialize API return status to SUCCESS
8198 x_return_status := FND_API.G_RET_STS_SUCCESS;
8199
8200 --
8201 -- Api body
8202 -- -----------------------------------------------------------------
8203 open move_maturity_date_cur(P_LOAN_ID);
8204 fetch move_maturity_date_cur into l_move_maturity_date;
8205 close move_maturity_date_cur;
8206
8207 if l_move_maturity_date = -1 then
8208
8209 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - we need to move the loan');
8210
8211 -- get the final payment request date
8212 open c_max_pay_req_date(p_loan_id);
8213 fetch c_max_pay_req_date into l_max_pay_request_date;
8214 close c_max_pay_req_date;
8215 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_max_pay_request_date' || l_max_pay_request_date);
8216
8217 -- get loan info
8218 open c_loan_info(p_loan_id);
8219 fetch c_loan_info into
8220 l_payment_frequency
8221 ,l_old_maturity_date
8222 ,l_custom_payments_flag
8223 ,l_term_phase_exists
8224 ,l_term
8225 ,l_term_period
8226 ,l_version_number
8227 ,l_terms_version_number
8228 ,l_term_id
8229 ,l_current_phase;
8230 close c_loan_info;
8231
8232 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_payment_frequency ' || l_payment_frequency);
8233 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_old_maturity_date ' || l_old_maturity_date );
8234 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_custom_payments_flag ' || l_custom_payments_flag);
8235 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_phase_exists ' || l_term_phase_exists );
8236 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term ' || l_term);
8237 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_period ' || l_term_period );
8238 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_version_number ' || l_version_number );
8239 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_terms_version_number ' || l_terms_version_number );
8240 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_id ' || l_term_id );
8241
8242 if l_custom_payments_flag <> 'Y' then
8243 -- we will be converting the term of the loan if frequency > MONTHLY
8244 if l_payment_frequency <> 'SEMI-MONTHLY' AND l_payment_frequency <> 'WEEKLY' AND l_payment_frequency <> 'BIWEEKLY' then
8245 l_new_frequency := 'MONTHS';
8246 l_initial_months := lns_fin_utils.convertPeriod(p_term => l_term
8247 ,p_term_period => l_term_period);
8248 else
8249 --weeks or semi-months
8250 if substr(l_payment_frequency, length(l_payment_frequency) - 1, 2) = 'LY' then
8251 l_temp := substr(l_payment_frequency, 1, length(l_payment_frequency) - 2) || 'S';
8252 else
8253 l_temp := l_payment_frequency;
8254 end if;
8255 l_new_frequency := l_temp;
8256 l_initial_months := l_term;
8257 end if;
8258 l_new_maturity_Date := l_old_maturity_date;
8259
8260 loop
8261 -- i will be the number of "TERMS" to add the LNS_LOAN_HEADERS.TERM
8262 i := i + 1;
8263 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - i ' || l_new_maturity_date);
8264 l_new_maturity_date := lns_fin_utils.getNextDate(p_date => l_new_maturity_date
8265 ,p_interval_type => l_new_frequency
8266 ,p_direction => 1);
8267 exit when l_new_maturity_date >= l_max_pay_request_date;
8268 end loop;
8269
8270 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NEW MATURITY DATE' || l_new_maturity_date );
8271
8272 --now we move the loan dates
8273 if (l_current_phase = 'OPEN' and l_term_phase_exists = 'Y') then
8274 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting new term dates');
8275
8276 -- Bug#6169438, Added new parameter l_dates_shifted_flag
8277 shiftLoanDates(p_loan_id => p_loan_id
8278 ,p_new_start_date => l_new_maturity_date
8279 ,p_phase => 'TERM'
8280 ,x_loan_details => l_loan_details
8281 ,x_dates_shifted_flag => l_dates_shifted_flag
8282 ,x_return_status => l_return_status
8283 ,x_msg_count => l_msg_count
8284 ,x_msg_data => l_msg_data);
8285 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM start date is ' || l_loan_details.loan_start_date);
8286 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM first payment date is ' || l_loan_details.first_payment_Date);
8287 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM principal first payment date is ' || l_loan_details.PRIN_FIRST_PAY_DATE);
8288 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM maturity date is ' || l_loan_details.maturity_date);
8289
8290 -- items to update for term phase
8291 l_term_rec.term_id := l_term_id;
8292 l_term_rec.FIRST_PAYMENT_DATE := l_loan_details.first_payment_Date;
8293 l_term_rec.PRIN_FIRST_PAY_DATE := l_loan_details.PRIN_FIRST_PAY_DATE;
8294 l_term_rec.NEXT_PAYMENT_DUE_DATE := l_loan_details.first_payment_Date;
8295 l_loan_header_rec.loan_maturity_date := l_loan_details.maturity_date;
8296 l_loan_header_rec.loan_start_date := l_loan_details.loan_start_date;
8297 lns_terms_pub.update_term(p_object_version_number => l_terms_version_number
8298 ,p_init_msg_list => fnd_api.g_false
8299 ,p_loan_term_rec => l_term_rec
8300 ,x_return_status => l_return_status
8301 ,x_msg_count => l_msg_count
8302 ,x_msg_data => l_msg_data);
8303 end if;
8304
8305 if l_current_phase = 'OPEN' then
8306 -- update items for loan header table
8307 l_loan_header_rec.loan_id := p_loan_id;
8308 l_loan_header_rec.open_maturity_date := l_new_maturity_date;
8309 l_loan_header_rec.open_loan_term := l_initial_months + i;
8310 l_loan_header_rec.open_loan_term_period := l_new_frequency;
8311
8312 lns_loan_header_pub.update_loan(p_object_version_number => l_version_number
8313 ,p_loan_header_rec => l_loan_header_rec
8314 ,p_init_msg_list => fnd_api.g_false
8315 ,x_return_status => l_return_status
8316 ,x_msg_count => l_msg_count
8317 ,x_msg_data => l_msg_data);
8318 elsif l_current_phase = 'TERM' then
8319
8320 l_loan_header_rec.loan_id := p_loan_id;
8321 l_loan_header_rec.loan_maturity_date := l_new_maturity_date;
8322 l_loan_header_rec.loan_term := l_initial_months + i;
8323 l_loan_header_rec.loan_term_period := l_new_frequency;
8324
8325 lns_loan_header_pub.update_loan(p_object_version_number => l_version_number
8326 ,p_loan_header_rec => l_loan_header_rec
8327 ,p_init_msg_list => fnd_api.g_false
8328 ,x_return_status => l_return_status
8329 ,x_msg_count => l_msg_count
8330 ,x_msg_data => l_msg_data);
8331
8332 end if; -- open phase
8333 end if; -- custom payments
8334
8335 else
8336 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NOTHING TO MOVE');
8337 end if;
8338
8339 --
8340 -- End of API body
8341 -- ----------------------------------------------------------------
8342 --
8343 -- Standard check for p_commit
8344 IF FND_API.to_Boolean(p_commit) THEN
8345 COMMIT WORK;
8346 END IF;
8347
8348
8349 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8350
8351 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8352
8353 EXCEPTION
8354 WHEN FND_API.G_EXC_ERROR THEN
8355 ROLLBACK TO shiftLoan;
8356 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8357 x_return_status := FND_API.G_RET_STS_ERROR;
8358 x_msg_count := l_msg_count;
8359 x_msg_data := l_msg_data;
8360 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8361
8362 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8363 ROLLBACK TO shiftLoan;
8364 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8365 x_return_status := FND_API.G_RET_STS_ERROR;
8366 x_msg_count := l_msg_count;
8367 x_msg_data := l_msg_data;
8368 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8369
8370 WHEN OTHERS THEN
8371 ROLLBACK TO shiftLoan;
8372 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8373 x_return_status := FND_API.G_RET_STS_ERROR;
8374 x_msg_count := l_msg_count;
8375 x_msg_data := l_msg_data;
8376 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8377
8378 end shiftLoan;
8379
8380 /*=========================================================================
8381 || PUBLIC PROCEDURE shiftLoanDates
8382 ||
8383 || DESCRIPTION
8384 ||
8385 || Overview: procedure will return a new loan details record with
8386 || shifted dates
8387 ||
8388 || Parameter: p_loan_id = loan_id
8389 || p_new_start_Date = new start date of loan
8390 ||
8391 || Source Tables: NA
8392 ||
8393 || Target Tables:
8394 ||
8395 || Return value: x_loan_Details
8396 || detail record of the loan with the new dates
8397 ||
8398 || KNOWN ISSUES
8399 ||
8400 || NOTES
8401 ||
8402 || MODIFICATION HISTORY
8403 || Date Author Description of Changes
8404 || 11/29/2004 11:35AM raverma Created
8405 || 7/29/2005 raverma added p_phase
8406 || 14-JUL-2007 mbolli Bug#6169438 - Added new OUT parameter x_dates_shifted_flag
8407 *====================================================================================================*/
8408 procedure shiftLoanDates(p_loan_id in number
8409 ,p_new_start_date in date
8410 ,p_phase in varchar2
8411 ,x_loan_details out NOCOPY lns_financials.loan_details_rec
8412 ,x_dates_shifted_flag OUT NOCOPY VARCHAR2
8413 ,x_return_status OUT NOCOPY VARCHAR2
8414 ,x_msg_count OUT NOCOPY NUMBER
8415 ,x_msg_data OUT NOCOPY VARCHAR2)
8416 is
8417 l_return_status VARCHAR2(1);
8418 l_msg_count NUMBER;
8419 l_msg_data VARCHAR2(32767);
8420 l_api_name varchar2(25);
8421 l_loan_details lns_financials.loan_Details_rec;
8422 l_day_difference number;
8423 l_new_maturity_date date;
8424 l_new_first_payment_date date;
8425 x number;
8426 l_new_int_first_pay_date date;
8427 l_new_prin_first_pay_date date;
8428 l_shift_dates_proc varchar2(100);
8429 l_plsql_block varchar2(200);
8430
8431 begin
8432
8433 -- Standard Start of API savepoint
8434 SAVEPOINT shiftLoanDates;
8435 l_api_name := 'shiftLoanDates';
8436 x := 0;
8437
8438 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8439 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id = ' || p_loan_id);
8440 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_new_start_date = ' || p_new_start_date);
8441 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase = ' || p_phase);
8442
8443 -- Initialize API return status to SUCCESS
8444 x_return_status := FND_API.G_RET_STS_SUCCESS;
8445 x_dates_shifted_flag := 'N';
8446
8447 --
8448 -- Api body
8449 -- ----------------------------------------------------------------
8450 lns_utility_pub.validate_any_id(p_api_version => 1.0
8451 ,p_init_msg_list => 'T'
8452 ,x_msg_count => l_msg_count
8453 ,x_msg_data => l_msg_data
8454 ,x_return_status => l_return_status
8455 ,p_col_id => p_loan_id
8456 ,p_col_name => 'LOAN_ID'
8457 ,p_table_name => 'LNS_LOAN_HEADERS_ALL');
8458
8459 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
8460 FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
8461 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
8462 FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
8463 FND_MSG_PUB.ADD;
8464 RAISE FND_API.G_EXC_ERROR;
8465 end if;
8466
8467 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
8468 ,p_based_on_terms => 'ORIGINAL'
8469 ,p_phase => p_phase);
8470
8471 if l_loan_Details.loan_start_date = p_new_start_date then
8472 x_loan_details := l_loan_details;
8473 return;
8474 end if;
8475
8476 -- get the new maturity date
8477 l_new_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term => l_loan_Details.loan_term
8478 ,p_term_period => l_loan_Details.loan_term_period
8479 ,p_frequency => l_loan_Details.amortization_frequency
8480 ,p_start_date => p_new_start_date);
8481
8482 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_maturity_date ' || l_new_maturity_date);
8483
8484 -- fix for FP bug 6938095: get package.procedure from LNS_SHIFT_PAY_DATES_PROC profile and call it dynamically
8485 l_shift_dates_proc := NVL(FND_PROFILE.VALUE('LNS_SHIFT_PAY_DATES_PROC'), 'LNS_DEFAULT_HOOKS_PVT.SHIFT_PAY_START_DATES');
8486 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_shift_dates_proc: ' || l_shift_dates_proc);
8487
8488 l_plsql_block := 'BEGIN ' || l_shift_dates_proc || '(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10); END;';
8489
8490 BEGIN
8491
8492 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Calling...');
8493
8494 EXECUTE IMMEDIATE l_plsql_block
8495 USING
8496 IN p_loan_id,
8497 IN p_new_start_date,
8498 IN l_loan_details.loan_start_Date,
8499 IN l_loan_details.first_payment_Date,
8500 IN l_loan_details.PRIN_FIRST_PAY_DATE,
8501 IN l_loan_Details.maturity_Date,
8502 IN p_new_start_date,
8503 IN OUT l_new_maturity_date,
8504 OUT l_new_int_first_pay_date,
8505 OUT l_new_prin_first_pay_date;
8506
8507 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Done');
8508
8509 EXCEPTION
8510 WHEN OTHERS THEN
8511 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, 'ERROR: ' || sqlerrm);
8512 FND_MESSAGE.SET_NAME('LNS', 'LNS_API_OTHERS_EXCEP');
8513 FND_MESSAGE.SET_TOKEN('ERROR' ,SQLERRM);
8514 FND_MSG_PUB.ADD;
8515 RAISE FND_API.G_EXC_ERROR;
8516 END;
8517
8518 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_int_first_pay_date: ' || l_new_int_first_pay_date);
8519 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_prin_first_pay_date: ' || l_new_prin_first_pay_date);
8520 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_maturity_date: ' || l_new_maturity_date);
8521
8522 if l_new_int_first_pay_date is null or l_new_int_first_pay_date < p_new_start_date then
8523 FND_MESSAGE.SET_NAME('LNS', 'LNS_PAYMENT_START_DATE_ERROR2');
8524 FND_MSG_PUB.ADD;
8525 RAISE FND_API.G_EXC_ERROR;
8526 end if;
8527
8528 if l_new_int_first_pay_date > l_new_maturity_date then
8529 FND_MESSAGE.SET_NAME('LNS', 'LNS_PAYMENT_START_DATE_ERROR1');
8530 FND_MSG_PUB.ADD;
8531 RAISE FND_API.G_EXC_ERROR;
8532 end if;
8533
8534 if l_loan_details.PRIN_FIRST_PAY_DATE is not null then
8535 if l_new_prin_first_pay_date is null or l_new_prin_first_pay_date < p_new_start_date then
8536 FND_MESSAGE.SET_NAME('LNS', 'LNS_PRIN_PAY_START_DATE_ERROR2');
8537 FND_MSG_PUB.ADD;
8538 RAISE FND_API.G_EXC_ERROR;
8539 end if;
8540
8541 if l_new_prin_first_pay_date > l_new_maturity_date then
8542 FND_MESSAGE.SET_NAME('LNS', 'LNS_PRIN_PAY_START_DATE_ERROR1');
8543 FND_MSG_PUB.ADD;
8544 RAISE FND_API.G_EXC_ERROR;
8545 end if;
8546 end if;
8547
8548 -- assign the new dates to the loan details record
8549 l_loan_Details.loan_start_date := p_new_start_date;
8550 l_loan_details.first_payment_Date := l_new_int_first_pay_date;
8551 l_loan_details.PRIN_FIRST_PAY_DATE := l_new_prin_first_pay_date;
8552 l_loan_Details.maturity_Date := l_new_maturity_Date;
8553
8554 x_loan_details := l_loan_details;
8555 x_dates_shifted_flag := 'Y';
8556
8557 --
8558 -- End of API body
8559 --
8560 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8561
8562 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8563 EXCEPTION
8564 WHEN FND_API.G_EXC_ERROR THEN
8565 ROLLBACK TO shiftLoanDates;
8566 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8567 x_return_status := FND_API.G_RET_STS_ERROR;
8568 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8569
8570 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8571 ROLLBACK TO shiftLoanDates;
8572 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8573 x_return_status := FND_API.G_RET_STS_ERROR;
8574 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8575
8576 WHEN OTHERS THEN
8577 ROLLBACK TO shiftLoanDates;
8578 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8579 x_return_status := FND_API.G_RET_STS_ERROR;
8580 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8581 end shiftLoanDates;
8582
8583
8584 /*=========================================================================
8585 || PUBLIC PROCEDURE calculateEPPayment
8586 ||
8587 || DESCRIPTION
8588 ||
8589 || Overview: returns a termly equal principal payment amount for a loan
8590 ||
8591 || PSEUDO CODE/LOGIC
8592 ||
8593 || PARAMETERS
8594 ||
8595 || Parameter: p_loan_amount => amount of loan
8596 || p_num_intervals => number of installments for loan
8597 || p_ending_balance => future or residual value of the loan (most loans will pass 0)
8598 || p_pay_in_arrears => true if payments are at end of period
8599 || false otherwise
8600 ||
8601 || payment = (p_loan_amount - p_ending_balance) / p_num_intervals;
8602 ||
8603 || Return value: principal amount to pay per installment
8604 ||
8605 || Source Tables: NA
8606 ||
8607 || Target Tables: NA
8608 ||
8609 || KNOWN ISSUES
8610 ||
8611 || NOTES
8612 ||
8613 || MODIFICATION HISTORY
8614 || Date Author Description of Changes
8615 || 09/13/2007 scherkas Created
8616 *=======================================================================*/
8617 function calculateEPPayment(p_loan_amount in number
8618 ,p_num_intervals in number
8619 ,p_ending_balance in number
8620 ,p_pay_in_arrears in boolean) return number
8621
8622 is
8623 l_periodic_amount number;
8624 l_api_name varchar2(25);
8625
8626 begin
8627
8628 l_api_name := 'calculateEPPayment';
8629 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8630
8631 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ': loan amount is ' || p_loan_amount);
8632 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ending balance is ' || p_ending_balance);
8633 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number of intervals is ' || p_num_intervals);
8634
8635 l_periodic_amount := (p_loan_amount - p_ending_balance) / p_num_intervals;
8636
8637 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic_prin_amount: ' || l_periodic_amount);
8638 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8639
8640 return l_periodic_amount;
8641
8642 Exception
8643 When others then
8644 null;
8645
8646 end calculateEPPayment;
8647
8648
8649
8650 /*=========================================================================
8651 || PUBLIC PROCEDURE calculatePayment
8652 ||
8653 || DESCRIPTION
8654 ||
8655 || Overview: returns a termly payment amount for a loan
8656 ||
8657 || PSEUDO CODE/LOGIC
8658 ||
8659 || PARAMETERS
8660 ||
8661 || Parameter: p_annualized_rate => annual rate of the loan
8662 || p_loan_amount => amount of loan
8663 || p_num_intervals => number of installments for loan
8664 || p_ending_balance => future or residual value of the loan (most loans will pass 0)
8665 || p_pay_in_arrears => true if payments are at end of period
8666 || false otherwise
8667 ||
8668 || payment =
8669 || loan_amount x periodic_rate /
8670 || (1 - (1 / (1 + periodic_rate)^p_num_intervals )) -
8671 || p_ending_balance x periodic_rate /
8672 || ((1 + periodic_rate)^p_num_intervals -1)
8673 ||
8674 || Return value: amount to pay per installment
8675 ||
8676 || Source Tables: NA
8677 ||
8678 || Target Tables: NA
8679 ||
8680 || KNOWN ISSUES
8681 ||
8682 || NOTES
8683 ||
8684 || MODIFICATION HISTORY
8685 || Date Author Description of Changes
8686 || 12/11/2003 12:40PM raverma Created
8687 || 7/22/2003 raverma enable pay in arrears = false
8688 *=======================================================================*/
8689 function calculatePayment(p_loan_amount in number
8690 ,p_periodic_rate in number
8691 ,p_num_intervals in number
8692 ,p_ending_balance in number
8693 ,p_pay_in_arrears in boolean) return number
8694
8695 is
8696 l_periodic_amount number;
8697 l_numerator number;
8698 l_denominator number;
8699 l_api_name varchar2(25);
8700 l_num_intervals number;
8701
8702 begin
8703
8704 l_api_name := 'calculatePayment';
8705 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8706
8707 if p_pay_in_arrears then
8708 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' pay in arrears');
8709 else
8710 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' pay in advance');
8711 end if;
8712 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number of intervals is ' || p_num_intervals);
8713 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate is ' || p_periodic_rate);
8714 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ending balance is ' || p_ending_balance);
8715 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ': loan amount is ' || p_loan_amount);
8716
8717 l_num_intervals := p_num_intervals;
8718 if l_num_intervals = 0 then
8719 l_num_intervals := 1;
8720 end if;
8721 -- check for 0 percent interest
8722 -- this is the pay in arrears formula
8723
8724 if p_ending_balance = 0 then
8725
8726 if p_pay_in_arrears then
8727 if p_periodic_rate <> 0 then
8728 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 1');
8729 l_numerator := p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount;
8730 l_denominator := Power ((1 + p_periodic_rate), l_num_intervals) - 1;
8731 else
8732 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 2');
8733 l_numerator := Power (1, l_num_intervals) * p_loan_amount;
8734 l_denominator := l_num_intervals;
8735 end if;
8736 else
8737 if p_periodic_rate <> 0 then
8738 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 3');
8739 l_numerator := p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount;
8740 l_denominator := Power ((1 + p_periodic_rate), l_num_intervals) - 1;
8741 else
8742 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 4');
8743 l_numerator := Power (1, l_num_intervals - 1) * p_loan_amount;
8744 l_denominator := l_num_intervals;
8745 end if;
8746
8747 end if;
8748
8749 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': numerator:' || l_numerator);
8750 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': denominator:' || l_denominator);
8751
8752 l_periodic_amount := l_numerator / l_denominator;
8753
8754 else -- for case of balloon payment
8755
8756 if p_pay_in_arrears then
8757 if p_periodic_rate <> 0 then
8758
8759 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 5');
8760 l_periodic_amount := ( (p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount) / (Power ((1 + p_periodic_rate), l_num_intervals) - 1) ) +
8761 ( (p_periodic_rate * p_ending_balance) / ((1 + p_periodic_rate) - Power ((1 + p_periodic_rate), l_num_intervals + 1)) );
8762
8763 else
8764 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 6');
8765 l_periodic_amount := ( (Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount) / l_num_intervals ) -
8766 ( p_ending_balance / l_num_intervals );
8767 end if;
8768
8769 else
8770 if p_periodic_rate <> 0 then
8771 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 7');
8772 l_periodic_amount := ( (p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount) / (Power ((1 + p_periodic_rate), l_num_intervals) - 1) ) +
8773 ( (p_periodic_rate * p_ending_balance) / ((1 + p_periodic_rate) - Power ((1 + p_periodic_rate), l_num_intervals + 1)) );
8774 else
8775 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 8');
8776 l_periodic_amount := ( (Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount) / l_num_intervals ) -
8777 ( p_ending_balance / l_num_intervals );
8778 end if;
8779
8780 end if;
8781
8782 end if;
8783
8784 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic_amount: ' || l_periodic_amount);
8785 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8786
8787 return l_periodic_amount;
8788
8789 Exception
8790 When others then
8791 null;
8792
8793 end calculatePayment;
8794
8795 /*=========================================================================
8796 || PUBLIC PROCEDURE calculateInterest
8797 ||
8798 || DESCRIPTION
8799 ||
8800 || Overview: returns an interest due on a loan
8801 || we will use the formula:
8802 || FV = P*r^n
8803 || where FV = future value at a given point in time
8804 || PV = Present value of loan / capital
8805 || r = rate annualized
8806 || n = period of payment
8807 || to compound interest continually we use the formula:
8808 || FV = Pe^(Yr)
8809 || where Y = years and
8810 || e = 2.71828....
8811 ||
8812 || PSEUDO CODE/LOGIC
8813 ||
8814 || PARAMETERS
8815 ||
8816 || Parameter: p_amount = amount of loan
8817 || p_annual_rate = interest rate for loan expressed as a whole number
8818 || p_start_date = date at which interest is calculated
8819 || p_end_date = date at which interest in ended
8820 || p_compounding_period = for future use
8821 ||
8822 || Return value: amount interest due
8823 ||
8824 || Source Tables: NA
8825 ||
8826 || Target Tables: NA
8827 ||
8828 || KNOWN ISSUES
8829 ||
8830 || NOTES
8831 ||
8832 || MODIFICATION HISTORY
8833 || Date Author Description of Changes
8834 || 12/08/2003 10:56AM raverma Created
8835 || 03/17/2004 raverma don't allow negative interest for now
8836 *=======================================================================*/
8837 function calculateInterest(p_amount in number
8838 ,p_periodic_rate in number
8839 ,p_compounding_period in varchar2) return number
8840 is
8841 l_periodic_rate number;
8842 l_amount number;
8843 l_api_name varchar2(25);
8844
8845 begin
8846
8847 l_api_name := 'calculateInterest';
8848 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8849 if p_amount > 0 then
8850 l_amount := p_amount;
8851 else
8852 l_amount := 0;
8853 end if;
8854 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8855
8856 return l_amount * p_periodic_rate;
8857
8858 end calculateInterest;
8859
8860
8861
8862
8863
8864 procedure validatePayoff(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
8865 ,p_payoff_date in date
8866 ,p_reason in VARCHAR2
8867 ,x_return_status OUT NOCOPY VARCHAR2
8868 ,x_msg_count OUT NOCOPY NUMBER
8869 ,x_msg_data OUT NOCOPY VARCHAR2)
8870 is
8871 l_api_name varchar2(25);
8872 l_api_version_number number;
8873 l_return_status VARCHAR2(1);
8874 l_msg_count NUMBER;
8875 l_msg_data VARCHAR2(32767);
8876
8877 begin
8878
8879 -- Initialize API return status to SUCCESS
8880 x_return_status := FND_API.G_RET_STS_SUCCESS;
8881 l_api_name := 'validatePayoff';
8882 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8883 --
8884 -- Api body
8885 -- --------------------------------------------------------------------
8886
8887
8888 -- these dates should be further restricted
8889 if p_loan_details.loan_status = 'PAIDOFF' then
8890 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_ALREADY');
8891 FND_MSG_PUB.Add;
8892 RAISE FND_API.G_EXC_ERROR;
8893
8894 --karamach --Bug5295446 --Need to prevent payoff for loans in Approved status as well
8895 --elsif p_loan_details.loan_status = 'INCOMPLETE' or p_loan_details.loan_status = 'DELETED' or
8896 -- p_loan_details.loan_status = 'REJECTED' or p_loan_details.loan_status = 'PENDING' then
8897 elsif p_loan_details.loan_status IN ('INCOMPLETE','DELETED','REJECTED','PENDING') then
8898 FND_MESSAGE.Set_Name('LNS', 'LNS_INVOICE_SUMMARY_ERROR');
8899 FND_MSG_PUB.Add;
8900 RAISE FND_API.G_EXC_ERROR;
8901 end if;
8902
8903 if p_payoff_date < p_loan_details.last_interest_accrual then
8904 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff too early');
8905 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_TOO_EARLY');
8906 FND_MESSAGE.SET_TOKEN('PAYOFF_DATE', fnd_date.date_to_displaydate(p_loan_details.last_interest_accrual));
8907 FND_MSG_PUB.Add;
8908 RAISE FND_API.G_EXC_ERROR;
8909 end if;
8910
8911 if p_payoff_date < p_loan_details.last_activity_date then
8912 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff too early');
8913 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_TOO_EARLY2');
8914 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LAST_ACTIVITY_DATE');
8915 FND_MESSAGE.SET_TOKEN('VALUE', fnd_date.date_to_displaydate(p_loan_details.last_activity_date));
8916 FND_MSG_PUB.Add;
8917 RAISE FND_API.G_EXC_ERROR;
8918 end if;
8919
8920 if p_reason = 'PAYOFF' then
8921 /* raverma added 12-08-05 */
8922 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling LNS_FUNDING_PUB.validate_disb_for_payoff returns ');
8923 LNS_FUNDING_PUB.VALIDATE_DISB_FOR_PAYOFF(P_API_VERSION => 1.0
8924 ,P_INIT_MSG_LIST => FND_API.G_FALSE
8925 ,P_COMMIT => FND_API.G_FALSE
8926 ,P_VALIDATION_LEVEL => 100
8927 ,P_LOAN_ID => p_loan_details.loan_id
8928 ,x_return_status => l_return_status
8929 ,x_msg_count => l_msg_count
8930 ,x_msg_data => l_msg_data);
8931 if l_return_Status <> FND_API.G_RET_STS_SUCCESS then
8932 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - validate_disb_for_payoff returns ' || l_return_Status);
8933 RAISE FND_API.G_EXC_ERROR;
8934 end if;
8935 end if;
8936
8937 x_return_status := l_return_Status;
8938 -- --------------------------------------------------------------------
8939 -- End of API body
8940 --
8941
8942 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8943
8944 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8945
8946 exception
8947
8948 WHEN FND_API.G_EXC_ERROR THEN
8949 x_return_status := FND_API.G_RET_STS_ERROR;
8950 x_msg_count := l_msg_count;
8951 x_msg_data := l_msg_data;
8952 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8953 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8954
8955 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8956 x_return_status := FND_API.G_RET_STS_ERROR;
8957 x_msg_count := l_msg_count;
8958 x_msg_data := l_msg_data;
8959 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8960 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8961
8962 WHEN OTHERS THEN
8963 x_return_status := FND_API.G_RET_STS_ERROR;
8964 x_msg_count := l_msg_count;
8965 x_msg_data := l_msg_data;
8966 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8967 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8968
8969 end;
8970
8971
8972
8973 /*=========================================================================
8974 || PUBLIC FUNCTION validatePayoff
8975 ||
8976 || DESCRIPTION
8977 || contains validation rules on dates and statuses for a payoff
8978 ||
8979 || PSEUDO CODE/LOGIC
8980 ||
8981 || PARAMETERS
8982 ||
8983 || Return value:
8984 ||
8985 || Source Tables: NA
8986 ||
8987 || Target Tables: NA
8988 ||
8989 || KNOWN ISSUES
8990 ||
8991 || NOTES
8992 ||
8993 ||
8994 || MODIFICATION HISTORY
8995 || Date Author Description of Changes
8996 || 10/26/2004 12:55PM raverma Created
8997 *=======================================================================*/
8998 procedure validatePayoff(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
8999 ,p_payoff_date in date
9000 ,x_return_status OUT NOCOPY VARCHAR2
9001 ,x_msg_count OUT NOCOPY NUMBER
9002 ,x_msg_data OUT NOCOPY VARCHAR2)
9003 is
9004
9005 begin
9006
9007 lns_financials.validatePayoff(p_loan_details => p_loan_details
9008 ,p_payoff_date => p_payoff_date
9009 ,p_reason => 'PAYOFF'
9010 ,x_return_status => x_return_status
9011 ,x_msg_count => x_msg_count
9012 ,x_msg_data => x_msg_data);
9013
9014 end;
9015
9016
9017
9018
9019 procedure calcLoanRemainingAmounts(p_api_version IN NUMBER
9020 ,p_init_msg_list IN VARCHAR2
9021 ,p_loan_id in number
9022 ,p_date in date
9023 ,p_reason in varchar2
9024 ,x_payoff_tbl OUT NOCOPY LNS_FINANCIALS.PAYOFF_TBL2
9025 ,x_return_status OUT NOCOPY VARCHAR2
9026 ,x_msg_count OUT NOCOPY NUMBER
9027 ,x_msg_data OUT NOCOPY VARCHAR2)
9028 IS
9029
9030 l_api_name varchar2(25);
9031 l_api_version_number number;
9032 l_return_status VARCHAR2(1);
9033 l_msg_count NUMBER;
9034 l_msg_data VARCHAR2(32767);
9035
9036 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
9037 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
9038 l_annualized_rate number;
9039 l_periodic_rate number;
9040 l_additional_interest number;
9041 l_additional_fees number;
9042 l_payoff_tbl LNS_FINANCIALS.PAYOFF_TBL2;
9043 l_principal_unpaid number;
9044 l_interest_unpaid number;
9045 l_fees_unpaid number;
9046 l_payoff_date date;
9047 l_from_date date;
9048 l_to_date date;
9049 l_multipler number;
9050 l_balance number;
9051 l_current_phase varchar2(30);
9052 l_rate_type varchar2(30);
9053 l_index_rate_id number;
9054 l_norm_interest number;
9055 l_add_prin_interest number;
9056 l_add_int_interest number;
9057 l_penal_prin_interest number;
9058 l_penal_int_interest number;
9059 l_penal_interest number;
9060 l_add_start_date date;
9061 l_add_end_date date;
9062 l_prev_deferred_int number;
9063 l_prev_cap_int number;
9064 l_previous_annualized number;
9065 l_early_pay_cr number;
9066
9067 l_norm_int_detail_str varchar2(2000);
9068 l_add_prin_int_detail_str varchar2(2000);
9069 l_add_int_int_detail_str varchar2(2000);
9070 l_penal_prin_int_detail_str varchar2(2000);
9071 l_penal_int_int_detail_str varchar2(2000);
9072 l_penal_int_detail_str varchar2(2000);
9073 l_early_pay_cr_detail_str varchar2(2000);
9074
9075 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
9076 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
9077 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
9078 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
9079
9080 cursor c_additional_fees(p_loan_id number, p_phase varchar2, p_installment number) is
9081 select nvl(sum(sched.fee_amount), 0)
9082 from lns_fee_schedules sched
9083 ,lns_fees fees
9084 where sched.loan_id = p_loan_id
9085 and sched.fee_id = fees.fee_id
9086 and sched.active_flag = 'Y'
9087 and sched.billed_flag = 'N'
9088 and sched.phase = p_phase
9089 and sched.fee_installment <= decode(p_installment, -1, 1, (p_installment+1))
9090 and fees.fee_category <> 'RECUR';
9091
9092 cursor c_loan_info(p_loan_id number) is
9093 select nvl(h.current_phase, 'TERM')
9094 from lns_loan_headers h
9095 where h.loan_id = p_loan_id;
9096
9097 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
9098 select ACTIVITY_DATE
9099 from LNS_PRIN_TRX_ACTIVITIES_V
9100 where loan_id = p_loan_id
9101 and PAYMENT_NUMBER = p_installment_number
9102 and PARENT_AMORTIZATION_ID is null
9103 and ACTIVITY_CODE in ('BILLING', 'START');
9104
9105 cursor c_get_def_cap_amounts(p_loan_id number, p_installment_number number) is
9106 select nvl(DEFERRED_INT_AMOUNT, 0), nvl(CAP_INT_AMOUNT, 0)
9107 from LNS_AMORTIZATION_SCHEDS
9108 where loan_id = p_loan_id
9109 and PAYMENT_NUMBER = p_installment_number
9110 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
9111 and PARENT_AMORTIZATION_ID is null
9112 and nvl(PHASE, 'TERM') = 'TERM';
9113
9114 begin
9115
9116 l_api_name := 'calcLoanRemainingAmounts';
9117 l_api_version_number := 1;
9118 l_additional_interest := 0;
9119 l_additional_fees := 0;
9120 l_principal_unpaid := 0;
9121 l_interest_unpaid := 0;
9122 l_fees_unpaid := 0;
9123 l_balance := 0;
9124 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9125 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
9126 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_date ' || p_date);
9127 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_reason ' || p_reason);
9128
9129 -- Standard Start of API savepoint
9130 SAVEPOINT calculatePayoff;
9131
9132 -- Standard call to check for call compatibility.
9133 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
9134 l_api_name, G_PKG_NAME)
9135 THEN
9136 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
9137 END IF;
9138
9139 -- Initialize message list IF p_init_msg_list is set to TRUE.
9140 IF FND_API.to_Boolean(p_init_msg_list) THEN
9141 FND_MSG_PUB.initialize;
9142 END IF;
9143
9144 -- Initialize API return status to SUCCESS
9145 x_return_status := FND_API.G_RET_STS_SUCCESS;
9146
9147 --
9148 -- Api body
9149 -- --------------------------------------------------------------------
9150
9151 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting current phase');
9152 open c_loan_info(p_loan_id);
9153 fetch c_loan_info into l_current_phase;
9154 close c_loan_info;
9155 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - current phase ' || l_current_phase);
9156
9157 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
9158 ,p_based_on_terms => 'CURRENT'
9159 ,p_phase => l_current_phase);
9160 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, l_current_phase);
9161 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - got loan details and rate info');
9162
9163 lns_financials.validatePayoff(p_loan_details => l_loan_details
9164 ,p_payoff_date => p_date
9165 ,p_reason => p_reason
9166 ,x_return_status => l_return_status
9167 ,x_msg_count => l_msg_count
9168 ,x_msg_data => l_msg_data);
9169 IF l_return_status <> FND_API.G_RET_STS_SUCCESS THEN
9170 LogMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
9171 RAISE FND_API.G_EXC_ERROR;
9172 END IF;
9173
9174 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing late fees');
9175 lns_fee_engine.processLateFees(p_loan_id => p_loan_id
9176 ,p_init_msg_list => p_init_msg_list
9177 ,p_commit => 'F'
9178 ,p_phase => l_loan_details.LOAN_PHASE
9179 ,x_return_status => l_return_status
9180 ,x_msg_count => l_msg_count
9181 ,x_msg_data => l_msg_data);
9182
9183 if p_reason = 'PAYOFF' then
9184 -- fix for bug 9795950: adding payoff fees to payoff process
9185 l_fee_structures(1).fee_category := 'EVENT';
9186 l_fee_structures(1).fee_type := 'EVENT_PAYOFF';
9187 l_fee_structures(1).phase := l_loan_details.LOAN_PHASE;
9188
9189 -- filling out basis table
9190 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
9191 l_fee_basis_tbl(1).fee_basis_amount := l_loan_details.remaining_balance;
9192 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
9193 l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.requested_amount;
9194 l_fee_basis_tbl(3).fee_basis_name := 'TOTAL_DISB_AMT';
9195 l_fee_basis_tbl(3).fee_basis_amount := l_loan_details.funded_amount;
9196 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN';
9197 l_fee_basis_tbl(4).fee_basis_amount := l_loan_details.unpaid_principal;
9198 l_fee_basis_tbl(5).fee_basis_name := 'OVERDUE_PRIN_INT';
9199 l_fee_basis_tbl(5).fee_basis_amount := l_loan_details.unpaid_principal + l_loan_details.UNPAID_INTEREST;
9200 l_fee_basis_tbl(6).fee_basis_name := 'CURR_LOAN';
9201 l_fee_basis_tbl(6).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT;
9202 l_fee_basis_tbl(7).fee_basis_name := 'TOTAL_UNDISB_AMT';
9203 l_fee_basis_tbl(7).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT - l_loan_details.funded_amount;
9204 l_fee_basis_tbl(8).fee_basis_name := 'OVERDUE_INT';
9205 l_fee_basis_tbl(8).fee_basis_amount := l_loan_details.UNPAID_INTEREST;
9206
9207 lns_fee_engine.processFees(p_init_msg_list => FND_API.G_FALSE
9208 ,p_commit => FND_API.G_FALSE
9209 ,p_loan_id => p_loan_id
9210 ,p_installment_number => -1
9211 ,p_fee_basis_tbl => l_fee_basis_tbl
9212 ,p_fee_structures => l_fee_structures
9213 ,x_fees_tbl => l_fees_tbl
9214 ,x_return_status => l_return_Status
9215 ,x_msg_count => l_msg_count
9216 ,x_msg_data => l_msg_data);
9217
9218 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
9219 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
9220 FND_MSG_PUB.ADD;
9221 RAISE FND_API.G_EXC_ERROR;
9222 end if;
9223 end if;
9224
9225 if p_date < l_loan_details.last_interest_accrual then
9226 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff prior to last interest accrual');
9227 -- we will have a interest credit
9228 l_from_date := p_date;
9229 l_to_date := l_loan_details.last_interest_accrual;
9230 l_multipler := -1;
9231 /*
9232 l_balance := lns_financials.getAverageDailyBalance(p_loan_id => p_loan_id
9233 ,p_term_id => null
9234 ,p_from_date => p_date
9235 ,p_to_date => l_loan_details.last_interest_accrual
9236 ,p_calc_method => null);
9237 */
9238 else
9239 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff after lastinterest accrual');
9240 l_from_date := l_loan_details.last_interest_accrual;
9241 l_to_date := p_date;
9242 l_multipler := 1;
9243 -- l_balance := l_loan_details.remaining_balance;
9244 end if;
9245 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - computed principal balance: ' || l_balance);
9246 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - from date: ' || l_from_date);
9247 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - to date: ' || l_to_date);
9248 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_muliplier: ' || l_multipler);
9249
9250 BEGIN
9251 -- changes as per scherkas 11-16-2005
9252 select
9253 nvl(sum(SCHED.PRINCIPAL_REMAINING),0)
9254 ,nvl(sum(SCHED.INTEREST_REMAINING),0)
9255 ,nvl(sum(SCHED.FEE_REMAINING),0)
9256 into l_principal_unpaid
9257 ,l_interest_unpaid
9258 ,l_fees_unpaid
9259 from LNS_AM_SCHEDS_V SCHED
9260 ,LNS_LOAN_HEADERS H
9261 where H.loan_id = p_loan_id and
9262 H.loan_id = Sched.loan_id and
9263 SCHED.reversed_code = 'N' and
9264 nvl(sched.phase, 'TERM') = nvl(h.current_phase, 'TERM');
9265 Exception
9266 when no_data_found then
9267 null;
9268 END;
9269 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_principal_unpaid: ' || l_principal_unpaid);
9270 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_interest_unpaid: ' || l_interest_unpaid);
9271 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_fees_unpaid: ' || l_fees_unpaid);
9272 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - status: ' || l_loan_details.loan_status);
9273
9274 -- get the wtd rate if necessary
9275 if l_rate_tbl.count = 1 then
9276 l_annualized_rate := l_rate_tbl(1).annual_rate;
9277 else
9278 l_annualized_rate := lns_financials.getWeightedRate(p_loan_details => l_loan_details
9279 ,p_start_date => l_from_date
9280 ,p_end_date => l_to_date
9281 ,p_rate_tbl => l_rate_tbl);
9282 end if;
9283 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_annualized_rate: ' || l_annualized_rate);
9284
9285 l_norm_interest := 0;
9286 l_add_prin_interest := 0;
9287 l_add_int_interest := 0;
9288 l_penal_prin_interest := 0;
9289 l_penal_int_interest := 0;
9290 l_penal_interest := 0;
9291 l_norm_int_detail_str := null;
9292 l_add_prin_int_detail_str := null;
9293 l_add_int_int_detail_str := null;
9294 l_penal_prin_int_detail_str := null;
9295 l_penal_int_int_detail_str := null;
9296 l_penal_int_detail_str := null;
9297
9298 -- get additional interest start date
9299 open c_get_last_bill_date(p_loan_id, l_loan_details.last_installment_billed);
9300 fetch c_get_last_bill_date into l_add_start_date;
9301 close c_get_last_bill_date;
9302
9303 -- get additional interest end date
9304 if trunc(l_add_start_date) > trunc(l_from_date) then
9305 l_add_start_date := l_from_date;
9306 end if;
9307 l_add_end_date := l_to_date;
9308
9309 -- get previously deferred interest
9310 open c_get_def_cap_amounts(p_loan_id, l_loan_details.last_installment_billed);
9311 fetch c_get_def_cap_amounts into l_prev_deferred_int, l_prev_cap_int;
9312 close c_get_def_cap_amounts;
9313 if l_prev_deferred_int is null then
9314 l_prev_deferred_int := 0;
9315 end if;
9316 if l_prev_cap_int is null then
9317 l_prev_cap_int := 0;
9318 end if;
9319 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_deferred_int = ' || l_prev_deferred_int);
9320 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
9321
9322 -- calculate normal interest
9323 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
9324 LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => p_loan_id,
9325 p_calc_method => l_loan_details.CALCULATION_METHOD,
9326 p_period_start_date => l_from_date,
9327 p_period_end_date => l_to_date,
9328 p_interest_rate => l_annualized_rate,
9329 p_day_count_method => l_loan_details.day_count_method,
9330 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9331 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9332 p_adj_amount => 0,
9333 p_CAP_AMOUNT => l_prev_cap_int,
9334 x_norm_interest => l_norm_interest,
9335 x_norm_int_details => l_norm_int_detail_str);
9336
9337 l_norm_interest := round(l_norm_interest, l_loan_details.currency_precision);
9338
9339 -- calculate additional interest on unpaid principal
9340 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
9341 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => p_loan_id,
9342 p_calc_method => l_loan_details.CALCULATION_METHOD,
9343 p_period_start_date => l_add_start_date,
9344 p_period_end_date => l_add_end_date,
9345 p_interest_rate => l_annualized_rate,
9346 p_day_count_method => l_loan_details.day_count_method,
9347 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9348 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9349 p_penal_int_rate => l_loan_details.PENAL_INT_RATE,
9350 p_prev_grace_end_date => l_from_date,
9351 p_grace_start_date => l_from_date,
9352 p_grace_end_date => (l_from_date + l_loan_details.PENAL_INT_GRACE_DAYS),
9353 p_target => 'UNPAID_PRIN',
9354 x_add_interest => l_add_prin_interest,
9355 x_penal_interest => l_penal_prin_interest,
9356 x_add_int_details => l_add_prin_int_detail_str,
9357 x_penal_int_details => l_penal_prin_int_detail_str);
9358 l_add_prin_interest := round(l_add_prin_interest, l_loan_details.currency_precision);
9359
9360 -- calculate additional interest on unpaid interest
9361 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
9362 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => p_loan_id,
9363 p_calc_method => l_loan_details.CALCULATION_METHOD,
9364 p_period_start_date => l_add_start_date,
9365 p_period_end_date => l_add_end_date,
9366 p_interest_rate => l_annualized_rate,
9367 p_day_count_method => l_loan_details.day_count_method,
9368 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9369 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9370 p_penal_int_rate => l_loan_details.PENAL_INT_RATE,
9371 p_prev_grace_end_date => l_from_date,
9372 p_grace_start_date => l_from_date,
9373 p_grace_end_date => (l_from_date + l_loan_details.PENAL_INT_GRACE_DAYS),
9374 p_target => 'UNPAID_INT',
9375 x_add_interest => l_add_int_interest,
9376 x_penal_interest => l_penal_int_interest,
9377 x_add_int_details => l_add_int_int_detail_str,
9378 x_penal_int_details => l_penal_int_int_detail_str);
9379 l_add_int_interest := round(l_add_int_interest, l_loan_details.currency_precision);
9380
9381 l_rate_details := getRateDetails(p_installment => (l_loan_details.last_installment_billed + 1)
9382 ,p_rate_tbl => l_rate_tbl);
9383 l_previous_annualized := l_rate_details.annual_rate;
9384
9385 -- calculate interest credit on early payment
9386 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
9387 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => p_loan_id,
9388 p_calc_method => l_loan_details.CALCULATION_METHOD,
9389 p_installment => (l_loan_details.last_installment_billed + 1),
9390 p_interest_rate => l_previous_annualized,
9391 p_day_count_method => l_loan_details.day_count_method,
9392 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9393 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9394 x_early_pay_cr => l_early_pay_cr,
9395 x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
9396
9397 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_loan_details.currency_precision);
9398 l_additional_interest := (l_prev_deferred_int + l_prev_cap_int + l_norm_interest + l_add_prin_interest +
9399 l_add_int_interest + l_penal_interest - l_early_pay_cr) * l_multipler;
9400 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
9401 l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
9402 else
9403 l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
9404 end if;
9405 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_additional_interest: ' || l_additional_interest);
9406
9407 begin
9408 open c_additional_fees(p_loan_id, l_current_phase, l_loan_details.last_installment_billed);
9409 fetch c_additional_fees into l_additional_fees;
9410 close c_additional_fees;
9411 exception when no_data_found then
9412 null;
9413 end;
9414
9415 l_payoff_tbl(1).PAYOFF_PURPOSE := 'PRIN';
9416 l_payoff_tbl(1).BILLED_AMOUNT := l_principal_unpaid;
9417 l_payoff_tbl(1).UNBILLED_AMOUNT := l_loan_details.remaining_balance - l_principal_unpaid;
9418 l_payoff_tbl(1).TOTAL_AMOUNT := l_loan_details.remaining_balance;
9419
9420 l_payoff_tbl(2).PAYOFF_PURPOSE := 'INT';
9421 l_payoff_tbl(2).BILLED_AMOUNT := l_interest_unpaid;
9422 l_payoff_tbl(2).UNBILLED_AMOUNT := l_additional_interest;
9423 l_payoff_tbl(2).TOTAL_AMOUNT := l_additional_interest + l_interest_unpaid;
9424
9425 l_payoff_tbl(3).PAYOFF_PURPOSE := 'FEE';
9426 l_payoff_tbl(3).BILLED_AMOUNT := l_fees_unpaid;
9427 l_payoff_tbl(3).UNBILLED_AMOUNT := l_additional_fees;
9428 l_payoff_tbl(3).TOTAL_AMOUNT := l_fees_unpaid + l_additional_fees;
9429
9430 x_payoff_tbl := l_payoff_tbl;
9431
9432 -- --------------------------------------------------------------------
9433 -- End of API body
9434 --
9435
9436 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9437
9438 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9439
9440 EXCEPTION
9441 WHEN FND_API.G_EXC_ERROR THEN
9442 ROLLBACK TO calculatePayoff;
9443 x_return_status := FND_API.G_RET_STS_ERROR;
9444 x_msg_count := l_msg_count;
9445 x_msg_data := l_msg_data;
9446 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9447 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
9448
9449 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
9450 ROLLBACK TO calculatePayoff;
9451 x_return_status := FND_API.G_RET_STS_ERROR;
9452 x_msg_count := l_msg_count;
9453 x_msg_data := l_msg_data;
9454 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9455 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
9456
9457 WHEN OTHERS THEN
9458 ROLLBACK TO calculatePayoff;
9459 x_return_status := FND_API.G_RET_STS_ERROR;
9460 x_msg_count := l_msg_count;
9461 x_msg_data := l_msg_data;
9462 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9463 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
9464
9465 end;
9466
9467
9468
9469 /*=========================================================================
9470 || PUBLIC FUNCTION calculatePayoff
9471 ||
9472 || DESCRIPTION
9473 || calculate any additional interest due on loan, etc fees, to
9474 || pay off
9475 ||
9476 || PSEUDO CODE/LOGIC
9477 || 1. get number of interest rates running over remaining period
9478 || 2. get weighted average of those rates
9479 || 3. calculate interest due on remaining principal
9480 || from payoff_date
9481 ||
9482 || PARAMETERS
9483 || p_loan_id => loan_id to payoff
9484 || p_payoff_date => date at which to payoff the loan
9485 ||
9486 || Return value:
9487 ||
9488 || Source Tables: NA
9489 ||
9490 || Target Tables: NA
9491 ||
9492 || KNOWN ISSUES
9493 ||
9494 || NOTES
9495 ||
9496 ||
9497 || MODIFICATION HISTORY
9498 || Date Author Description of Changes
9499 || 03/24/2004 12:55PM raverma Created
9500 || 04/15/2004 raverma check to see if loan is PAIDOFF
9501 *=======================================================================*/
9502 procedure calculatePayoff(p_api_version IN NUMBER
9503 ,p_init_msg_list IN VARCHAR2
9504 ,p_loan_id in number
9505 ,p_payoff_date in date
9506 ,x_payoff_tbl OUT NOCOPY LNS_FINANCIALS.PAYOFF_TBL2
9507 ,x_return_status OUT NOCOPY VARCHAR2
9508 ,x_msg_count OUT NOCOPY NUMBER
9509 ,x_msg_data OUT NOCOPY VARCHAR2)
9510 IS
9511 l_payoff_tbl LNS_FINANCIALS.PAYOFF_TBL2;
9512 begin
9513
9514 calcLoanRemainingAmounts(p_api_version => 1.0
9515 ,p_init_msg_list => p_init_msg_list
9516 ,p_loan_id => p_loan_id
9517 ,p_date => p_payoff_date
9518 ,p_reason => 'PAYOFF'
9519 ,x_payoff_tbl => l_payoff_tbl
9520 ,x_return_status => x_return_status
9521 ,x_msg_count => x_msg_count
9522 ,x_msg_data => x_msg_data);
9523
9524 x_payoff_tbl := l_payoff_tbl;
9525
9526 end;
9527
9528
9529
9530 -- Introduced to fix bug 7565117
9531 procedure get_factors(p_frequency in varchar2,
9532 p_days_in_year in number,
9533 x_ppy in out nocopy number,
9534 x_days_in_period in out nocopy number)
9535 is
9536 l_days_in_year number;
9537 begin
9538
9539 if p_frequency = 'DAILY' then
9540 x_ppy := p_days_in_year;
9541 elsif p_frequency = 'WEEKLY' then
9542 x_ppy := 52;
9543 elsif p_frequency = 'BIWEEKLY' then
9544 x_ppy := 26;
9545 elsif p_frequency = 'SEMI-MONTHLY' then
9546 x_ppy := 24;
9547 elsif p_frequency = 'MONTHLY' then
9548 x_ppy := 12;
9549 elsif p_frequency = 'BI-MONTHLY' then
9550 x_ppy := 6;
9551 elsif p_frequency = 'QUARTERLY' then
9552 x_ppy := 4;
9553 elsif p_frequency = 'SEMI-ANNUALLY' then
9554 x_ppy := 2;
9555 elsif p_frequency = 'YEARLY' then
9556 x_ppy := 1;
9557 else
9558 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_INTERVAL');
9559 FND_MESSAGE.SET_TOKEN('INTERVAL',p_frequency);
9560 FND_MSG_PUB.Add;
9561 RAISE FND_API.G_EXC_ERROR;
9562 end if;
9563
9564 x_days_in_period := p_days_in_year/x_ppy;
9565 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_ppy = ' || x_ppy);
9566 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_days_in_period = ' || x_days_in_period);
9567
9568 end;
9569
9570
9571 /*=========================================================================
9572 || PUBLIC PROCEDURE getCompoundPeriodicRate
9573 ||
9574 || DESCRIPTION
9575 ||
9576 || Overview: this function will return the compound interest rate
9577 ||
9578 || Parameters:
9579 || p_compound_freq - mandatory; compounding frequency
9580 || p_payment_freq - mandatory; payment frequency
9581 || p_start_date - optional; start date of rate
9582 || p_end_date - optional; end date of rate
9583 || p_annualized rate - mandatory; interest rate expressed as a WHOLE number
9584 || p_days_count_method - mandatory; day count method
9585 ||
9586 || Source Tables: NA
9587 ||
9588 || Target Tables: NA
9589 ||
9590 || Return value: compound periodic interest rate on the loan
9591 ||
9592 | KNOWN ISSUES
9593 |
9594 | NOTES
9595 ||
9596 || MODIFICATION HISTORY
9597 || Date Author Description of Changes
9598 || 09/21/2007 scherkas Created
9599 || 4/08/2008 scherkas Fix logic to work with any number of years between period_start_date and period_end_date
9600 *=======================================================================*/
9601 function getCompoundPeriodicRate(p_compound_freq in varchar2
9602 ,p_payment_freq in varchar2
9603 ,p_annualized_rate in number
9604 ,p_period_start_date in date
9605 ,p_period_end_date in date
9606 ,p_days_count_method in varchar2
9607 ,p_target in varchar2) return number
9608 is
9609 l_periodic_rate number;
9610 l_day_count number;
9611 l_days_in_year number;
9612 l_api_name varchar2(25);
9613 l_year1 number;
9614 l_year2 number;
9615 l_rate1 number;
9616 l_days_ratio number;
9617 l_payments_per_year number;
9618 l_compounds_per_year number;
9619 l_start_date date;
9620 l_end_date date;
9621 l_days_in_period number;
9622 l_total_periodic_rate number;
9623 l_avrg_days_in_years number;
9624 l_years_count number;
9625
9626 begin
9627
9628 l_api_name := 'getCompoundPeriodicRate';
9629 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9630 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_compound_freq: ' || p_compound_freq);
9631 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_payment_freq: ' || p_payment_freq);
9632 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_annualized_rate: ' || p_annualized_rate);
9633 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_days_count_method: ' || p_days_count_method);
9634 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_period_start_date: ' || p_period_start_date);
9635 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_period_end_date: ' || p_period_end_date);
9636 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_target: ' || p_target);
9637
9638 select to_number(to_char(p_period_start_date, 'YYYY')) into l_year1 from dual;
9639 select to_number(to_char(p_period_end_date, 'YYYY')) into l_year2 from dual;
9640
9641 l_periodic_rate := 0;
9642 l_total_periodic_rate := 0;
9643
9644 if p_target = 'INTEREST' then
9645
9646 l_days_ratio := 0;
9647 l_avrg_days_in_years := 0;
9648 l_years_count := 0;
9649
9650 for k in l_year1..l_year2 loop
9651
9652 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ------ Calculating for year ' || k);
9653 l_periodic_rate := 0;
9654 l_rate1 := 0;
9655 l_day_count := 0;
9656 l_days_in_year := 0;
9657
9658 if k = l_year1 then
9659 l_start_date := p_period_start_date;
9660 else
9661 l_start_date := l_end_date;
9662 end if;
9663
9664 if k = l_year2 then
9665 l_end_date := p_period_end_date;
9666 else
9667 l_end_date := to_date('01/01/' || to_char(k+1),'DD/MM/YYYY');
9668 end if;
9669
9670 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_start_date = ' || l_start_date);
9671 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_date = ' || l_end_date);
9672
9673 l_day_count := LNS_FIN_UTILS.getDayCount(p_start_date => l_start_date
9674 ,p_end_date => l_end_date
9675 ,p_day_count_method => p_days_count_method);
9676
9677 l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year => k
9678 ,p_year_count_method => p_days_count_method);
9679
9680 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_day_count = ' || l_day_count);
9681 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_days_in_year = ' || l_days_in_year);
9682
9683 get_factors(p_frequency => p_compound_freq,
9684 p_days_in_year => l_days_in_year,
9685 x_ppy => l_compounds_per_year,
9686 x_days_in_period => l_days_in_period);
9687 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compounds per year = ' || l_compounds_per_year);
9688
9689 get_factors(p_frequency => p_payment_freq,
9690 p_days_in_year => l_days_in_year,
9691 x_ppy => l_payments_per_year,
9692 x_days_in_period => l_days_in_period);
9693 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payments_per_year = ' || l_payments_per_year);
9694 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_days_in_period = ' || l_days_in_period);
9695
9696 l_periodic_rate := l_day_count/l_days_in_period * (Power((1+((p_annualized_rate)/(100*l_compounds_per_year))),(l_compounds_per_year/l_payments_per_year))-1);
9697 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate = ' || l_periodic_rate);
9698
9699 l_total_periodic_rate := l_total_periodic_rate + l_periodic_rate;
9700 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_total_periodic_rate = ' || l_total_periodic_rate);
9701
9702 end loop;
9703
9704 else
9705
9706 l_avrg_days_in_years := 0;
9707 l_years_count := 0;
9708 for k in l_year1..l_year2 loop
9709
9710 l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year => k
9711 ,p_year_count_method => p_days_count_method);
9712
9713 l_avrg_days_in_years := l_avrg_days_in_years + l_days_in_year;
9714 l_years_count := l_years_count + 1;
9715
9716 end loop;
9717
9718 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_years_count = ' || l_years_count);
9719 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total number of days in all years = ' || l_avrg_days_in_years);
9720
9721 l_avrg_days_in_years := l_avrg_days_in_years / l_years_count;
9722 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_avrg_days_in_years = ' || l_avrg_days_in_years);
9723
9724 get_factors(p_frequency => p_payment_freq,
9725 p_days_in_year => l_avrg_days_in_years,
9726 x_ppy => l_payments_per_year,
9727 x_days_in_period => l_days_in_period);
9728 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': avarage payments per year = ' || l_payments_per_year);
9729
9730 get_factors(p_frequency => p_compound_freq,
9731 p_days_in_year => l_avrg_days_in_years,
9732 x_ppy => l_compounds_per_year,
9733 x_days_in_period => l_days_in_period);
9734 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compounds per year = ' || l_compounds_per_year);
9735
9736 l_total_periodic_rate := Power((1+((p_annualized_rate)/(100*l_compounds_per_year))),(l_compounds_per_year/l_payments_per_year))-1;
9737 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_total_periodic_rate = ' || l_total_periodic_rate);
9738
9739 end if;
9740
9741 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-------------');
9742 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Final Periodic rate ' || l_total_periodic_rate);
9743 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9744
9745 return l_total_periodic_rate;
9746
9747 end getCompoundPeriodicRate;
9748
9749
9750 /*=========================================================================
9751 || PUBLIC PROCEDURE getPeriodicRate
9752 ||
9753 || DESCRIPTION
9754 ||
9755 || Overview: this function will return the interest rate for a given
9756 || period of time so the interest in a give month at
9757 || 12% interest per year will return a 1% monthly rate
9758 || (30 /360 methodology)
9759 ||
9760 || Parameter: p_start_date optional start date of rate
9761 || p_end_date optional end date of rate
9762 || p_annualized rate = interest rate expressed as a WHOLE number
9763 || p_days_count_method = for future use
9764 ||
9765 || Source Tables: NA
9766 ||
9767 || Target Tables: NA
9768 ||
9769 || Return value: periodic interest rate on the loan
9770 ||
9771 | KNOWN ISSUES
9772 |
9773 | NOTES
9774 ||
9775 || MODIFICATION HISTORY
9776 || Date Author Description of Changes
9777 || 12/09/2003 1:51PM raverma Created
9778 || 2/26/2004 raverma added more robust day / year counting methodolgy
9779 || 7/22/2004 raverma handle situation where start date = end date
9780 || 3/22/2006 karamach Fix date format issue for bug5112031
9781 || 4/08/2008 scherkas Fix logic to work with any number of years between period_start_date and period_end_date
9782 *=======================================================================*/
9783 function getPeriodicRate(p_payment_freq in varchar2
9784 ,p_period_start_date in date
9785 ,p_period_end_date in date
9786 ,p_annualized_rate in number
9787 ,p_days_count_method in varchar2
9788 ,p_target in varchar2) return number
9789 is
9790 l_annual_rate number;
9791 l_periodic_rate number;
9792 l_day_count number;
9793 l_days_in_year number;
9794 l_api_name varchar2(25);
9795 l_year1 number;
9796 l_year2 number;
9797 l_periodic_factor number;
9798 l_rate1 number;
9799 l_rate2 number;
9800 l_start_date date;
9801 l_end_date date;
9802 l_avrg_days_in_years number;
9803 l_years_count number;
9804 l_payments_per_year number;
9805 l_days_in_period number;
9806
9807 begin
9808
9809 l_api_name := 'getPeriodicRate';
9810 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9811 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_days_count_method);
9812 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': annualized rate: ' || p_annualized_rate);
9813 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
9814 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
9815 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_target: ' || p_target);
9816
9817 l_annual_rate := p_annualized_rate / 100;
9818 l_periodic_rate := 0;
9819
9820 select to_number(to_char(p_period_start_date, 'YYYY')) into l_year1 from dual;
9821 select to_number(to_char(p_period_end_date, 'YYYY')) into l_year2 from dual;
9822
9823 if p_target = 'INTEREST' then
9824
9825 for k in l_year1..l_year2 loop
9826
9827 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ------ Calculating for year ' || k);
9828 l_rate1 := 0;
9829 l_day_count := 0;
9830 l_days_in_year := 0;
9831
9832 if k = l_year1 then
9833 l_start_date := p_period_start_date;
9834 else
9835 l_start_date := l_end_date;
9836 end if;
9837
9838 if k = l_year2 then
9839 l_end_date := p_period_end_date;
9840 else
9841 l_end_date := to_date('01/01/' || to_char(k+1),'DD/MM/YYYY');
9842 end if;
9843
9844 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_start_date = ' || l_start_date);
9845 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_date = ' || l_end_date);
9846
9847 l_day_count := LNS_FIN_UTILS.getDayCount(p_start_date => l_start_date
9848 ,p_end_date => l_end_date
9849 ,p_day_count_method => p_days_count_method);
9850
9851 l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year => k
9852 ,p_year_count_method => p_days_count_method);
9853
9854 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_day_count = ' || l_day_count);
9855 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_days_in_year = ' || l_days_in_year);
9856
9857 l_rate1 := (l_day_count / l_days_in_year) * l_annual_rate;
9858 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate1 = ' || l_rate1);
9859
9860 l_periodic_rate := l_periodic_rate + l_rate1;
9861 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic rate = ' || l_periodic_rate);
9862
9863 end loop;
9864
9865 else
9866
9867 l_avrg_days_in_years := 0;
9868 l_years_count := 0;
9869 for k in l_year1..l_year2 loop
9870
9871 l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year => k
9872 ,p_year_count_method => p_days_count_method);
9873
9874 l_avrg_days_in_years := l_avrg_days_in_years + l_days_in_year;
9875 l_years_count := l_years_count + 1;
9876
9877 end loop;
9878
9879 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_years_count = ' || l_years_count);
9880 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total number of days in all years = ' || l_avrg_days_in_years);
9881
9882 l_avrg_days_in_years := l_avrg_days_in_years / l_years_count;
9883 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': avarage days_in_year = ' || l_avrg_days_in_years);
9884
9885 get_factors(p_frequency => p_payment_freq,
9886 p_days_in_year => l_avrg_days_in_years,
9887 x_ppy => l_payments_per_year,
9888 x_days_in_period => l_days_in_period);
9889 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payments_per_year = ' || l_payments_per_year);
9890
9891 l_periodic_rate := l_annual_rate / l_payments_per_year;
9892
9893 end if;
9894
9895 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-------------');
9896 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Final Periodic rate ' || l_periodic_rate);
9897 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9898
9899 return l_periodic_rate;
9900
9901 end getPeriodicRate;
9902
9903 /*
9904 ||
9905 || Parameter: p_rate = annualized interest rate
9906 || p_period_value = time factor like '2'
9907 || p_period_type = 'DAILY', 'WEEKLY', 'BI-WEEKLY', 'MONTHLY'
9908 || 'BI-MONTHLY',
9909 || Return value:
9910 ||
9911 || Source Tables:
9912 ||
9913 || Target Tables:
9914 ||
9915 || Creation date: 12/08/2003 3:33PM
9916 ||
9917 || Major Modifications: when who what
9918 ||
9919 */
9920 function compoundInterest(p_rate in number
9921 ,p_period_value in number
9922 ,p_period_type in varchar2) return number
9923 is
9924 begin
9925 null;
9926 end compoundInterest;
9927
9928 /*=========================================================================
9929 || PUBLIC PROCEDURE getAnnualRate
9930 ||
9931 || DESCRIPTION
9932 ||
9933 || Overview: gets the current interest rate for the loan
9934 ||
9935 || Parameter: loan_id
9936 ||
9937 || Return value: current annual rate for the loan
9938 ||
9939 || Source Tables: LNS_RATE_SCHEDULES
9940 ||
9941 || Target Tables: NA
9942 ||
9943 || KNOWN ISSUES
9944 ||
9945 || NOTES
9946 ||
9947 || MODIFICATION HISTORY
9948 || Date Author Description of Changes
9949 || 12/15/2003 4:28PM raverma Created
9950 ||
9951 *=======================================================================*/
9952 function getAnnualRate(p_loan_Id in number) return number
9953 is
9954 l_rate number;
9955 l_api_name varchar2(20);
9956
9957 begin
9958
9959 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9960
9961 select rs.current_interest_rate into l_rate
9962 from lns_rate_schedules rs,
9963 lns_terms t,
9964 lns_loan_headers_all h
9965 where h.loan_id = p_loan_id
9966 and h.loan_id = t.loan_id
9967 and rs.term_id = t.term_id
9968 and rs.start_date_active <= sysdate
9969 and rs.end_date_active >= sysdate;
9970
9971 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9972
9973 return l_rate;
9974
9975 Exception
9976
9977 When Others then
9978 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Error: ' || sqlerrm);
9979 --seed this message
9980 -- FND_MESSAGE.Set_Name('LNS', 'LNS_UNABLE_TO_COMPUTE_BALANCE');
9981 -- FND_MSG_PUB.Add;
9982 -- RAISE FND_API.G_EXC_ERROR;
9983
9984 end getAnnualRate;
9985
9986 /*=========================================================================
9987 || PUBLIC PROCEDURE getActiveRate
9988 ||
9989 || DESCRIPTION
9990 ||
9991 || Overview: gets the current interest rate for the loan
9992 || we will look at the last installment billed (not reversed)
9993 || to get the rate on the loan
9994 || Parameter: loan_id
9995 ||
9996 || Return value: current annual rate for the loan
9997 ||
9998 || Source Tables: LNS_RATE_SCHEDULES,
9999 ||
10000 || Target Tables: NA
10001 ||
10002 || KNOWN ISSUES
10003 ||
10004 || NOTES
10005 ||
10006 || MODIFICATION HISTORY
10007 || Date Author Description of Changes
10008 || 3/8/2004 4:28PM raverma Created
10009 ||
10010 *=======================================================================*/
10011 function getActiveRate(p_loan_id in number) return number
10012 is
10013 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
10014 l_last_installment number;
10015 l_active_rate number;
10016 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
10017
10018
10019 begin
10020
10021 l_active_rate := -1;
10022 l_rate_tbl := getRateSchedule(p_loan_id, 'TERM');
10023
10024 if l_rate_tbl.count = 1 then
10025 l_active_rate := l_rate_tbl(1).annual_rate;
10026
10027 else
10028
10029 begin
10030
10031 l_last_installment := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id);
10032
10033 if l_last_installment = 0
10034 then l_last_installment := 1;
10035 end if;
10036
10037 exception when others then
10038 l_last_installment := 1;
10039 end;
10040 l_rate_details := getRateDetails(p_installment => l_last_installment
10041 ,p_rate_tbl => l_rate_tbl);
10042 l_active_rate := l_rate_Details.annual_rate;
10043
10044 end if;
10045
10046 return l_active_rate;
10047
10048 end getActiveRate;
10049
10050
10051 /*=========================================================================
10052 || PUBLIC PROCEDURE calculateInterestRate
10053 ||
10054 || DESCRIPTION
10055 ||
10056 || Overview: function to calcualte interest for a variableRate Loan
10057 ||
10058 || Parameter:
10059 || p_initial_rate in number => initial interest rate for loan
10060 || p_last_period_rate in number => last periodic rate
10061 || p_max_period_adjustment in number => maximum rate diff between adjustments
10062 || p_max_lifetime_adjustment in number => maximum lifetime rate difference
10063 || p_ceiling in number => maximum rate
10064 || p_floor in number => minimum rate
10065 || p_rate_to_compare in number => index rate plus spread
10066 ||
10067 || Return value: variable interest rate
10068 ||
10069 || Source Tables: NA
10070 ||
10071 || Target Tables: NA
10072 ||
10073 || KNOWN ISSUES
10074 ||
10075 || NOTES
10076 ||
10077 || Creation date: 12/08/2003 6:31PM
10078 ||
10079 || Major Modifications: when who what
10080 || 11/20/2005 raverma created
10081 *=======================================================================*/
10082 function calculateInterestRate(p_initial_rate in number
10083 ,p_rate_to_compare in number
10084 ,p_last_period_rate in number
10085 ,p_max_first_adjustment in number
10086 ,p_max_period_adjustment in number
10087 ,p_max_lifetime_adjustment in number
10088 ,p_ceiling_rate in number
10089 ,p_floor_rate in number
10090 ,p_installment_number in number) return number
10091
10092 is
10093 l_new_rate number;
10094 l_rate_diff number;
10095 l_life_rate_diff number;
10096 l_sign1 number;
10097 l_sign2 number;
10098 l_api_name varchar2(30);
10099
10100 begin
10101
10102 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10103 -- need to check for NULLs
10104 l_rate_diff := ABS(p_rate_to_compare - p_last_period_rate);
10105 l_life_rate_diff := ABS(p_rate_to_compare - p_initial_rate);
10106 l_sign1 := 1;
10107 l_sign2 := 1;
10108 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_diff ' || l_rate_diff);
10109 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_life_rate_diff ' || l_life_rate_diff);
10110
10111 -- rate differentials go both ways
10112 if p_rate_to_compare < p_last_period_rate then
10113 l_sign1 := -1;
10114 end if;
10115
10116 -- rate differentials go both ways
10117 if p_rate_to_compare < p_initial_rate then
10118 l_sign2 := -1;
10119 end if;
10120
10121 l_new_rate := p_rate_to_compare;
10122
10123 if l_new_rate > p_ceiling_rate and p_ceiling_rate is not null then
10124 l_new_rate := p_ceiling_rate;
10125 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was above CEILING of: ' || p_ceiling_rate);
10126 end if;
10127
10128 l_life_rate_diff := ABS(l_new_rate - p_initial_rate);
10129 if l_life_rate_diff > p_max_lifetime_adjustment and p_max_lifetime_adjustment is not null then
10130 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was above life differential of: ' || l_life_rate_diff );
10131 l_new_rate := p_last_period_rate + (p_max_lifetime_adjustment * l_sign2);
10132 end if;
10133 l_rate_diff := ABS(l_new_rate - p_last_period_rate);
10134
10135 if l_rate_diff > p_max_period_adjustment and p_max_period_adjustment is not null then
10136 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New rate was above adjustment differential of: ' || l_rate_diff);
10137 l_new_rate := p_last_period_rate + (p_max_period_adjustment * l_sign1);
10138 end if;
10139
10140 if l_new_rate < p_floor_rate and p_floor_rate is not null then
10141 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was below floor of ' || p_floor_rate );
10142 l_new_rate := p_floor_rate;
10143 end if;
10144 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_rate ' || l_new_rate);
10145
10146 return l_new_rate;
10147
10148 end calculateInterestRate;
10149
10150 /*=========================================================================
10151 || PUBLIC PROCEDURE getRemainingBalance
10152 ||
10153 || DESCRIPTION
10154 ||
10155 || Overview: function to get the remaining balance on the loan
10156 ||
10157 || Parameter: loan_id
10158 ||
10159 || Return value: Amount Or BALANCE on loan
10160 ||
10161 || Source Tables: LNS_TERMS, LNS_LOAN_HEADER, LNS_AMORTIZATION_SCHEDS
10162 ||
10163 || Target Tables: NA
10164 ||
10165 || KNOWN ISSUES
10166 ||
10167 || NOTES
10168 ||
10169 || Creation date: 12/08/2003 6:31PM
10170 ||
10171 || Major Modifications: when who what
10172 || 12/26/2003 raverma base the remaining balance from
10173 || loan status
10174 || 2/03/2004 balance if ACTIVE is based on PRINCIPAL_BALANCE
10175 || 7/29/2004 balance if DEFAULT or DELINQUENT = ACTIVE
10176 *=======================================================================*/
10177 function getRemainingBalance(p_loan_id in number) return number
10178 is
10179 l_balance number;
10180 l_initial_amount number;
10181 l_billed_amount number;
10182 l_loan_status varchar2(30);
10183 l_column varchar2(30);
10184 l_table varchar2(30);
10185 l_api_name varchar2(30);
10186
10187 begin
10188 l_balance := -1;
10189 l_initial_amount := 0;
10190 l_billed_amount := 0;
10191 l_api_name := 'getRemainingBalance';
10192 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10193
10194 Execute Immediate
10195 ' Select Loan_Status ' ||
10196 ' From lns_loan_headers_all ' ||
10197 ' where loan_id = :p_loan_id'
10198 into l_loan_status
10199 using p_loan_id;
10200
10201 if l_loan_status = 'APPROVED' then
10202 l_column := 'TOTAL_PRINCIPAL_BALANCE';
10203 l_table := 'LNS_PAY_SUM_V';
10204 -- l_column := 'REQUESTED_AMOUNT';
10205 -- l_table := 'LNS_LOAN_HEADERS_ALL';
10206
10207 elsif l_loan_Status = 'ACTIVE' then
10208 l_column := 'TOTAL_PRINCIPAL_BALANCE';
10209 l_table := 'LNS_PAY_SUM_V';
10210
10211 elsif l_loan_Status = 'DELINQUENT' then
10212 l_column := 'TOTAL_PRINCIPAL_BALANCE';
10213 l_table := 'LNS_PAY_SUM_V';
10214
10215 elsif l_loan_Status = 'DEFAULT' then
10216 l_column := 'TOTAL_PRINCIPAL_BALANCE';
10217 l_table := 'LNS_PAY_SUM_V';
10218
10219 elsif l_loan_Status = 'PAIDOFF' then
10220 l_column := 'TOTAL_PRINCIPAL_BALANCE';
10221 l_table := 'LNS_PAY_SUM_V';
10222 -- l_column := 'REQUESTED_AMOUNT';
10223 -- l_table := 'LNS_LOAN_HEADERS_ALL';
10224
10225 elsif l_loan_Status = 'CANCELLED' then
10226 l_column := 'TOTAL_PRINCIPAL_BALANCE';
10227 l_table := 'LNS_PAY_SUM_V';
10228
10229 elsif l_loan_status = 'PENDING' then
10230 l_column := 'REQUESTED_AMOUNT';
10231 l_table := 'LNS_LOAN_HEADERS_ALL';
10232
10233 elsif l_loan_status = 'INCOMPLETE' then
10234 l_column := 'REQUESTED_AMOUNT';
10235 l_table := 'LNS_LOAN_HEADERS_ALL';
10236
10237 elsif l_loan_status = 'IN_FUNDING' then
10238 l_column := 'REQUESTED_AMOUNT';
10239 l_table := 'LNS_LOAN_HEADERS_ALL';
10240
10241 elsif l_loan_status = 'FUNDING_ERROR' then
10242 l_column := 'REQUESTED_AMOUNT';
10243 l_table := 'LNS_LOAN_HEADERS_ALL';
10244
10245 else -- catch any new statuses
10246 l_column := 'REQUESTED_AMOUNT';
10247 l_table := 'LNS_LOAN_HEADERS_ALL';
10248
10249 end if;
10250
10251 Execute Immediate
10252 ' Select ' || l_column ||
10253 ' From ' || l_table ||
10254 ' where loan_id = :p_loan_id'
10255 into l_balance
10256 using p_loan_id;
10257
10258 -- logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': remainingBalance: ' || l_balance);
10259 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
10260
10261 return l_balance;
10262 /*
10263 Exception
10264 When Others then
10265 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Error: ' || sqlerrm);
10266 --seed this message
10267 FND_MESSAGE.Set_Name('LNS', 'LNS_UNABLE_TO_COMPUTE_BALANCE');
10268 FND_MSG_PUB.Add;
10269 RAISE FND_API.G_EXC_ERROR;
10270 */
10271 end getRemainingBalance;
10272
10273
10274 function getFundedAmount(p_loan_id in number, p_date in date, p_based_on_terms varchar2) return number
10275 is
10276
10277 l_api_name varchar2(30) := 'getFundedAmount';
10278 l_funded_amount number;
10279 l_bill_on_appr_amounts varchar2(1);
10280
10281 cursor c_get_loan_balance(p_loan_id number, p_date date) is
10282 select
10283 decode(loan.loan_class_code,
10284 'DIRECT', (select nvl(sum(disb_line.LINE_AMOUNT), 0) from lns_disb_lines disb_line, lns_disb_headers disb_hdr
10285 where disb_hdr.loan_id = loan.loan_id and /*disb_hdr.phase = 'TERM' and */
10286 disb_hdr.disb_header_id = disb_line.disb_header_id and disb_line.STATUS = 'FULLY_FUNDED' and
10287 trunc(disb_line.DISBURSEMENT_DATE) <= trunc(p_date)),
10288 'ERS', (select nvl(sum(lines.REQUESTED_AMOUNT), 0) from lns_loan_lines lines
10289 where lines.loan_id = loan.loan_id and lines.STATUS = 'APPROVED' and lines.end_date is null and
10290 trunc(lines.ADJUSTMENT_DATE) <= trunc(p_date)))
10291 from lns_loan_headers_all loan
10292 where loan.loan_id = p_loan_id;
10293
10294 cursor c_get_loan_balance1(p_loan_id number, p_date date) is
10295 select
10296 decode(loan.loan_class_code,
10297 'DIRECT', (select nvl(sum(disb_hdr.HEADER_AMOUNT), 0) from lns_disb_headers disb_hdr
10298 where disb_hdr.loan_id = loan.loan_id and
10299 disb_hdr.STATUS is null and
10300 (disb_hdr.PAYMENT_REQUEST_DATE is null or trunc(disb_hdr.PAYMENT_REQUEST_DATE) <= trunc(p_date))),
10301 'ERS', (select nvl(sum(lines.REQUESTED_AMOUNT), 0) from lns_loan_lines lines
10302 where lines.loan_id = loan.loan_id and (lines.STATUS is null or lines.STATUS = 'PENDING') and
10303 lines.end_date is null))
10304 from lns_loan_headers_all loan
10305 where loan.loan_id = p_loan_id;
10306
10307 cursor c_get_loan_balance2(p_loan_id number, p_date date) is
10308 select
10309 decode(loan.loan_class_code,
10310 'DIRECT', loan.requested_amount + nvl(loan.ADD_REQUESTED_AMOUNT, 0) /* +
10311 (select nvl(sum(adj.ADJUSTMENT_AMOUNT), 0) from LNS_LOAN_AMOUNT_ADJS adj
10312 where adj.LOAN_ID = loan.loan_id and adj.STATUS = 'APPROVED' and
10313 trunc(adj.EFFECTIVE_DATE) <= trunc(p_date))*/,
10314 'ERS', (select nvl(sum(lines.REQUESTED_AMOUNT), 0) from lns_loan_lines lines
10315 where lines.loan_id = loan.loan_id and (lines.STATUS is null or lines.STATUS = 'PENDING') and
10316 lines.end_date is null))
10317 from lns_loan_headers_all loan
10318 where loan.loan_id = p_loan_id;
10319
10320 cursor c_get_bill_opt(p_loan_id number) is
10321 select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
10322 from lns_loan_headers_all
10323 where loan_id = p_loan_id;
10324 begin
10325 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10326 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_loan_id = ' || p_loan_id);
10327 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_date = ' || p_date);
10328 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_based_on_terms = ' || p_based_on_terms);
10329
10330 open c_get_bill_opt(p_loan_id);
10331 fetch c_get_bill_opt into l_bill_on_appr_amounts;
10332 close c_get_bill_opt;
10333 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
10334
10335 if l_bill_on_appr_amounts = 'N' then -- bill based on funding amounts
10336
10337 if p_based_on_terms = 'CURRENT' then
10338 open c_get_loan_balance(p_loan_id, p_date);
10339 fetch c_get_loan_balance into l_funded_amount;
10340 close c_get_loan_balance;
10341 else
10342 open c_get_loan_balance1(p_loan_id, p_date);
10343 fetch c_get_loan_balance1 into l_funded_amount;
10344 close c_get_loan_balance1;
10345 end if;
10346
10347 else -- bill based on approved amounts
10348
10349 open c_get_loan_balance2(p_loan_id, p_date);
10350 fetch c_get_loan_balance2 into l_funded_amount;
10351 close c_get_loan_balance2;
10352
10353 end if;
10354
10355 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_funded_amount = ' || l_funded_amount);
10356 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
10357
10358 return l_funded_amount;
10359 end;
10360
10361
10362 /*========================================================================
10363 | PUBLIC FUNCTION weightBalance
10364 |
10365 | DESCRIPTION
10366 | takes a table of loan_activities, sorts them and weights the balance
10367 || by the from/to dates
10368 |
10369 | PSEUDO CODE/LOGIC
10370 || - calculate the wtd average daily balance for the loan (construction)
10371 || - day counting method is accoring to the terms of the loan
10372 ||
10373 || within the given from/to date range
10374 || ADB =[(# of days X Balance 1 ) +
10375 || (# of days X Balance 2 ) +
10376 || (# of days X Balance 3 ) +
10377 || .
10378 || .
10379 || .
10380 || (# of days X Balance N ) ]
10381 || /
10382 || Total Number of Days (from <-> to dates)
10383 |
10384 | PARAMETERS
10385 |
10386 | Return value:
10387 |
10388 | Source Tables: NA
10389 |
10390 | Target Tables: NA
10391 |
10392 | KNOWN ISSUES
10393 |
10394 | MODIFICATION HISTORY
10395 | Date Author Description of Changes
10396 | 07/19/05 4:13:PM raverma Created
10397 *=======================================================================*/
10398 function weightBalance(p_loan_activities IN LNS_FINANCIALS.LOAN_ACTIVITY_TBL
10399 ,p_from_date in date
10400 ,p_to_date in date
10401 ,p_day_count_method in varchar2) return number
10402 is
10403 l_balance_days number;
10404 l_total_days number;
10405 l_num_days number;
10406 l_weighted_balance number;
10407 k number;
10408 m number;
10409 l_api_name varchar2(25);
10410 l_begin_balance number;
10411 l_end_balance number;
10412 l_total_activity_amount number;
10413 l_loan_activities LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
10414
10415
10416 begin
10417 l_api_name := 'weightBalance';
10418 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10419 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - number of activities: ' || p_loan_activities.count);
10420 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
10421 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
10422 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_day_count_method: ' || p_day_count_method);
10423
10424 -- sort activities by activity date
10425
10426 -- # of days @ balance 1
10427 -- # of days @ balance 2
10428 -- # of days @ balance N
10429 -- find balance on from date
10430 -- find balance on to date
10431 -- find number of balance changes between the 2
10432 -- loop thru each balance change and calc # of days at balance
10433 -- now calculate ADB using dates from and to
10434 l_balance_days := 0;
10435 l_total_days := 0;
10436 l_num_days := 0;
10437 l_weighted_balance := 0;
10438 l_total_activity_amount := 0;
10439 l_loan_activities := p_loan_activities;
10440 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - sorting the activities');
10441 sortRows(l_loan_activities);
10442
10443 /*
10444 for j in 1..p_loan_activities.count
10445 loop
10446 dbms_output.put_line(p_loan_activities(j).activity_date );
10447 dbms_output.put_line(p_loan_activities(j).ending_balance );
10448 end loop;
10449 */
10450
10451 m := l_loan_activities.count;
10452
10453 if m = 1 then
10454 l_weighted_balance := l_loan_activities(1).ending_balance;
10455 else
10456
10457 for p in 1..m loop
10458 --dbms_output.put_line('p is ' || p);
10459 if l_loan_activities(p).activity_amount > 0 then
10460 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p ' || p);
10461 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity date: ' || l_loan_activities(p).activity_date);
10462 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity amount: ' || l_loan_activities(p).activity_amount);
10463 if p = 1 then
10464 -- this is for the previous balance
10465 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
10466 ,p_end_date => p_to_date
10467 ,p_day_count_method => p_day_count_method);
10468 elsif p < m then
10469 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
10470 ,p_end_date => l_loan_activities(p+1).activity_date
10471 ,p_day_count_method => p_day_count_method);
10472 elsif p = m then
10473 --dbms_output.put_line('2');
10474 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
10475 ,p_end_date => p_to_date
10476 ,p_day_count_method => p_day_count_method);
10477 end if;
10478
10479 if l_num_days > 0 then
10480 l_total_activity_amount := l_total_activity_amount + l_loan_activities(p).activity_amount;
10481 end if;
10482
10483 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - total activity amount: ' || l_total_activity_amount);
10484 --dbms_output.put_line('day count is ' || l_num_days);
10485 --dbms_output.put_line('balance is ' || p_loan_activities(p).ending_balance);
10486 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
10487 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_num_days: ' || l_num_days);
10488 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity_amount: ' || l_loan_activities(p).activity_amount);
10489 l_balance_days := l_balance_days + (l_num_days * l_loan_activities(p).activity_amount);
10490 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - result l_balance_days: ' || l_balance_days);
10491 end if;
10492
10493 end loop;
10494
10495 -- this is the total days (denominator)
10496 l_total_Days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
10497 ,p_end_date => p_to_date
10498 ,p_day_count_method => p_day_count_method);
10499 -- dbms_output.put_line('total days is ' || l_total_Days );
10500 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
10501 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_total_days: ' || l_total_days);
10502 l_weighted_balance := l_balance_days / l_total_days;
10503 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_weighted_balance: ' || l_weighted_balance);
10504
10505 end if;
10506
10507 return l_weighted_balance;
10508
10509 end weightBalance;
10510
10511 /*=========================================================================
10512 || PUBLIC FUNCTION getWeightedBalance
10513 ||
10514 || DESCRIPTION
10515 ||
10516 || PARAMETERS
10517 || p_loan_id loan_id
10518 || p_term_id term_id (for future use)
10519 || p_from_date date from which to calculate ADB
10520 || p_to_date date to which to calculate ADB
10521 || p_calc_method 'ACTUAL' or 'TARGET'
10522 ||
10523 || Return value: wtd average daily balance for the loan
10524 ||
10525 || Source Tables: LNS_DISB_HEADERS, LNS_DISB_LINES
10526 ||
10527 || Target Tables: NA
10528 ||
10529 || KNOWN ISSUES
10530 ||
10531 || NOTES
10532 ||
10533 || MODIFICATION HISTORY
10534 || Date Author Description of Changes
10535 || 07/17/05 1:51:PM raverma Created
10536 *=======================================================================*/
10537 procedure getWeightedBalance(p_loan_id in number
10538 ,p_from_date in date
10539 ,p_to_date in date
10540 ,p_calc_method in varchar2
10541 ,p_phase in varchar2
10542 ,p_day_count_method in varchar2
10543 ,p_adj_amount in number
10544 ,x_wtd_balance out NOCOPY number
10545 ,x_begin_balance out NOCOPY number
10546 ,x_end_balance out NOCOPY number)
10547
10548 is
10549 l_api_name varchar2(25);
10550 l_loan_activities LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
10551 i number;
10552 l_activity_date date;
10553 l_activity_amount number;
10554 l_loan_start_date date;
10555 l_display_order number;
10556 l_precision number;
10557
10558 cursor c_actual_balance(p_loan_id number, p_from_date date, p_to_date date) IS
10559 select * from
10560 (select p_from_date activity_date
10561 ,nvl(sum(line_amount), 0)
10562 ,1 display_order
10563 from lns_disb_lines lines
10564 where disb_header_id in (select disb_header_id from lns_disb_headers where loan_id = p_loan_id)
10565 and trunc(disbursement_date) <= p_from_date
10566 UNION
10567 select trunc(line.disbursement_date) activity_date
10568 ,nvl(sum(inv.amount), 0)
10569 ,2 display_order
10570 from AP_INVOICE_PAYMENTS_ALL inv
10571 ,lns_disb_headers head
10572 ,lns_disb_lines line
10573 where head.loan_id = p_loan_id
10574 and line.disb_header_id = head.disb_header_id
10575 and line.invoice_id is not null
10576 and line.invoice_id = inv.invoice_id
10577 and line.status IN ('PARTIALLY_FUNDED', 'FULLY_FUNDED')
10578 and trunc(line.disbursement_date) > p_from_date
10579 and trunc(line.disbursement_date) < p_to_date
10580 group by trunc(line.disbursement_date))
10581 order by display_order, activity_date;
10582
10583 cursor c_theoretical_balance(p_loan_id number, p_from_date date, p_to_date date) IS
10584 select * from
10585 (select p_from_date activity_date
10586 ,nvl(sum(header_amount),0)
10587 ,1 display_order
10588 from lns_disb_headers
10589 where loan_id = p_loan_id
10590 and trunc(payment_request_date) <= p_from_date
10591 UNION
10592 select payment_request_date activity_date
10593 ,nvl(sum(header_amount),0)
10594 ,2 display_order
10595 from lns_disb_headers
10596 where loan_id = p_loan_id
10597 and trunc(payment_request_date) > p_from_date
10598 and trunc(payment_request_date) < p_to_date
10599 group by payment_request_date
10600 UNION
10601 select lines.*
10602 from
10603 (select p_from_date activity_date
10604 ,nvl(sum(REQUESTED_AMOUNT),0)
10605 ,3 display_order
10606 from lns_loan_lines
10607 where loan_id = p_loan_id
10608 and (status is null or status = 'PENDING')
10609 and end_date is null) lines,
10610 lns_loan_headers_all loan
10611 where loan.loan_id = p_loan_id
10612 and loan.LOAN_CLASS_CODE = 'ERS')
10613 order by display_order, activity_date;
10614
10615 cursor c_loan_boundaries(p_loan_id number)
10616 is
10617 select open_loan_start_date
10618 from lns_loan_headers
10619 where loan_id = p_loan_id;
10620
10621 cursor c_curr_precision(p_loan_id number) is
10622 select curr.precision
10623 from lns_loan_headers_all h
10624 ,fnd_currencies curr
10625 where h.loan_id = p_loan_id
10626 and curr.currency_code = h.loan_currency;
10627
10628 begin
10629
10630 l_api_name := 'getWeightedBalance';
10631 i := 0;
10632 x_wtd_balance := 0;
10633 x_begin_balance := 0;
10634 x_end_balance := 0;
10635 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Begin');
10636 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
10637 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
10638 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id: ' || p_loan_id);
10639 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_calc_method: ' || p_calc_method);
10640 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_adj_amount: ' || p_adj_amount);
10641 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase: ' || p_phase);
10642
10643 -- validate the from and to Dates
10644 if p_from_date > p_to_date then
10645 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_ACTIVE_DATE');
10646 FND_MSG_PUB.Add;
10647 RAISE FND_API.G_EXC_ERROR;
10648 end if;
10649
10650 l_loan_activities(1).ending_balance := 0;
10651
10652 if p_calc_method = 'ACTUAL' then
10653
10654 -- get all the balance activities on the loan
10655 OPEN c_actual_balance(p_loan_id, p_from_date, p_to_date);
10656 LOOP
10657 i := i + 1;
10658 FETCH c_actual_balance INTO
10659 l_activity_date
10660 ,l_activity_amount
10661 ,l_display_order;
10662 EXIT WHEN c_actual_balance%NOTFOUND;
10663
10664 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
10665 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date = ' || l_activity_date);
10666 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount = ' || l_activity_amount);
10667 l_loan_activities(i).activity_date := l_activity_date;
10668 l_loan_activities(i).activity_amount := l_activity_amount;
10669 if i = 1 then
10670 l_loan_activities(i).ending_balance := l_activity_amount;
10671 x_begin_balance := l_loan_activities(i).ending_balance;
10672 x_end_balance := l_loan_activities(i).ending_balance;
10673 else
10674 l_loan_activities(i).ending_balance := l_activity_amount + l_loan_activities(i-1).ending_balance;
10675 x_end_balance := l_loan_activities(i).ending_balance;
10676 end if;
10677 l_activity_date := null;
10678 l_activity_amount := null;
10679 END LOOP;
10680 close c_actual_balance;
10681
10682 elsif p_calc_method = 'TARGET' then
10683
10684 OPEN c_theoretical_balance(p_loan_id, p_from_date, p_to_date);
10685 LOOP
10686 i := i + 1;
10687 FETCH c_theoretical_balance INTO
10688 l_activity_date
10689 ,l_activity_amount
10690 ,l_display_order;
10691 EXIT WHEN c_theoretical_balance%NOTFOUND;
10692
10693 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
10694 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date = ' || l_activity_date);
10695 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount = ' || l_activity_amount);
10696
10697 if i = 1 then
10698 l_activity_amount := l_activity_amount - p_adj_amount;
10699 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NEW l_activity_amount = ' || l_activity_amount);
10700
10701 l_loan_activities(i).ending_balance := l_activity_amount;
10702 x_begin_balance := l_loan_activities(i).ending_balance;
10703 else
10704 l_loan_activities(i).ending_balance := l_activity_amount + l_loan_activities(i-1).ending_balance;
10705 end if;
10706
10707 x_end_balance := l_loan_activities(i).ending_balance;
10708 l_loan_activities(i).activity_date := l_activity_date;
10709 l_loan_activities(i).activity_amount := l_activity_amount;
10710
10711 l_activity_date := null;
10712 l_activity_amount := null;
10713 END LOOP;
10714 close c_theoretical_balance;
10715
10716 end if;
10717
10718 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting wtd balance');
10719 x_wtd_balance := weightBalance(p_loan_activities => l_loan_activities
10720 ,p_from_date => p_from_date
10721 ,p_to_date => p_to_date
10722 ,p_day_count_method => p_day_count_method);
10723
10724 OPEN c_curr_precision(p_loan_id);
10725 FETCH c_curr_precision INTO l_precision;
10726 CLOSE c_curr_precision;
10727
10728 x_wtd_balance := round(x_wtd_balance, l_precision);
10729 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_wtd_balance = ' || x_wtd_balance);
10730 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_begin_balance = ' || x_begin_balance);
10731 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_end_balance = ' || x_end_balance);
10732
10733 end getWeightedBalance;
10734
10735
10736
10737 /*=========================================================================
10738 || PUBLIC FUNCTION getAverageDailyBalance
10739 ||
10740 || DESCRIPTION
10741 || - calculate average daily balance for the loan (term)
10742 || - day counting method is accoring to the terms of the loan
10743 ||
10744 || only one method supported right now:
10745 || within the given from/to date range
10746 || ADB =[(# of days X Balance 1 ) +
10747 || (# of days X Balance 2 ) +
10748 || (# of days X Balance 3 ) +
10749 || .
10750 || .
10751 || .
10752 || (# of days X Balance N ) ]
10753 || /
10754 || Total Number of Days (from <-> to dates)
10755 ||
10756 || PARAMETERS
10757 || p_loan_id loan_id
10758 || p_term_id term_id (for future use)
10759 || p_from_date date from which to calculate ADB
10760 || p_to_date date to which to calculate ADB
10761 || p_calc_method for future use
10762 ||
10763 || Return value: average daily balance for the loan
10764 ||
10765 || Source Tables: LNS_RECEIVABLE_ACTIVITIES_V, LNS_LOAN_HEADERS
10766 ||
10767 || Target Tables: NA
10768 ||
10769 || KNOWN ISSUES
10770 ||
10771 || NOTES
10772 ||
10773 ||
10774 || MODIFICATION HISTORY
10775 || Date Author Description of Changes
10776 || 05/31/06 1:51:PM karamach Added cursor c_loan_phase and passed current_phase to getLoanDetails api to fix bug5237022
10777 || 09/30/04 1:51:PM raverma Created
10778 ||
10779 *=======================================================================*/
10780 function getAverageDailyBalance(p_loan_id number
10781 ,p_term_id number
10782 ,p_from_date date
10783 ,p_to_date date
10784 ,p_calc_method number) return number
10785 is
10786
10787 -- this cursor will get balance by activity date
10788 -- the markers ensure that funding and maturity are the 1st and last rows
10789 cursor c_balance_history(p_loan_id number) is
10790 select trunc(loan_start_date) activity_date,
10791 funded_amount activity_amount,
10792 funded_amount ending_balance
10793 from lns_loan_headers
10794 where loan_id = p_loan_id
10795 union all
10796 select trunc(activity_date) activity_date,
10797 sum(activity_amount) activity_amount,
10798 LNS_BILLING_UTIL_PUB.LOAN_BALANCE_BY_DATE(P_LOAN_ID, activity_date) --min(balance_by_activity_date) ending_balance
10799 from LNS_REC_ACT_CASH_CM_V rav
10800 where rav.loan_id = p_loan_id and
10801 line_type_code = 'PRIN' and
10802 (activity_code in ('PMT', 'ADJ') or (activity_code = 'CM' and activity_number like 'NET%'))
10803 group by activity_date
10804 union all
10805 select trunc(loan_maturity_date) activity_date
10806 ,null
10807 ,lns_financials.getRemainingBalance(p_loan_id)
10808 from lns_loan_headers
10809 where loan_id = p_loan_id
10810 order by activity_date asc;
10811
10812 -- this cursor will get the current phase of the loan
10813 cursor c_loan_phase(p_loan_id number) is
10814 select nvl(current_phase,'TERM') current_phase
10815 from lns_loan_headers
10816 where loan_id = p_loan_id;
10817
10818 l_activity_date date;
10819 l_activity_amount number;
10820 l_balance_days number;
10821 l_num_days number;
10822 l_total_days number;
10823 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
10824 l_loan_activities LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
10825 l_average_daily_balance number;
10826 k number;
10827 m number;
10828 l_num_balance_changes number;
10829 l_api_name varchar2(25);
10830 l_begin_balance number;
10831 l_end_balance number;
10832 i number;
10833 -- l_marker number;
10834 l_loan_phase varchar2(30);
10835
10836 begin
10837
10838 --LNS_BILLING_UTIL_PUB.LOAN_BALANCE_BY_DATE(P_LOAN_ID IN NUMBER, P_DATE IN DATE) function
10839 l_api_name := 'getAverageDailyBalance';
10840 l_balance_days := 0;
10841 l_num_days := 0;
10842 l_total_days := 0;
10843 l_average_daily_balance:= 0;
10844 i := 0;
10845 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Begin');
10846 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
10847 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
10848
10849 -- validate the from and to Dates
10850 if p_from_date > p_to_date then
10851 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_ACTIVE_DATE');
10852 FND_MSG_PUB.Add;
10853 RAISE FND_API.G_EXC_ERROR;
10854 end if;
10855
10856 OPEN c_loan_phase(p_loan_id);
10857 FETCH c_loan_phase INTO l_loan_phase;
10858 CLOSE c_loan_phase;
10859
10860 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
10861 ,p_based_on_terms => 'CURRENT'
10862 --karamach bug5237022
10863 --,p_phase => 'TERM');
10864 ,p_phase => l_loan_phase);
10865
10866 -- validate if dates are within the boundaries of loan_start and maturity_dates
10867 if p_to_date > l_loan_details.maturity_date then
10868 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR1');
10869 FND_MSG_PUB.Add;
10870 RAISE FND_API.G_EXC_ERROR;
10871 end if;
10872
10873 if p_from_date < l_loan_details.loan_start_date then
10874 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR2');
10875 FND_MSG_PUB.Add;
10876 RAISE FND_API.G_EXC_ERROR;
10877 end if;
10878
10879 -- get all the balance activities on the loan
10880 OPEN c_balance_history(p_loan_id);
10881 LOOP
10882 i := i + 1;
10883 FETCH c_balance_history INTO
10884 l_activity_date
10885 ,l_activity_amount
10886 ,l_end_balance;
10887 -- ,l_marker;
10888 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
10889 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date: ' || l_activity_date);
10890 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount: ' || l_activity_amount);
10891 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_end_balance: ' || l_end_balance);
10892 EXIT WHEN c_balance_history%NOTFOUND;
10893
10894 l_loan_activities(i).activity_date := l_activity_date;
10895 l_loan_activities(i).activity_amount := l_activity_amount;
10896 l_loan_activities(i).ending_balance := l_end_balance;
10897
10898 END LOOP;
10899 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - number of activities: ' || l_loan_activities.count);
10900
10901 -- # of balance changes = l_loan_activities.count - 2
10902 -- # of days @ balance 1
10903 -- # of days @ balance 2
10904 -- # of days @ balance N
10905 -- find balance on from date
10906 -- find balance on to date
10907 -- find number of balance changes between the 2
10908 -- loop thru each balance change and calc # of days at balance
10909 -- now calculate ADB using dates from and to
10910 k := 1;
10911 WHILE p_from_date >= l_loan_activities(k).activity_date loop
10912 l_begin_balance := l_loan_activities(k).ending_balance;
10913 k := k + 1;
10914 end loop;
10915 k := k - 1;
10916
10917 m := 1;
10918 WHILE p_to_date >= l_loan_activities(m).activity_date loop
10919 l_end_balance := l_loan_activities(m).ending_balance;
10920 m := m + 1;
10921 end loop;
10922 m := m - 1;
10923
10924 --dbms_output.put_line('output k' || k);
10925 --dbms_output.put_line('output m' || m);
10926
10927 if k = m then
10928 l_average_daily_balance := l_loan_activities(k).ending_balance;
10929 else
10930 for p in k..m loop
10931 --dbms_output.put_line('p is ' || p);
10932 if p = k then -- first record
10933 --dbms_output.put_line('1');
10934 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
10935 ,p_end_date => l_loan_activities(p + 1).activity_date
10936 ,p_day_count_method => l_loan_details.day_count_method);
10937
10938 elsif p = m then
10939 -- dbms_output.put_line('3');
10940 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
10941 ,p_end_date => p_to_date
10942 ,p_day_count_method => l_loan_details.day_count_method);
10943
10944 else
10945 -- dbms_output.put_line('2');
10946 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
10947 ,p_end_date => l_loan_activities(p + 1).activity_date
10948 ,p_day_count_method => l_loan_details.day_count_method);
10949
10950 end if;
10951 --dbms_output.put_line('day count is ' || l_num_days);
10952 --dbms_output.put_line('balance is ' || l_loan_activities(p).ending_balance);
10953 l_balance_days := l_balance_days + l_num_days * l_loan_activities(p).ending_balance;
10954
10955 end loop;
10956 -- this is the total days (denominator)
10957 l_total_Days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
10958 ,p_end_date => p_to_date
10959 ,p_day_count_method => l_loan_details.day_count_method);
10960
10961 --dbms_output.put_line('total days is ' || l_total_Days );
10962 l_average_daily_balance := l_balance_days / l_total_days;
10963 end if;
10964
10965 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
10966 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_total_balance: ' || l_total_days);
10967 --dbms_output.put_line('adb is ' || l_average_daily_balance);
10968 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_end_balance: ' || l_end_balance);
10969 return round(l_average_daily_balance, l_loan_details.currency_precision);
10970
10971 EXCEPTION
10972
10973 When others Then
10974 return -1;
10975 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - ' || sqlerrm);
10976
10977
10978 end getAverageDailyBalance;
10979
10980
10981 function getAPR(p_loan_id in number
10982 ,p_term_id in number
10983 ,p_actual_flag in varchar2) return number
10984 is
10985
10986 begin
10987 null;
10988 /*
10989 public static double RATE(double d, double d1, double d2)
10990 {
10991 double d3 = 1.0D;
10992 double d4 = 0.5D;
10993 double d5 = d1;
10994 if(d * d1 <= d2)
10995 {
10996 return 0.0D;
10997 }
10998 for(int i = 1; i < 50; i++)
10999 {
11000 double d6 = PMT(d3, d, d2);
11001 if(d6 == d1)
11002 {
11003 return d3;
11004 }
11005 if(d6 < d1)
11006 {
11007 d3 += d4;
11008 } else
11009 {
11010 d3 -= d4;
11011 }
11012 d4 /= 2D;
11013 }
11014
11015 return d3;
11016 }
11017 */
11018 end;
11019
11020
11021 -- This procedure calculates normal interest
11022 procedure CALC_NORM_INTEREST(p_loan_id in number,
11023 p_calc_method in varchar2,
11024 p_period_start_date in date,
11025 p_period_end_date in date,
11026 p_interest_rate in number,
11027 p_day_count_method in varchar2,
11028 p_payment_freq in varchar2,
11029 p_compound_freq in varchar2,
11030 p_adj_amount in number,
11031 p_CAP_AMOUNT in number default 0,
11032 x_norm_interest out NOCOPY number,
11033 x_norm_int_details out NOCOPY varchar2)
11034 is
11035 l_api_name varchar2(25);
11036 l_activity_date date;
11037 l_activity_code varchar2(30);
11038 l_activity_amount number;
11039 l_theory_balance number;
11040 l_actual_balance number;
11041 l_days_late number;
11042 l_display_order number;
11043 l_rate number;
11044 l_day_count number;
11045 i number;
11046 l_norm_prev_amount number;
11047 l_norm_interest number;
11048 l_norm_prev_act_date date;
11049 l_cum_norm_interest number;
11050 l_periodic_rate number;
11051 l_norm_int_detail_str varchar2(2000);
11052 l_precision number;
11053
11054 cursor c_trx_activities(p_loan_id number, p_start_date date, p_end_date date) is
11055 select
11056 trunc(ACTIVITY_DATE),
11057 ACTIVITY_CODE,
11058 ACTIVITY_AMOUNT,
11059 THEORETICAL_BALANCE,
11060 ACTUAL_BALANCE,
11061 DAYS_LATE,
11062 display_order
11063 from LNS_PRIN_TRX_ACTIVITIES_V
11064 where loan_id = p_loan_id and
11065 trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
11066 trunc(ACTIVITY_DATE) <= trunc(p_end_date) and
11067 ACTIVITY_CODE in ('START', 'DUE', 'DISBURSEMENT', 'INVOICE_ADDED')
11068 order by activity_date, display_order, LOAN_AMORTIZATION_ID;
11069
11070 cursor c_curr_precision(p_loan_id number) is
11071 select curr.precision
11072 from lns_loan_headers_all h
11073 ,fnd_currencies curr
11074 where h.loan_id = p_loan_id
11075 and curr.currency_code = h.loan_currency;
11076
11077 begin
11078
11079 l_api_name := 'CALC_NORM_INTEREST';
11080 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11081 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
11082 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
11083 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
11084 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
11085 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
11086 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
11087 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
11088 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
11089 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
11090 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
11091 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': adj amount: ' || p_adj_amount);
11092 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': capitalized int: ' || p_CAP_AMOUNT);
11093
11094 -- calculating normal and additional interest
11095 i := 1;
11096 l_norm_interest := 0;
11097 l_cum_norm_interest := 0;
11098 l_norm_prev_amount := 0;
11099 l_norm_prev_act_date := p_period_start_date;
11100 x_norm_interest := 0;
11101
11102 OPEN c_curr_precision(p_loan_id);
11103 FETCH c_curr_precision INTO l_precision;
11104 CLOSE c_curr_precision;
11105
11106 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
11107
11108 OPEN c_trx_activities(p_loan_id, p_period_start_date, p_period_end_date);
11109 LOOP
11110
11111 FETCH c_trx_activities INTO
11112 l_activity_date
11113 ,l_activity_code
11114 ,l_activity_amount
11115 ,l_theory_balance
11116 ,l_actual_balance
11117 ,l_days_late
11118 ,l_display_order;
11119
11120 EXIT WHEN c_trx_activities%NOTFOUND;
11121
11122 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11123 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Theory_Bal Actual_Bal Days_Late');
11124 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_activity_date || ' ' || l_activity_code || ' ' || l_activity_amount || ' ' || l_theory_balance || ' ' || l_actual_balance || ' ' || l_days_late);
11125
11126 l_theory_balance := l_theory_balance + p_CAP_AMOUNT;
11127 -- normal interest
11128 if l_activity_code = 'DISBURSEMENT' or l_activity_code = 'INVOICE_ADDED' then
11129 l_norm_prev_amount := l_theory_balance - l_activity_amount - p_adj_amount;
11130 end if;
11131
11132 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating normal interest...');
11133 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_norm_prev_act_date || ' - ' || l_activity_date);
11134 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_norm_prev_amount);
11135 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11136
11137 if (p_calc_method = 'SIMPLE') then
11138
11139 -- recalculate periodic rate for each period if day counting methodolgy varies
11140
11141 l_periodic_rate := lns_financials.getPeriodicRate(
11142 p_payment_freq => p_payment_freq
11143 ,p_period_start_date => l_norm_prev_act_date
11144 ,p_period_end_date => l_activity_date
11145 ,p_annualized_rate => p_interest_rate
11146 ,p_days_count_method => p_day_count_method
11147 ,p_target => 'INTEREST');
11148
11149 elsif (p_calc_method = 'COMPOUND') then
11150
11151 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11152 ,p_payment_freq => p_payment_freq
11153 ,p_annualized_rate => p_interest_rate
11154 ,p_period_start_date => l_norm_prev_act_date
11155 ,p_period_end_date => l_activity_date
11156 ,p_days_count_method => p_day_count_method
11157 ,p_target => 'INTEREST');
11158
11159 end if;
11160 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11161
11162 l_norm_interest := lns_financials.calculateInterest(p_amount => l_norm_prev_amount
11163 ,p_periodic_rate => l_periodic_rate
11164 ,p_compounding_period => null);
11165 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'normal interest = ' || l_norm_interest);
11166
11167 if trunc(l_norm_prev_act_date) <> trunc(l_activity_date) then
11168 if l_norm_int_detail_str is not null then
11169 l_norm_int_detail_str := l_norm_int_detail_str || ' +<br>';
11170 end if;
11171 l_norm_int_detail_str := l_norm_int_detail_str ||
11172 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_norm_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11173 ' * Balance ' || round(l_norm_prev_amount, l_precision) ||
11174 ' * Rate ' || p_interest_rate || '%';
11175 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
11176 end if;
11177
11178 l_cum_norm_interest := l_cum_norm_interest + l_norm_interest;
11179 if l_activity_code = 'DISBURSEMENT' or l_activity_code = 'INVOICE_ADDED' then
11180 l_norm_prev_amount := l_theory_balance - p_adj_amount;
11181 else
11182 l_norm_prev_amount := l_theory_balance;
11183 end if;
11184 l_norm_prev_act_date := l_activity_date;
11185 i := i + 1;
11186 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative normal interest = ' || l_cum_norm_interest);
11187
11188 END LOOP;
11189 close c_trx_activities;
11190
11191 -- manually adding last record for p_period_end_date date
11192 l_activity_date := p_period_end_date;
11193 l_activity_code := 'DUE';
11194 l_activity_amount := 0;
11195 l_days_late := 0;
11196
11197 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11198 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Theory_Bal Actual_Bal Days_Late');
11199 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '*' || l_activity_date || ' ' || l_activity_code || ' ' || l_activity_amount || ' ' || l_theory_balance || ' ' || l_actual_balance || ' ' || l_days_late);
11200
11201 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating normal interest...');
11202 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_norm_prev_act_date || ' - *' || l_activity_date);
11203 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_norm_prev_amount);
11204 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11205
11206 -- normal interest
11207 if (p_calc_method = 'SIMPLE') then
11208
11209 -- recalculate periodic rate for each period if day counting methodolgy varies
11210
11211 l_periodic_rate := lns_financials.getPeriodicRate(
11212 p_payment_freq => p_payment_freq
11213 ,p_period_start_date => l_norm_prev_act_date
11214 ,p_period_end_date => l_activity_date
11215 ,p_annualized_rate => p_interest_rate
11216 ,p_days_count_method => p_day_count_method
11217 ,p_target => 'INTEREST');
11218 elsif (p_calc_method = 'COMPOUND') then
11219
11220 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11221 ,p_payment_freq => p_payment_freq
11222 ,p_annualized_rate => p_interest_rate
11223 ,p_period_start_date => l_norm_prev_act_date
11224 ,p_period_end_date => l_activity_date
11225 ,p_days_count_method => p_day_count_method
11226 ,p_target => 'INTEREST');
11227
11228 end if;
11229 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11230
11231 l_norm_interest := lns_financials.calculateInterest(p_amount => l_norm_prev_amount
11232 ,p_periodic_rate => l_periodic_rate
11233 ,p_compounding_period => null);
11234 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'normal interest = ' || l_norm_interest);
11235
11236 if trunc(l_norm_prev_act_date) <> trunc(l_activity_date) then
11237 if l_norm_int_detail_str is not null then
11238 l_norm_int_detail_str := l_norm_int_detail_str || ' +<br>';
11239 end if;
11240 l_norm_int_detail_str := l_norm_int_detail_str ||
11241 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_norm_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11242 ' * Balance ' || round(l_norm_prev_amount, l_precision) ||
11243 ' * Rate ' || p_interest_rate || '%';
11244 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
11245 end if;
11246
11247 l_cum_norm_interest := l_cum_norm_interest + l_norm_interest;
11248
11249 x_norm_interest := round(l_cum_norm_interest, l_precision);
11250 x_norm_int_details := x_norm_interest || ' (' || l_norm_int_detail_str || ')';
11251
11252 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Normal Interest = ' || x_norm_interest);
11253 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Normal Interest Details = ' || x_norm_int_details);
11254 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
11255 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11256
11257 end;
11258
11259
11260 -- This procedure calculates additional and penal interest
11261 procedure CALC_ADD_INTEREST(p_loan_id in number,
11262 p_calc_method in varchar2,
11263 p_period_start_date in date,
11264 p_period_end_date in date,
11265 p_interest_rate in number,
11266 p_day_count_method in varchar2,
11267 p_payment_freq in varchar2,
11268 p_compound_freq in varchar2,
11269 p_penal_int_rate in number,
11270 p_prev_grace_end_date in date,
11271 p_grace_start_date in date,
11272 p_grace_end_date in date,
11273 p_target in varchar2,
11274 x_add_interest out NOCOPY number,
11275 x_penal_interest out NOCOPY number,
11276 x_add_int_details out NOCOPY varchar2,
11277 x_penal_int_details out NOCOPY varchar2)
11278 is
11279 l_api_name varchar2(25);
11280 l_activity_date date;
11281 l_activity_code varchar2(30);
11282 l_activity_amount number;
11283 l_theory_balance number;
11284 l_actual_balance number;
11285 l_days_late number;
11286 l_display_order number;
11287 l_rate number;
11288 l_day_count number;
11289 i number;
11290 l_add_prev_amount number;
11291 l_add_interest number;
11292 l_add_prev_act_date date;
11293 l_cum_add_interest number;
11294 l_periodic_rate number;
11295 l_penal_interest number;
11296 l_cum_penal_interest number;
11297 l_penal_period_rate number;
11298 l_interest_rate number;
11299 l_first_act_after_grace boolean;
11300 l_first_act_after_prev_grace boolean;
11301 l_add_int_setting varchar2(1);
11302 l_add_int_detail_str varchar2(2000);
11303 l_penal_int_detail_str varchar2(2000);
11304 l_penal_prev_act_date date;
11305 l_precision number;
11306
11307 cursor c_trx_prin_activities(p_loan_id number, p_start_date date, p_end_date date) is
11308 select
11309 trunc(ACTIVITY_DATE),
11310 ACTIVITY_CODE,
11311 ACTIVITY_AMOUNT,
11312 INTEREST_RATE,
11313 THEORETICAL_BALANCE,
11314 ACTUAL_BALANCE,
11315 DAYS_LATE,
11316 display_order
11317 from LNS_PRIN_TRX_ACTIVITIES_V
11318 where loan_id = p_loan_id and
11319 trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
11320 trunc(ACTIVITY_DATE) < trunc(p_end_date) and
11321 ACTIVITY_CODE not in ('DISBURSEMENT', 'INVOICE_ADDED')
11322 order by activity_date, display_order;
11323
11324 cursor c_trx_int_activities(p_loan_id number, p_start_date date, p_end_date date) is
11325 select
11326 trunc(ACTIVITY_DATE),
11327 ACTIVITY_CODE,
11328 ACTIVITY_AMOUNT,
11329 INTEREST_RATE,
11330 THEORETICAL_BALANCE,
11331 ACTUAL_BALANCE,
11332 DAYS_LATE,
11333 display_order
11334 from LNS_INT_TRX_ACTIVITIES_V
11335 where loan_id = p_loan_id and
11336 trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
11337 trunc(ACTIVITY_DATE) < trunc(p_end_date)
11338 order by activity_date, display_order;
11339
11340 cursor c_add_int_setting(p_loan_id number, p_target varchar2) is
11341 select decode(p_target, 'UNPAID_PRIN', nvl(term.CALC_ADD_INT_UNPAID_PRIN, 'Y'), 'UNPAID_INT', nvl(term.CALC_ADD_INT_UNPAID_INT, 'Y'))
11342 from lns_loan_headers loan,
11343 lns_terms term
11344 where loan.loan_id = p_loan_id and
11345 loan.loan_id = term.loan_id;
11346
11347 cursor c_curr_precision(p_loan_id number) is
11348 select curr.precision
11349 from lns_loan_headers_all h
11350 ,fnd_currencies curr
11351 where h.loan_id = p_loan_id
11352 and curr.currency_code = h.loan_currency;
11353
11354 begin
11355
11356 l_api_name := 'CALC_ADD_INTEREST';
11357 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11358 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
11359 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
11360 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
11361 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
11362 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
11363 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
11364 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
11365 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
11366 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
11367 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
11368 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': target: ' || p_target);
11369 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': penal_int_rate: ' || p_penal_int_rate);
11370 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prev_grace_end_date: ' || p_prev_grace_end_date);
11371 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': grace_start_date: ' || p_grace_start_date);
11372 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': grace_end_date: ' || p_grace_end_date);
11373
11374 x_add_interest := 0;
11375 x_penal_interest := 0;
11376
11377 -- fix for bug 8609721
11378 OPEN c_add_int_setting(p_loan_id, p_target);
11379 FETCH c_add_int_setting INTO l_add_int_setting;
11380 CLOSE c_add_int_setting;
11381 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_setting = ' || l_add_int_setting);
11382
11383 if (l_add_int_setting = 'N' or p_interest_rate = 0) and p_penal_int_rate = 0 then -- fix for bug 8609721
11384 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculate additional interest is off and penal interest rate = 0');
11385 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': exiting');
11386 return;
11387 end if;
11388
11389 if p_period_start_date > p_period_end_date then
11390 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': x_add_interest: ' || x_add_interest);
11391 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': x_add_interest: ' || x_add_interest);
11392 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': exiting');
11393 return;
11394 end if;
11395
11396 -- calculating normal and additional interest
11397 i := 1;
11398 l_add_interest := 0;
11399 l_cum_add_interest := 0;
11400 l_add_prev_amount := 0;
11401 l_add_prev_act_date := p_period_start_date;
11402 l_penal_interest := 0;
11403 l_cum_penal_interest := 0;
11404 l_interest_rate := 0;
11405 l_first_act_after_grace := true;
11406 l_first_act_after_prev_grace := true;
11407 l_penal_prev_act_date := p_grace_end_date;
11408
11409 OPEN c_curr_precision(p_loan_id);
11410 FETCH c_curr_precision INTO l_precision;
11411 CLOSE c_curr_precision;
11412
11413 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
11414
11415 if p_target = 'UNPAID_PRIN' then
11416 OPEN c_trx_prin_activities(p_loan_id, p_period_start_date, p_period_end_date);
11417 elsif p_target = 'UNPAID_INT' then
11418 OPEN c_trx_int_activities(p_loan_id, p_period_start_date, p_period_end_date);
11419 end if;
11420
11421 LOOP
11422
11423 l_add_interest := 0;
11424 l_penal_interest := 0;
11425
11426 if p_target = 'UNPAID_PRIN' then
11427 FETCH c_trx_prin_activities INTO
11428 l_activity_date
11429 ,l_activity_code
11430 ,l_activity_amount
11431 ,l_interest_rate
11432 ,l_theory_balance
11433 ,l_actual_balance
11434 ,l_days_late
11435 ,l_display_order;
11436
11437 EXIT WHEN c_trx_prin_activities%NOTFOUND;
11438 elsif p_target = 'UNPAID_INT' then
11439 FETCH c_trx_int_activities INTO
11440 l_activity_date
11441 ,l_activity_code
11442 ,l_activity_amount
11443 ,l_interest_rate
11444 ,l_theory_balance
11445 ,l_actual_balance
11446 ,l_days_late
11447 ,l_display_order;
11448
11449 EXIT WHEN c_trx_int_activities%NOTFOUND;
11450 end if;
11451
11452 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11453 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Rate Theory_Bal Actual_Bal Days_Late');
11454 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_activity_date || ' ' || l_activity_code || ' ' || l_activity_amount || ' ' || l_interest_rate || ' ' || l_theory_balance || ' ' || l_actual_balance || ' ' || l_days_late);
11455
11456 if l_add_prev_amount >= 0 then
11457
11458 if l_add_int_setting = 'Y' then -- fix for bug 8609721
11459
11460 -- additional interest
11461 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating additional interest...');
11462 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - ' || l_activity_date);
11463 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11464 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11465
11466 if (p_calc_method = 'SIMPLE') then
11467
11468 -- recalculate periodic rate for each period if day counting methodolgy varies
11469
11470 l_periodic_rate := lns_financials.getPeriodicRate(
11471 p_payment_freq => p_payment_freq
11472 ,p_period_start_date => l_add_prev_act_date
11473 ,p_period_end_date => l_activity_date
11474 ,p_annualized_rate => p_interest_rate
11475 ,p_days_count_method => p_day_count_method
11476 ,p_target => 'INTEREST');
11477
11478 elsif (p_calc_method = 'COMPOUND') then
11479
11480 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11481 ,p_payment_freq => p_payment_freq
11482 ,p_annualized_rate => p_interest_rate
11483 ,p_period_start_date => l_add_prev_act_date
11484 ,p_period_end_date => l_activity_date
11485 ,p_days_count_method => p_day_count_method
11486 ,p_target => 'INTEREST');
11487
11488 end if;
11489 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11490
11491 l_add_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11492 ,p_periodic_rate => l_periodic_rate
11493 ,p_compounding_period => null);
11494 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'additional interest = ' || l_add_interest);
11495
11496 if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11497 if l_add_int_detail_str is not null then
11498 l_add_int_detail_str := l_add_int_detail_str || ' +<br>';
11499 end if;
11500 l_add_int_detail_str := l_add_int_detail_str ||
11501 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11502 ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11503 ' * Rate ' || p_interest_rate || '%';
11504 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_add_int_detail_str);
11505 end if;
11506
11507 end if;
11508
11509 if p_penal_int_rate > 0 and
11510 ((trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and trunc(l_activity_date) <= trunc(p_grace_start_date)) or
11511 (trunc(l_activity_date) > trunc(p_grace_end_date)))
11512 then
11513
11514 if trunc(l_activity_date) > trunc(p_grace_end_date) and
11515 l_first_act_after_grace = true
11516 then
11517 l_add_prev_act_date := p_grace_start_date;
11518 l_first_act_after_grace := false;
11519 elsif trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and
11520 trunc(l_activity_date) <= trunc(p_grace_start_date) and
11521 l_first_act_after_prev_grace = true
11522 then
11523 if trunc(p_prev_grace_end_date) < trunc(p_period_start_date) then
11524 l_add_prev_act_date := p_period_start_date;
11525 else
11526 l_add_prev_act_date := p_prev_grace_end_date;
11527 end if;
11528 l_first_act_after_prev_grace := false;
11529 end if;
11530
11531 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating penal interest...');
11532 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - ' || l_activity_date);
11533 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11534 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_penal_int_rate);
11535
11536 -- calc penal interest rate
11537 if (p_calc_method = 'SIMPLE') then
11538
11539 l_penal_period_rate := lns_financials.getPeriodicRate(
11540 p_payment_freq => p_payment_freq
11541 ,p_period_start_date => l_add_prev_act_date
11542 ,p_period_end_date => l_activity_date
11543 ,p_annualized_rate => p_penal_int_rate
11544 ,p_days_count_method => p_day_count_method
11545 ,p_target => 'INTEREST');
11546
11547 elsif (p_calc_method = 'COMPOUND') then
11548
11549 l_penal_period_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11550 ,p_payment_freq => p_payment_freq
11551 ,p_annualized_rate => p_penal_int_rate
11552 ,p_period_start_date => l_add_prev_act_date
11553 ,p_period_end_date => l_activity_date
11554 ,p_days_count_method => p_day_count_method
11555 ,p_target => 'INTEREST');
11556
11557 end if;
11558
11559 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal periodic_rate = ' || l_penal_period_rate);
11560
11561 l_penal_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11562 ,p_periodic_rate => l_penal_period_rate
11563 ,p_compounding_period => null);
11564 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal interest = ' || l_penal_interest);
11565
11566 if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11567 if l_penal_int_detail_str is not null then
11568 l_penal_int_detail_str := l_penal_int_detail_str || ' +<br>';
11569 end if;
11570 l_penal_int_detail_str := l_penal_int_detail_str ||
11571 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11572 ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11573 ' * Rate ' || p_penal_int_rate || '%';
11574 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_penal_int_detail_str);
11575 end if;
11576 end if;
11577
11578 else
11579 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Ignoring this record b/c l_add_prev_amount < 0');
11580 end if;
11581
11582 l_cum_add_interest := l_cum_add_interest + l_add_interest;
11583 l_cum_penal_interest := l_cum_penal_interest + l_penal_interest;
11584 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative additional interest = ' || l_cum_add_interest);
11585 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative penal interest = ' || l_cum_penal_interest);
11586
11587 if p_target = 'UNPAID_PRIN' then
11588 l_add_prev_amount := l_actual_balance - l_theory_balance;
11589 elsif p_target = 'UNPAID_INT' then
11590 l_add_prev_amount := l_theory_balance - l_actual_balance;
11591 end if;
11592
11593 l_add_prev_act_date := l_activity_date;
11594 i := i + 1;
11595
11596 END LOOP;
11597 if p_target = 'UNPAID_PRIN' then
11598 close c_trx_prin_activities;
11599 elsif p_target = 'UNPAID_INT' then
11600 close c_trx_int_activities;
11601 end if;
11602
11603 -- manually adding last record for p_period_end_date date
11604 l_activity_date := p_period_end_date;
11605 l_activity_code := 'DUE';
11606 l_activity_amount := 0;
11607 l_days_late := 0;
11608 l_add_interest := 0;
11609 l_penal_interest := 0;
11610 /*
11611 if p_interest_rate is not null then
11612 l_interest_rate := p_interest_rate;
11613 end if;
11614 */
11615 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11616 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Rate Theory_Bal Actual_Bal Days_Late');
11617 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '*' || l_activity_date || ' ' || l_activity_code || ' ' || l_activity_amount || ' ' || l_interest_rate || ' ' || l_theory_balance || ' ' || l_actual_balance || ' ' || l_days_late);
11618
11619 if l_add_prev_amount >= 0 then
11620 if l_add_int_setting = 'Y' then -- fix for bug 8609721
11621
11622 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating additional interest...');
11623 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - *' || l_activity_date);
11624 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11625 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11626
11627 -- additional interest
11628 if (p_calc_method = 'SIMPLE') then
11629
11630 -- recalculate periodic rate for each period if day counting methodolgy varies
11631
11632 l_periodic_rate := lns_financials.getPeriodicRate(
11633 p_payment_freq => p_payment_freq
11634 ,p_period_start_date => l_add_prev_act_date
11635 ,p_period_end_date => l_activity_date
11636 ,p_annualized_rate => p_interest_rate
11637 ,p_days_count_method => p_day_count_method
11638 ,p_target => 'INTEREST');
11639
11640 elsif (p_calc_method = 'COMPOUND') then
11641
11642 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11643 ,p_payment_freq => p_payment_freq
11644 ,p_annualized_rate => p_interest_rate
11645 ,p_period_start_date => l_add_prev_act_date
11646 ,p_period_end_date => l_activity_date
11647 ,p_days_count_method => p_day_count_method
11648 ,p_target => 'INTEREST');
11649
11650 end if;
11651 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11652
11653 l_add_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11654 ,p_periodic_rate => l_periodic_rate
11655 ,p_compounding_period => null);
11656 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'additional interest = ' || l_add_interest);
11657
11658 if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11659 if l_add_int_detail_str is not null then
11660 l_add_int_detail_str := l_add_int_detail_str || ' +<br>';
11661 end if;
11662 l_add_int_detail_str := l_add_int_detail_str ||
11663 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11664 ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11665 ' * Rate ' || p_interest_rate || '%';
11666 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_add_int_detail_str);
11667 end if;
11668
11669 end if;
11670
11671 if p_penal_int_rate > 0 and
11672 ((trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and trunc(l_activity_date) <= trunc(p_grace_start_date)) or
11673 (trunc(l_activity_date) > trunc(p_grace_end_date)))
11674 then
11675
11676 if trunc(l_activity_date) > trunc(p_grace_end_date) and
11677 l_first_act_after_grace = true
11678 then
11679 l_add_prev_act_date := p_grace_start_date;
11680 l_first_act_after_grace := false;
11681 elsif trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and
11682 trunc(l_activity_date) <= trunc(p_grace_start_date) and
11683 l_first_act_after_prev_grace = true
11684 then
11685 if trunc(p_prev_grace_end_date) < trunc(p_period_start_date) then
11686 l_add_prev_act_date := p_period_start_date;
11687 else
11688 l_add_prev_act_date := p_prev_grace_end_date;
11689 end if;
11690 l_first_act_after_prev_grace := false;
11691 end if;
11692
11693 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating penal interest...');
11694 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - *' || l_activity_date);
11695 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11696 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_penal_int_rate);
11697
11698 -- calc penal interest rate
11699 if (p_calc_method = 'SIMPLE') then
11700
11701 l_penal_period_rate := lns_financials.getPeriodicRate(
11702 p_payment_freq => p_payment_freq
11703 ,p_period_start_date => l_add_prev_act_date
11704 ,p_period_end_date => l_activity_date
11705 ,p_annualized_rate => p_penal_int_rate
11706 ,p_days_count_method => p_day_count_method
11707 ,p_target => 'INTEREST');
11708
11709 elsif (p_calc_method = 'COMPOUND') then
11710
11711 l_penal_period_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11712 ,p_payment_freq => p_payment_freq
11713 ,p_annualized_rate => p_penal_int_rate
11714 ,p_period_start_date => l_add_prev_act_date
11715 ,p_period_end_date => l_activity_date
11716 ,p_days_count_method => p_day_count_method
11717 ,p_target => 'INTEREST');
11718
11719 end if;
11720
11721 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal periodic_rate = ' || l_penal_period_rate);
11722
11723 l_penal_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11724 ,p_periodic_rate => l_penal_period_rate
11725 ,p_compounding_period => null);
11726 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal interest = ' || l_penal_interest);
11727
11728 if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11729 if l_penal_int_detail_str is not null then
11730 l_penal_int_detail_str := l_penal_int_detail_str || ' +<br>';
11731 end if;
11732 l_penal_int_detail_str := l_penal_int_detail_str ||
11733 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11734 ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11735 ' * Rate ' || p_penal_int_rate || '%';
11736 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_penal_int_detail_str);
11737 end if;
11738
11739 end if;
11740
11741 else
11742 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Ignoring this record b/c l_add_prev_amount < 0');
11743 end if;
11744
11745 l_cum_add_interest := l_cum_add_interest + l_add_interest;
11746 l_cum_penal_interest := l_cum_penal_interest + l_penal_interest;
11747
11748 x_add_interest := round(l_cum_add_interest, l_precision);
11749 x_penal_interest := round(l_cum_penal_interest, l_precision);
11750 if x_add_interest = 0 and l_add_int_detail_str is null then
11751 x_add_int_details := null;
11752 else
11753 x_add_int_details := x_add_interest || ' (' || l_add_int_detail_str || ')';
11754 end if;
11755 x_penal_int_details := l_penal_int_detail_str;
11756
11757 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Additional Interest = ' || x_add_interest);
11758 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Additional Interest Details = ' || x_add_int_details);
11759
11760 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Penal Interest = ' || x_penal_interest);
11761 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Penal Interest Details = ' || x_penal_int_details);
11762
11763 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
11764 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11765
11766 end;
11767
11768
11769
11770 procedure get_char2num_conv_chars(x_chars_to_replace out nocopy varchar2, x_replace_chars out nocopy varchar2)
11771 is
11772 l_num number;
11773 l_str varchar2(10);
11774 l_char varchar2(1);
11775 BEGIN
11776
11777 l_num := 123.12;
11778
11779 select to_char(l_num) into l_str from dual;
11780 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'number 123.12 => string ' || l_str);
11781
11782 l_char := substr(l_str, 4, 1);
11783 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'number . => char ' || l_char);
11784
11785 x_chars_to_replace := ',.';
11786 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_chars_to_replace = ' || x_chars_to_replace);
11787 x_replace_chars := l_char || l_char;
11788 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_replace_chars = ' || x_replace_chars);
11789
11790 END;
11791
11792
11793
11794 -- this procedure loads original amortization schedule from agreement report
11795 procedure LOAD_ORIGINAL_SCHEDULE(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC,
11796 x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
11797 is
11798 /*-----------------------------------------------------------------------+
11799 | Local Variable Declarations and initializations |
11800 +-----------------------------------------------------------------------*/
11801
11802 l_api_name CONSTANT VARCHAR2(30) := 'LOAD_ORIGINAL_SCHEDULE';
11803 l_clob CLOB;
11804 l_parser dbms_xmlparser.Parser;
11805 l_doc dbms_xmldom.DOMDocument;
11806 l_nl dbms_xmldom.DOMNodeList;
11807 l_n dbms_xmldom.DOMNode;
11808 i number;
11809 l_data varchar2(2000);
11810 l_loan_id number;
11811 l_period_start_date date;
11812 l_replace_chars varchar2(10);
11813 l_chars_to_replace varchar2(10);
11814 l_adj number;
11815 l_FUNDED_AMOUNT number;
11816 l_value varchar2(100);
11817 l_date_format varchar2(20);
11818 l_unknown_date_format varchar2(20);
11819
11820 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
11821 l_rate_schedule LNS_FINANCIALS.RATE_SCHEDULE_TBL;
11822
11823 /*-----------------------------------------------------------------------+
11824 | Cursor Declarations |
11825 +-----------------------------------------------------------------------*/
11826
11827 CURSOR c_get_xml(p_loan_id NUMBER) IS
11828 SELECT nvl(DOCUMENT_XML, empty_clob())
11829 FROM LNS_LOAN_DOCUMENTS
11830 WHERE source_id = p_loan_id and
11831 SOURCE_TABLE = 'LNS_LOAN_HEADERS_ALL' and
11832 DOCUMENT_TYPE = 'LOAN_AGREEMENT' AND
11833 VERSION = 1;
11834
11835 BEGIN
11836
11837 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11838 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
11839
11840 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Fetching clob...');
11841 l_clob := empty_clob();
11842 open c_get_xml(p_loan_details.LOAN_ID);
11843 fetch c_get_xml into l_clob;
11844 close c_get_xml;
11845 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'lenght = ' || length(l_clob));
11846
11847 if length(l_clob) = 0 then
11848 x_loan_amort_tbl := l_amort_tbl;
11849 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Clob is empty. Returning.');
11850 return;
11851 end if;
11852
11853 -- Create a parser.
11854 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Creating a parser...');
11855 l_parser := dbms_xmlparser.newParser;
11856
11857 -- Parse the document and create a new DOM document.
11858 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Parsing the document and creating a new DOM document...');
11859 dbms_xmlparser.parseClob(l_parser, l_clob);
11860 l_doc := dbms_xmlparser.getDocument(l_parser);
11861
11862 -- Free resources associated with the CLOB and Parser now they are no longer needed.
11863 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Freeing resources...');
11864 dbms_xmlparser.freeParser(l_parser);
11865
11866 get_char2num_conv_chars(l_chars_to_replace, l_replace_chars);
11867
11868 -- Get a list of all the RATE_SCHEDULE_ROW nodes in the document using the XPATH syntax.
11869 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Getting a list of all the RATE_SCHEDULE_ROW nodes...');
11870 l_nl := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(l_doc),'/LNSAGREEMENT/ROWSET/ROW/RATE_SCHEDULE/RATE_SCHEDULE_ROW');
11871 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11872 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Rate schedule:');
11873 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FROM TO RATE');
11874 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '---- ---- ----');
11875
11876 i := 0;
11877 l_unknown_date_format := '?';
11878 FOR cur_emp IN 0 .. dbms_xmldom.getLength(l_nl) - 1 LOOP
11879 l_n := dbms_xmldom.item(l_nl, cur_emp);
11880 i := i+1;
11881
11882 dbms_xslprocessor.valueOf(l_n,'INSTALLMENT_FROM/text()',l_data);
11883 l_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11884 dbms_xslprocessor.valueOf(l_n,'INSTALLMENT_TO/text()',l_data);
11885 l_rate_schedule(i).END_INSTALLMENT_NUMBER := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11886 dbms_xslprocessor.valueOf(l_n,'INTEREST_RATE/text()',l_data);
11887 l_rate_schedule(i).ANNUAL_RATE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11888
11889 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME,
11890 l_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER || ' ' ||
11891 l_rate_schedule(i).END_INSTALLMENT_NUMBER || ' ' ||
11892 l_rate_schedule(i).ANNUAL_RATE);
11893 END LOOP;
11894
11895 -- Get a list of all the AMORTIZATION_ROW nodes in the document using the XPATH syntax.
11896 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Getting a list of all the AMORTIZATION_ROW nodes...');
11897 l_nl := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(l_doc),'/LNSAGREEMENT/ROWSET/ROW/AMORTIZATION/AMORTIZATION_ROW');
11898
11899 -- Loop through the list and create a new record in a tble collection
11900 -- for each EMP record.
11901
11902 i := 0;
11903 l_period_start_date := p_loan_details.LOAN_START_DATE;
11904 l_FUNDED_AMOUNT := 0;
11905 FOR cur_emp IN 0 .. dbms_xmldom.getLength(l_nl) - 1 LOOP
11906 l_n := dbms_xmldom.item(l_nl, cur_emp);
11907 i := i+1;
11908
11909 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11910
11911 -- Use XPATH syntax to assign values to he elements of the collection.
11912 dbms_xslprocessor.valueOf(l_n,'PAYMENT_NUMBER/text()',l_data);
11913 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_NUMBER data = ' || l_data);
11914 l_amort_tbl(i).INSTALLMENT_NUMBER := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11915
11916 dbms_xslprocessor.valueOf(l_n,'DUE_DATE/text()',l_data);
11917 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DUE_DATE data = ' || l_data);
11918
11919 if l_date_format is null then
11920 -- convert due date logic:
11921 -- 1. trying 11i format DD-MON-RRRR
11922 -- 2. trying old R12 format MM/DD/YYYY
11923 -- 3. trying new R12 format YYYY-MM-DD
11924 BEGIN
11925 l_date_format := 'DD-MON-RRRR'; -- 11i code used fnd_date.date_to_chardate api which used this hardcoded date format
11926 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Trying to convert using 11i format ' || l_date_format || '...');
11927 l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11928 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Success!');
11929 EXCEPTION
11930 WHEN OTHERS THEN
11931 BEGIN
11932 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Failed. ERROR: ' || sqlerrm);
11933 l_date_format := 'MM/DD/YYYY';
11934 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Trying to convert using old R12 format ' || l_date_format || '...');
11935 l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11936 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Success!');
11937 EXCEPTION
11938 WHEN OTHERS THEN
11939 BEGIN
11940 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Failed. ERROR: ' || sqlerrm);
11941 l_date_format := 'YYYY-MM-DD';
11942 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Trying to convert using new R12 format ' || l_date_format || '...');
11943 l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11944 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Success!');
11945 EXCEPTION
11946 WHEN OTHERS THEN
11947 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Failed. ERROR: ' || sqlerrm);
11948 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Oh well, we tried hard. Unknown date format. No due date then :(');
11949 l_amort_tbl(i).DUE_DATE := to_date(null);
11950 l_date_format := l_unknown_date_format;
11951 END;
11952 END;
11953 END;
11954 elsif l_date_format = l_unknown_date_format then
11955 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Date format is unknown, setting due date to null');
11956 l_amort_tbl(i).DUE_DATE := to_date(null);
11957 else
11958 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Date format = ' || l_date_format);
11959 l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11960 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Due date is converted successfully');
11961 end if;
11962
11963 dbms_xslprocessor.valueOf(l_n,'PAYMENT_PRINCIPAL/text()',l_data);
11964 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_PRINCIPAL data = ' || l_data);
11965 l_amort_tbl(i).PRINCIPAL_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11966
11967 dbms_xslprocessor.valueOf(l_n,'PAYMENT_INTEREST/text()',l_data);
11968 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_INTEREST data = ' || l_data);
11969 l_amort_tbl(i).INTEREST_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11970
11971 dbms_xslprocessor.valueOf(l_n,'PAYMENT_FEES/text()',l_data);
11972 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_FEES data = ' || l_data);
11973 l_amort_tbl(i).FEE_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11974
11975 dbms_xslprocessor.valueOf(l_n,'OTHER_AMOUNT/text()',l_data);
11976 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'OTHER_AMOUNT data = ' || l_data);
11977 l_amort_tbl(i).OTHER_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11978
11979 dbms_xslprocessor.valueOf(l_n,'PAYMENT_TOTAL/text()',l_data);
11980 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_TOTAL data = ' || l_data);
11981 l_amort_tbl(i).TOTAL := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11982
11983 dbms_xslprocessor.valueOf(l_n,'BEGINNING_BALANCE/text()',l_data);
11984 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'BEGINNING_BALANCE data = ' || l_data);
11985 l_amort_tbl(i).BEGIN_BALANCE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11986
11987 dbms_xslprocessor.valueOf(l_n,'ENDING_BALANCE/text()',l_data);
11988 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ENDING_BALANCE data = ' || l_data);
11989 l_amort_tbl(i).END_BALANCE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11990
11991 dbms_xslprocessor.valueOf(l_n,'INTEREST_CUMULATIVE/text()',l_data);
11992 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_CUMULATIVE data = ' || l_data);
11993 l_amort_tbl(i).INTEREST_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11994
11995 dbms_xslprocessor.valueOf(l_n,'PRINCIPAL_CUMULATIVE/text()',l_data);
11996 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PRINCIPAL_CUMULATIVE data = ' || l_data);
11997 l_amort_tbl(i).PRINCIPAL_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11998
11999 dbms_xslprocessor.valueOf(l_n,'FEES_CUMULATIVE/text()',l_data);
12000 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FEES_CUMULATIVE data = ' || l_data);
12001 l_amort_tbl(i).FEES_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
12002
12003 dbms_xslprocessor.valueOf(l_n,'OTHER_CUMULATIVE/text()',l_data);
12004 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'OTHER_CUMULATIVE data = ' || l_data);
12005 l_amort_tbl(i).OTHER_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
12006
12007 dbms_xslprocessor.valueOf(l_n,'SOURCE/text()',l_data);
12008 l_amort_tbl(i).SOURCE := l_data;
12009
12010 dbms_xslprocessor.valueOf(l_n,'NORMAL_INT_AMOUNT/text()',l_data);
12011 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT data = ' || l_data);
12012 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12013 if l_value is not null then
12014 l_amort_tbl(i).NORMAL_INT_AMOUNT := to_number(l_value);
12015 else
12016 l_amort_tbl(i).NORMAL_INT_AMOUNT := l_amort_tbl(i).INTEREST_AMOUNT;
12017 end if;
12018 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amort_tbl(i).NORMAL_INT_AMOUNT);
12019
12020 dbms_xslprocessor.valueOf(l_n,'PREV_DEFERRED_INT_AMOUNT/text()',l_data);
12021 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_DEFERRED_INT_AMOUNT data = ' || l_data);
12022 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12023 if l_value is not null then
12024 l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT := to_number(l_value);
12025 else
12026 l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT := 0;
12027 end if;
12028 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_DEFERRED_INT_AMOUNT = ' || l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT);
12029
12030 dbms_xslprocessor.valueOf(l_n,'DEFERRED_INT_AMOUNT/text()',l_data);
12031 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DEFERRED_INT_AMOUNT data = ' || l_data);
12032 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12033 if l_value is not null then
12034 l_amort_tbl(i).DEFERRED_INT_AMOUNT := to_number(l_value);
12035 else
12036 l_amort_tbl(i).DEFERRED_INT_AMOUNT := 0;
12037 end if;
12038 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DEFERRED_INT_AMOUNT = ' || l_amort_tbl(i).DEFERRED_INT_AMOUNT);
12039
12040 dbms_xslprocessor.valueOf(l_n,'PREV_CAP_INT_AMOUNT/text()',l_data);
12041 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT data = ' || l_data);
12042 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12043 if l_value is not null then
12044 l_amort_tbl(i).PREV_CAP_INT_AMOUNT := to_number(l_value);
12045 else
12046 l_amort_tbl(i).PREV_CAP_INT_AMOUNT := 0;
12047 end if;
12048 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amort_tbl(i).PREV_CAP_INT_AMOUNT);
12049
12050 dbms_xslprocessor.valueOf(l_n,'CURR_CAP_INT_AMOUNT/text()',l_data);
12051 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT data = ' || l_data);
12052 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12053 if l_value is not null then
12054 l_amort_tbl(i).CURR_CAP_INT_AMOUNT := to_number(l_value);
12055 else
12056 l_amort_tbl(i).CURR_CAP_INT_AMOUNT := 0;
12057 end if;
12058 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amort_tbl(i).CURR_CAP_INT_AMOUNT);
12059
12060 dbms_xslprocessor.valueOf(l_n,'CAP_INT_AMOUNT/text()',l_data);
12061 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT data = ' || l_data);
12062 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12063 if l_value is not null then
12064 l_amort_tbl(i).CAP_INT_AMOUNT := to_number(l_value);
12065 else
12066 l_amort_tbl(i).CAP_INT_AMOUNT := 0;
12067 end if;
12068 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amort_tbl(i).CAP_INT_AMOUNT);
12069
12070 dbms_xslprocessor.valueOf(l_n,'NORMAL_INT_DETAILS/text()',l_data);
12071 l_amort_tbl(i).NORMAL_INT_DETAILS := l_data;
12072 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amort_tbl(i).NORMAL_INT_DETAILS);
12073
12074 dbms_xslprocessor.valueOf(l_n,'DEFERRED_INT_DETAILS/text()',l_data);
12075 l_amort_tbl(i).DEFERRED_INT_DETAILS := l_data;
12076 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DEFERRED_INT_DETAILS = ' || l_amort_tbl(i).DEFERRED_INT_DETAILS);
12077
12078 dbms_xslprocessor.valueOf(l_n,'CAP_INT_DETAILS/text()',l_data);
12079 l_amort_tbl(i).CAP_INT_DETAILS := l_data;
12080 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amort_tbl(i).CAP_INT_DETAILS);
12081
12082 dbms_xslprocessor.valueOf(l_n,'DISBURSEMENT_AMOUNT/text()',l_data);
12083 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DISBURSEMENT_AMOUNT data = ' || l_data);
12084 l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12085 if l_value is not null then
12086 l_amort_tbl(i).DISBURSEMENT_AMOUNT := to_number(l_value);
12087 else
12088 if l_amort_tbl(i).INSTALLMENT_NUMBER = 0 or l_amort_tbl(i).INSTALLMENT_NUMBER = 1 then
12089 l_adj := 0;
12090 else
12091 l_adj := l_amort_tbl(i-1).END_BALANCE;
12092 end if;
12093 l_amort_tbl(i).DISBURSEMENT_AMOUNT :=
12094 abs(l_amort_tbl(i).BEGIN_BALANCE - l_amort_tbl(i).END_BALANCE - l_amort_tbl(i).PRINCIPAL_AMOUNT) +
12095 (l_amort_tbl(i).BEGIN_BALANCE - l_adj);
12096 end if;
12097 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DISBURSEMENT_AMOUNT = ' || l_amort_tbl(i).DISBURSEMENT_AMOUNT);
12098
12099 FOR j IN 1 .. l_rate_schedule.count LOOP
12100 if l_amort_tbl(i).INSTALLMENT_NUMBER >= l_rate_schedule(j).BEGIN_INSTALLMENT_NUMBER and
12101 l_amort_tbl(i).INSTALLMENT_NUMBER <= l_rate_schedule(j).END_INSTALLMENT_NUMBER
12102 then
12103 l_amort_tbl(i).INTEREST_RATE := l_rate_schedule(j).ANNUAL_RATE;
12104 exit;
12105 end if;
12106 END LOOP;
12107
12108 l_amort_tbl(i).PERIOD_START_DATE := l_period_start_date;
12109 l_amort_tbl(i).PERIOD_END_DATE := l_amort_tbl(i).DUE_DATE;
12110 l_amort_tbl(i).UNPAID_PRIN := 0;
12111 l_amort_tbl(i).UNPAID_INT := 0;
12112 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT := 0;
12113 l_amort_tbl(i).ADD_INT_INT_AMOUNT := 0;
12114 l_amort_tbl(i).PENAL_INT_AMOUNT := 0;
12115 l_amort_tbl(i).EARLY_PAY_CR_AMOUNT := 0;
12116
12117 if l_amort_tbl(i).INSTALLMENT_NUMBER = 0 then
12118 l_amort_tbl(i).INTEREST_RATE := l_rate_schedule(1).ANNUAL_RATE;
12119 l_amort_tbl(i).PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_amort_tbl(i).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_amort_tbl(i).PERIOD_START_DATE, 1);
12120 else
12121 l_amort_tbl(i).PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_amort_tbl(i).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_amort_tbl(i).DUE_DATE-1), 1);
12122 end if;
12123
12124 l_amort_tbl(i).FUNDED_AMOUNT := l_FUNDED_AMOUNT + l_amort_tbl(i).DISBURSEMENT_AMOUNT;
12125 l_FUNDED_AMOUNT := l_amort_tbl(i).FUNDED_AMOUNT;
12126 l_period_start_date := l_amort_tbl(i).PERIOD_END_DATE;
12127
12128 END LOOP;
12129
12130 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
12131 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Original amortization schedule:');
12132 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PN DD RATE BB PAY PRIN INT FEE OTHER EB');
12133 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--- ------- ---- ------ ------ ------ ------ ------ ------ ------');
12134
12135 FOR i IN 1 .. l_amort_tbl.count LOOP
12136 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME,
12137 l_amort_tbl(i).INSTALLMENT_NUMBER || ' ' ||
12138 l_amort_tbl(i).DUE_DATE || ' ' ||
12139 l_amort_tbl(i).INTEREST_RATE || ' ' ||
12140 l_amort_tbl(i).BEGIN_BALANCE || ' ' ||
12141 l_amort_tbl(i).TOTAL || ' ' ||
12142 l_amort_tbl(i).PRINCIPAL_AMOUNT || ' ' ||
12143 l_amort_tbl(i).INTEREST_AMOUNT || ' ' ||
12144 l_amort_tbl(i).FEE_AMOUNT || ' ' ||
12145 l_amort_tbl(i).OTHER_AMOUNT || ' ' ||
12146 l_amort_tbl(i).END_BALANCE);
12147 END LOOP;
12148
12149 -- Free any resources associated with the document now it
12150 -- is no longer needed.
12151 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Freeing resources...');
12152 dbms_xmldom.freeDocument(l_doc);
12153 dbms_xmlparser.freeParser(l_parser);
12154
12155 x_loan_amort_tbl := l_amort_tbl;
12156 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
12157
12158 EXCEPTION
12159 WHEN OTHERS THEN
12160 LogMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, ' - in exception. Error: ' || sqlerrm);
12161 --dbms_lob.freetemporary(l_clob);
12162 dbms_xmlparser.freeParser(l_parser);
12163 dbms_xmldom.freeDocument(l_doc);
12164 FND_MESSAGE.SET_NAME('LNS', 'LNS_API_OTHERS_EXCEP');
12165 FND_MESSAGE.SET_TOKEN('ERROR' ,sqlerrm);
12166 FND_MSG_PUB.Add;
12167 END;
12168
12169
12170 -- This procedure calculates interest credit on early payment
12171 procedure CALC_EARLY_PAY_CR(p_loan_id in number,
12172 p_calc_method in varchar2,
12173 p_installment in number,
12174 p_interest_rate in number,
12175 p_day_count_method in varchar2,
12176 p_payment_freq in varchar2,
12177 p_compound_freq in varchar2,
12178 x_early_pay_cr out NOCOPY number,
12179 x_EARLY_PAY_CR_DETAILS out NOCOPY varchar2)
12180 is
12181 l_api_name varchar2(25);
12182 l_activity_code varchar2(30);
12183 l_activity_amount number;
12184 l_theory_balance number;
12185 l_actual_balance number;
12186 l_days_late number;
12187 l_display_order number;
12188 i number;
12189 l_from_date date;
12190 l_to_date date;
12191 l_cr_amount number;
12192 l_cum_cr_amount number;
12193 l_cr_detail_str varchar2(2000);
12194 l_periodic_rate number;
12195 l_precision number;
12196 l_early_pay_setting varchar2(1);
12197 l_amount number;
12198
12199 cursor c_early_payments(p_loan_id number, p_payment_number number) is
12200 select
12201 trunc(ACTIVITY_DATE),
12202 trunc(DUE_DATE),
12203 ACTIVITY_CODE,
12204 ACTIVITY_AMOUNT,
12205 THEORETICAL_BALANCE,
12206 ACTUAL_BALANCE,
12207 DAYS_LATE,
12208 display_order
12209 from LNS_PRIN_TRX_ACTIVITIES_V
12210 where loan_id = p_loan_id and
12211 payment_number = p_payment_number and
12212 DAYS_LATE < 0 and
12213 ACTIVITY_CODE in ('PMT', 'CM', 'ADJUSTMENT')
12214 order by activity_date, display_order, LOAN_AMORTIZATION_ID;
12215
12216 cursor c_early_payment_setting(p_loan_id number) is
12217 select nvl(term.CALC_EARLY_PAY_CR, 'N')
12218 from lns_loan_headers loan,
12219 lns_terms term
12220 where loan.loan_id = p_loan_id and
12221 loan.loan_id = term.loan_id;
12222
12223 cursor c_curr_precision(p_loan_id number) is
12224 select curr.precision
12225 from lns_loan_headers_all h
12226 ,fnd_currencies curr
12227 where h.loan_id = p_loan_id
12228 and curr.currency_code = h.loan_currency;
12229
12230 begin
12231
12232 l_api_name := 'CALC_EARLY_PAY_CR';
12233 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
12234 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
12235 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
12236 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
12237 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
12238 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': installment: ' || p_installment);
12239 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
12240 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
12241 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
12242 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
12243
12244 i := 1;
12245 l_cr_amount := 0;
12246 l_cum_cr_amount := 0;
12247 x_early_pay_cr := 0;
12248
12249 -- checking for setting
12250 OPEN c_early_payment_setting(p_loan_id);
12251 FETCH c_early_payment_setting INTO l_early_pay_setting;
12252 CLOSE c_early_payment_setting;
12253 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_early_pay_setting = ' || l_early_pay_setting);
12254
12255 if l_early_pay_setting = 'N' then
12256 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculate Interest Credit on Early Payments is off. Exiting');
12257 return;
12258 end if;
12259
12260 OPEN c_curr_precision(p_loan_id);
12261 FETCH c_curr_precision INTO l_precision;
12262 CLOSE c_curr_precision;
12263
12264 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
12265
12266 OPEN c_early_payments(p_loan_id, p_installment-1);
12267 LOOP
12268
12269 FETCH c_early_payments INTO
12270 l_from_date
12271 ,l_to_date
12272 ,l_activity_code
12273 ,l_activity_amount
12274 ,l_theory_balance
12275 ,l_actual_balance
12276 ,l_days_late
12277 ,l_display_order;
12278
12279 EXIT WHEN c_early_payments%NOTFOUND;
12280
12281 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
12282 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'From_Date To_Date Act Act_Amount Theory_Bal Actual_Bal Days_Late');
12283 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_from_date || ' ' || l_to_date || ' ' ||
12284 l_activity_code || ' ' || l_activity_amount || ' ' || l_theory_balance || ' ' || l_actual_balance || ' ' || l_days_late);
12285
12286 l_amount := abs(l_theory_balance - l_actual_balance);
12287 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating amount...');
12288 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_from_date || ' - ' || l_to_date);
12289 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_amount);
12290 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
12291
12292 if (p_calc_method = 'SIMPLE') then
12293
12294 -- recalculate periodic rate for each period if day counting methodolgy varies
12295
12296 l_periodic_rate := lns_financials.getPeriodicRate(
12297 p_payment_freq => p_payment_freq
12298 ,p_period_start_date => l_from_date
12299 ,p_period_end_date => l_to_date
12300 ,p_annualized_rate => p_interest_rate
12301 ,p_days_count_method => p_day_count_method
12302 ,p_target => 'INTEREST');
12303
12304 elsif (p_calc_method = 'COMPOUND') then
12305
12306 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
12307 ,p_payment_freq => p_payment_freq
12308 ,p_annualized_rate => p_interest_rate
12309 ,p_period_start_date => l_from_date
12310 ,p_period_end_date => l_to_date
12311 ,p_days_count_method => p_day_count_method
12312 ,p_target => 'INTEREST');
12313
12314 end if;
12315 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
12316
12317 l_cr_amount := lns_financials.calculateInterest(p_amount => l_amount
12318 ,p_periodic_rate => l_periodic_rate
12319 ,p_compounding_period => null);
12320 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculated credit amount = ' || l_cr_amount);
12321
12322 if l_cr_detail_str is not null then
12323 l_cr_detail_str := l_cr_detail_str || ' +<br>';
12324 end if;
12325 l_cr_detail_str := l_cr_detail_str ||
12326 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_from_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_to_date-1), 1) ||
12327 ' * Balance ' || round(l_amount, l_precision) ||
12328 ' * Rate ' || p_interest_rate || '%';
12329 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_cr_detail_str);
12330
12331 l_cum_cr_amount := l_cum_cr_amount + l_cr_amount;
12332 i := i + 1;
12333 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Cumulative credit amount = ' || l_cum_cr_amount);
12334
12335 END LOOP;
12336 close c_early_payments;
12337
12338 x_early_pay_cr := round(l_cum_cr_amount, l_precision);
12339 if l_cr_detail_str is not null then
12340 l_cr_detail_str := ' (' || l_cr_detail_str || ')';
12341 end if;
12342
12343 x_EARLY_PAY_CR_DETAILS := x_early_pay_cr || l_cr_detail_str;
12344
12345 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Credit Amount = ' || x_early_pay_cr);
12346 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Credit Amount Details = ' || x_EARLY_PAY_CR_DETAILS);
12347 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
12348 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
12349
12350 end;
12351
12352
12353
12354 END LNS_FINANCIALS;