[Home] [Help]
PACKAGE BODY: APPS.LNS_FINANCIALS
Source
1 PACKAGE BODY LNS_FINANCIALS AS
2 /* $Header: LNS_FINANCIAL_B.pls 120.28.12010000.7 2009/01/20 10:59:49 gparuchu 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
12 G_PKG_NAME CONSTANT VARCHAR2(30) := 'LNS_FINANCIALS';
13
14 --------------------------------------------
15 -- internal package routines
16 --------------------------------------------
17
18 procedure logMessage(log_level in number
19 ,module in varchar2
20 ,message in varchar2)
21 is
22
23 begin
24
25 IF log_level >= FND_LOG.G_CURRENT_RUNTIME_LEVEL THEN
26 FND_LOG.STRING(log_level, module, message);
27 END IF;
28
29 end;
30
31 -- internal usage only
32 function formatTerm(p_timeString IN varchar2) return varchar2
33 is
34
35 l_temp varchar2(30);
36 begin
37
38 -- this logic is to handle "MONTHLY" => "MONTHS" ETC...
39 if substr(p_timeString, length(p_timeString) - 1, 2) = 'LY' then
40 l_temp := substr(p_timeString, 1, length(p_timeString) - 2) || 'S';
41 else
42 l_temp := p_timeString;
43 end if;
44
45 return l_temp;
46
47 end;
48
49 /*
50 || Overview: debugging routine only
51 ||
52 || Parameter: amortizationTable to log
53 ||
54 || Creation date: 12/08/2003 6:31PM
55 ||
56 */
57 procedure printAmortizationTable(p_amort_tbl IN lns_financials.amortization_tbl)
58
59 is
60
61 l_api_name varchar2(30);
62 i number;
63 l_installment_number varchar2(30);
64 l_due_date varchar2(30);
65 l_principal_amount varchar2(30);
66 l_interest_amount varchar2(30);
67 l_fee_amount varchar2(30);
68 l_other_amount varchar2(30);
69 l_total varchar2(30);
70 l_begin_balance varchar2(30);
71 l_end_balance varchar2(30);
72 l_principal_cumulative varchar2(30);
73 l_interest_cumulative varchar2(30);
74 l_fees_cumulative varchar2(30);
75 l_other_cumulative varchar2(30);
76 l_rate_id varchar2(30);
77
78 begin
79 i := 0;
80 l_api_name := 'printAmortizationTable';
81
82 i := p_amort_tbl.count;
83 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
84 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization table count: ' || i);
85 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Period Due Date TOTAL DUE Interest Principal Fees Other ' ||
86 ' Cum.Interest Cum.Principal Cum.Fees Cum.Other Begin Balance End Balanace ');
87 /*
88 for k in 1..i
89 loop
90 l_installment_number := nvl(to_char(p_amort_tbl(k).installment_number), ' ');
91 l_due_date := nvl(to_char(p_amort_tbl(k).due_date, 'mm/dd/yy'), ' ');
92 l_total := nvl(to_char(p_amort_tbl(k).total), ' ');
93 l_interest_amount := nvl(to_char(p_amort_tbl(k).interest_amount), ' ');
94 l_principal_amount := nvl(to_char(p_amort_tbl(k).principal_amount), ' ');
95 l_other_amount := nvl(to_char(p_amort_tbl(k).other_amount), ' ');
96 l_fee_amount := nvl(to_char(p_amort_tbl(k).fee_amount), ' ');
97 -- l_interest_cumulative := nvl(to_char(p_amort_tbl(k).interest_cumulative), ' ');
98 -- l_principal_cumulative := nvl(to_char(p_amort_tbl(k).principal_cumulative), ' ');
99 -- l_fees_cumulative := nvl(to_char(p_amort_tbl(k).fees_cumulative), ' ');
100 -- l_other_cumulative := nvl(to_char(p_amort_tbl(k).other_cumulative), ' ');
101 -- l_rate_id := nvl(to_char(p_amort_tbl(k).rate_id), ' ');
102 l_begin_balance := nvl(to_char(p_amort_tbl(k).begin_balance), ' ');
103 l_end_balance := nvl(to_char(p_amort_tbl(k).end_balance), ' ');
104
105 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ' || l_installment_number ||
106 ' ' || l_due_date ||
107 ' ' || l_total ||
108 ' ' || l_interest_amount ||
109 ' ' || l_principal_amount ||
110 ' ' || l_other_amount ||
111 ' ' || l_fee_amount ||
112 -- ' ' || l_fees_cumulative ||
113 -- ' ' || l_other_cumulative ||
114 -- ' ' || l_interest_cumulative ||
115 -- ' ' || l_principal_cumulative ||
116 ' ' || l_begin_balance ||
117 ' ' || l_end_balance);
118 end loop;
119 */
120 end printAmortizationTable;
121
122 /* routine will sort loanActivities by activityDate
123 */
124 procedure sortRows(p_loan_activity_tbl in out nocopy LNS_FINANCIALS.LOAN_ACTIVITY_TBL)
125
126 is
127 j number; -- counter
128 l_tmp_row LNS_FINANCIALS.LOAN_ACTIVITY_REC; -- to store temp row
129 l_min date; -- minimum date
130
131 begin
132
133 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, ' - sorting the rows');
134 for i in 1..p_loan_activity_tbl.count loop
135 l_min := p_loan_activity_tbl(i).activity_date;
136
137 for j in i + 1..p_loan_activity_tbl.count loop
138
139 if p_loan_activity_tbl(j).activity_date < l_min then
140 l_min := p_loan_activity_tbl(j).activity_date;
141 l_tmp_row := p_loan_activity_tbl(i);
142 p_loan_activity_tbl(i) := p_loan_activity_tbl(j);
143 p_loan_activity_tbl(j) := l_tmp_row;
144 end if;
145 end loop;
146 end loop;
147 end sortRows;
148
149 /*=========================================================================
150 || PUBLIC PROCEDURE floatingRatePostProcessing
151 ||
152 || DESCRIPTION
153 ||
154 || Overview: handle all post processing steps after BILLLING a FLOATING rate loan
155 ||
156 || Parameter: p_loan_id => loan id
157 || p_period_begin_date => date at which interest was last adjusted
158 || p_annualized_interest_rate => rate for which installment was billed
159 || p_rate_id => rateID for rae
160 ||
161 || Return value:
162 ||
163 || Source Tables:
164 ||
165 || Target Tables: LNS_TERMS, LNS_RATE_SCHEDULES
166 ||
167 || KNOWN ISSUES
168 ||
169 || NOTES
170 || -- POST PROCESSING STEPS recalculate and enter into LNS_TERMS
171 || -- 1. next_rate_change_date
172 || -- 2. new projected rate
173 || -- 3. re-align rate schedule
174 ||
175 || MODIFICATION HISTORY
176 || Date Author Description of Changes
177 || 11/24/2005 11:35AM raverma Created
178 || 06/16/2006 11:35AM karamach Added code to check and update only the existing rate sch row
179 || when begin_installment_number = end_installment_number = p_installment_number for the rate schedule row being processed
180 || as part of the fix for bug5331888
181 ||
182 *=======================================================================*/
183 procedure floatingRatePostProcessing(p_loan_id IN NUMBER
184 ,p_init_msg_list IN VARCHAR2
185 ,p_commit IN VARCHAR2
186 ,p_installment_number IN NUMBER
187 ,p_period_begin_date IN DATE
188 ,p_interest_adjustment_freq IN VARCHAR2
189 ,p_annualized_interest_rate IN NUMBER
190 ,p_rate_id IN OUT NOCOPY NUMBER
191 ,p_phase IN VARCHAR2
192 ,x_return_status OUT NOCOPY VARCHAR2
193 ,x_msg_count OUT NOCOPY NUMBER
194 ,x_msg_data OUT NOCOPY VARCHAR2)
195 is
196 l_next_rate_change date;
197 l_api_name varchar2(30);
198 l_new_rate_id number;
199 l_return_status VARCHAR2(1);
200 l_msg_count NUMBER;
201 l_msg_data VARCHAR2(32767);
202
203 Cursor c_get_rate_sch_info(pRateId number) is
204 select begin_installment_number, end_installment_number
205 from lns_rate_schedules where rate_id = pRateId;
206 l_begin_inst_num number;
207 l_end_inst_num number;
208 BEGIN
209
210 l_api_name := 'floatingRatePostProcessing';
211 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
212 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
213 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
214 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number ' || p_installment_number);
215 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_period_begin_date ' || p_period_begin_date);
216 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_interest_adjustment_freq ' || p_interest_adjustment_freq);
217 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_annualized_interest_rate ' || p_annualized_interest_rate);
218 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_rate_id ' || p_rate_id);
219 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
220
221 -- Standard Start of API savepoint
222 SAVEPOINT floatingPostProcessor;
223
224 -- Initialize message list IF p_init_msg_list is set to TRUE.
225 IF FND_API.to_Boolean(p_init_msg_list) THEN
226 FND_MSG_PUB.initialize;
227 END IF;
228
229 -- Initialize API return status to SUCCESS
230 x_return_status := FND_API.G_RET_STS_SUCCESS;
231
232 --
233 -- Api body
234 -- ----------------------------------------------------------------
235
236 if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
237 ,p_phase => p_phase) then
238 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting next rate change info');
239 l_next_rate_change := lns_fin_utils.getNextDate(p_date => p_period_begin_date
240 ,p_interval_type => p_interest_adjustment_freq
241 ,p_direction => 1);
242 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating terms with new date ' || l_next_rate_change);
243 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating terms with new rate' || p_annualized_interest_rate);
244 if p_phase = 'OPEN' then
245 update lns_terms
246 set next_rate_change_date = l_next_rate_change
247 ,open_projected_rate = p_annualized_interest_rate
248 ,last_update_date = sysdate
249 ,last_updated_by = lns_utility_pub.user_id
250 where loan_id = p_loan_id;
251 elsif p_phase = 'TERM' then
252 update lns_terms
253 set next_rate_change_date = l_next_rate_change
254 ,term_projected_rate = p_annualized_interest_rate
255 ,last_update_date = sysdate
256 ,last_updated_by = lns_utility_pub.user_id
257 where loan_id = p_loan_id;
258 end if;
259
260 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating the rate schedule ' || p_rate_id);
261 -- 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
262 open c_get_rate_sch_info(p_rate_id);
263 fetch c_get_rate_sch_info into l_begin_inst_num,l_end_inst_num;
264 close c_get_rate_sch_info;
265
266 if (l_begin_inst_num = l_end_inst_num and l_begin_inst_num = p_installment_number) then
267 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);
268
269 -- update existing rate_schedule row
270 update lns_rate_schedules
271 set current_interest_rate = p_annualized_interest_rate
272 ,index_rate = p_annualized_interest_rate - nvl(spread,0)
273 where rate_id = p_rate_id;
274
275 else --else for if (l_begin_inst_num = l_end_inst_num = p_installment_number) then
276 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');
277 update lns_rate_schedules
278 set begin_installment_number = begin_installment_number + 1
279 ,current_interest_rate = spread
280 ,index_rate = null
281 where rate_id = p_rate_id;
282
283 select LNS_RATE_SCHEDULES_S.NEXTVAL into l_new_rate_id
284 from dual;
285
286 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - adding new row into rate schedule');
287 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_rate_id ' || l_new_rate_id );
288 insert into lns_rate_schedules(RATE_ID
289 ,TERM_ID
290 ,INDEX_RATE
291 ,SPREAD
292 ,CURRENT_INTEREST_RATE
293 ,START_DATE_ACTIVE
294 ,END_DATE_ACTIVE
295 ,CREATED_BY
296 ,CREATION_DATE
297 ,LAST_UPDATED_BY
298 ,LAST_UPDATE_DATE
299 ,LAST_UPDATE_LOGIN
300 ,OBJECT_VERSION_NUMBER
301 ,INDEX_DATE
302 ,BEGIN_INSTALLMENT_NUMBER
303 ,END_INSTALLMENT_NUMBER
304 ,INTEREST_ONLY_FLAG
305 ,FLOATING_FLAG
306 ,PHASE)
307 (select
308 l_new_rate_id
309 ,TERM_ID
310 ,p_annualized_interest_rate - nvl(spread,0)
311 ,SPREAD
312 ,p_annualized_interest_rate --make sure you only insert spread overtop of CIR
313 ,START_DATE_ACTIVE
314 ,END_DATE_ACTIVE
315 ,CREATED_BY
316 ,sysdate
317 ,LAST_UPDATED_BY
318 ,sysdate
319 ,LAST_UPDATE_LOGIN
320 ,1
321 ,INDEX_DATE
322 ,p_installment_number
323 ,p_installment_number
324 ,INTEREST_ONLY_FLAG
325 ,FLOATING_FLAG
326 ,PHASE
327 from lns_rate_schedules
328 where rate_id = p_rate_id);
329
330 -- assign new rate id for OUT parameter
331 p_rate_id := l_new_rate_id ;
332
333 end if; --end else part for if (l_begin_inst_num = l_end_inst_num = p_installment_number) then
334
335 else --else for if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
336
337 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating the rate schedule LAST ROW ' || p_rate_id);
338 -- update existing rate_schedule row
339 update lns_rate_schedules
340 set current_interest_rate = p_annualized_interest_rate
341 ,index_rate = p_annualized_interest_rate - nvl(spread,0)
342 where rate_id = p_rate_id;
343
344 end if; --end if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
345
346
347 --
348 -- End of API body
349 --
350 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
351 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
352
353 EXCEPTION
354 WHEN FND_API.G_EXC_ERROR THEN
355 ROLLBACK TO floatingPostProcessor;
356 x_return_status := FND_API.G_RET_STS_ERROR;
357 x_msg_count := l_msg_count;
358 x_msg_data := l_msg_data;
359 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
360 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
361
362 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
363 ROLLBACK TO floatingPostProcessor;
364 x_return_status := FND_API.G_RET_STS_ERROR;
365 x_msg_count := l_msg_count;
366 x_msg_data := l_msg_data;
367 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
368 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
369
370 WHEN OTHERS THEN
371 ROLLBACK TO floatingPostProcessor;
372 x_return_status := FND_API.G_RET_STS_ERROR;
373 x_msg_count := l_msg_count;
374 x_msg_data := l_msg_data;
375 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
376 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
377
378 end floatingRatePostProcessing;
379
380 --------------------------------------------
381 -- validation routines
382 --------------------------------------------
383
384 /*=========================================================================
385 || PUBLIC PROCEDURE validateLoan
386 ||
387 || DESCRIPTION
388 ||
389 || Overview: cover rountine to validate the loan
390 ||
391 || Parameter: loan_id
392 ||
393 || Return value:
394 ||
395 || Source Tables: NA
396 ||
397 || Target Tables:
398 ||
399 || KNOWN ISSUES
400 ||
401 || NOTES
402 ||
403 || MODIFICATION HISTORY
404 || Date Author Description of Changes
405 || 12/08/2003 11:35AM raverma Created
406 ||
407 *=======================================================================*/
408 procedure validateLoan(p_api_version IN NUMBER
409 ,p_init_msg_list IN VARCHAR2
410 ,p_loan_ID IN NUMBER
411 ,x_return_status OUT NOCOPY VARCHAR2
412 ,x_msg_count OUT NOCOPY NUMBER
413 ,x_msg_data OUT NOCOPY VARCHAR2)
414 is
415 l_api_name varchar2(25);
416 l_api_version_number number;
417 l_return_status VARCHAR2(1);
418 l_msg_count NUMBER;
419 l_msg_data VARCHAR2(32767);
420
421 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
422 l_amount number;
423 l_status varchar2(30);
424
425 CURSOR c_terms(p_Loan_id NUMBER) IS
426 SELECT TERM_ID
427 FROM LNS_TERMS
428 WHERE LOAN_ID = p_Loan_id;
429
430 BEGIN
431
432 l_api_name := 'validateLoan';
433 l_api_version_number := 1;
434 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
435
436 -- Standard Start of API savepoint
437 SAVEPOINT validateLoan;
438
439 -- Standard call to check for call compatibility.
440 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
441 l_api_name, G_PKG_NAME)
442 THEN
443 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
444 END IF;
445
446 -- Initialize message list IF p_init_msg_list is set to TRUE.
447 IF FND_API.to_Boolean(p_init_msg_list) THEN
448 FND_MSG_PUB.initialize;
449 END IF;
450
451 -- Initialize API return status to SUCCESS
452 x_return_status := FND_API.G_RET_STS_SUCCESS;
453
454 --
455 -- Api body
456 -- ----------------------------------------------------------------
457 -- there should be one active row in the terms
458 -- ----------------------------------------------------------------
459 Begin
460 OPEN c_terms(p_loan_id);
461 CLOSE c_terms;
462
463 Exception
464 When No_Data_Found then
465 CLOSE c_terms;
466 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_TERMS');
467 FND_MSG_PUB.Add;
468 RAISE FND_API.G_EXC_ERROR;
469 end;
470
471 -- rate schedules should have one row
472 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
473
474 if l_rate_tbl.count = 0 then
475 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_RATE_SCHEDULE');
476 FND_MSG_PUB.Add;
477 RAISE FND_API.G_EXC_ERROR;
478 end if;
479
480 Begin
481 l_amount := lns_financials.getRemainingBalance(p_loan_id);
482 if l_amount <= 0 then
483 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_AMOUNT');
484 FND_MSG_PUB.Add;
485 RAISE FND_API.G_EXC_ERROR;
486 end if;
487
488 end;
489
490 --
491 -- End of API body
492 --
493
494 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
495
496 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
497
498 EXCEPTION
499 WHEN FND_API.G_EXC_ERROR THEN
500 x_return_status := FND_API.G_RET_STS_ERROR;
501 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
502
503 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
504 x_return_status := FND_API.G_RET_STS_ERROR;
505 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
506
507 WHEN OTHERS THEN
508 x_return_status := FND_API.G_RET_STS_ERROR;
509 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
510
511 END validateLoan;
512
513 ---------------------------------------------------------------------------
514 --- amortization routines
515 ---------------------------------------------------------------------------
516
517 /*=========================================================================
518 || PUBLIC PROCEDURE runAmortization
519 ||
520 || DESCRIPTION
521 ||
522 || Overview: procedure will run an amortization and store it into a
523 || return an amortization table
524 ||
525 || Parameter: loan_id
526 ||
527 || Source Tables: NA
528 ||
529 || Target Tables: None
530 ||
531 || Return value: x_amort_tbl is table of amortization records
532 ||
533 || KNOWN ISSUES
534 ||
535 || NOTES
536 ||
537 || MODIFICATION HISTORY
538 || Date Author Description of Changes
539 || 11/09/2004 11:35AM raverma Created
540 ||
541 *=======================================================================*/
542 procedure runAmortization(p_api_version IN NUMBER
543 ,p_init_msg_list IN VARCHAR2
544 ,p_commit IN VARCHAR2
545 ,p_loan_ID IN NUMBER
546 ,p_based_on_terms IN VARCHAR2
547 ,x_amort_tbl OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_TBL
548 ,x_return_status OUT NOCOPY VARCHAR2
549 ,x_msg_count OUT NOCOPY NUMBER
550 ,x_msg_data OUT NOCOPY VARCHAR2)
551
552 is
553 l_api_name varchar2(25);
554 l_api_version_number number;
555 l_return_status VARCHAR2(1);
556 l_msg_count NUMBER;
557 l_msg_data VARCHAR2(32767);
558
559 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
560 l_amort_tbl2 LNS_FINANCIALS.AMORTIZATION_TBL;
561 l_total_amortization LNS_FINANCIALS.AMORTIZATION_REC;
562 l_key NUMBER;
563 b_showActual boolean := false;
564 l_last_installment_billed number;
565 l_customized varchar2(1);
566
567 cursor c_customized (p_loan_id number) is
568 SELECT nvl(h.custom_payments_flag, 'N')
569 FROM lns_loan_headers_all h
570 WHERE loan_id = p_loan_id;
571
572 cursor c_customSchedule(p_loan_id number) is
573 select payment_number installment_number
574 ,due_date due_date
575 ,nvl(principal_amount, 0) principal_amount
576 ,nvl(interest_amount, 0) interest_amount
577 ,nvl(other_amount, 0) other_amount
578 ,nvl(installment_begin_balance, 0) begin_balance
579 ,nvl(installment_end_balance, 0) end_balance
580 from lns_custom_paymnt_scheds
581 where loan_id = p_loan_id
582 order by payment_number;
583
584 -- bug # 4258345
585 -- add late fees to
586 cursor c_manual_fees(p_loan_id number, p_installment number) is
587 select sum(nvl(fee_amount,0))
588 from lns_fee_schedules sch,
589 lns_fees fees
590 where sch.active_flag = 'Y'
591 and sch.billed_flag = 'N'
592 and fees.fee_id = sch.fee_id
593 and ((fees.fee_category = 'MANUAL')
594 OR (fees.fee_category = 'EVENT' AND fees.fee_type = 'EVENT_LATE_CHARGE'))
595 and sch.loan_id = p_loan_id
596 and fee_installment = p_installment;
597
598 l_installment_number number;
599 l_due_date date;
600 l_principal_amount number;
601 l_interest_amount number;
602 l_other_amount number;
603 l_fee_amount number;
604 l_begin_balance number;
605 l_end_balance number;
606 l_total number;
607 l_num_records number;
608 i number;
609 m number;
610 l_records_to_copy number;
611 l_num_installments number;
612 l_num_rows number;
613 l_manual_fee_amount number;
614 l_records_to_destroy number;
615 l_start_date number;
616 l_funded_amount number;
617 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
618 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
619
620 l_last_payment number;
621
622 -- for fees
623 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
624 l_memo_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
625 l_orig_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
626 l_memo_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
627 l_orig_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
628 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
629 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
630
631 l_custom_tbl LNS_CUSTOM_PUB.CUSTOM_TBL;
632 l_AMORT_METHOD varchar2(30);
633
634 -- get the sum of fees for a given loan for a given installment
635 cursor c_fees(p_loan_id number, p_installment number) is
636 select nvl(sum(sched.fee_amount), 0)
637 from lns_fee_schedules sched
638 ,lns_fees struct
639 where sched.loan_id = p_loan_id
640 and sched.fee_id = struct.fee_id
641 and struct.fee_type = 'EVENT_ORIGINATION'
642 and fee_installment = p_installment
643 and active_flag = 'Y';
644
645 BEGIN
646 -- Standard Start of API savepoint
647 SAVEPOINT runAmortization_PVT;
648 l_api_name := 'runAmortization';
649 l_api_version_number := 1;
650 i := 0;
651 l_manual_fee_amount := 0;
652
653
654 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
655 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_ID ' || p_loan_ID);
656 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_based_on_terms ' || p_based_on_terms);
657
658 -- Standard call to check for call compatibility.
659 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
660 l_api_name, G_PKG_NAME)
661 THEN
662 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
663 END IF;
664
665 -- Initialize message list IF p_init_msg_list is set to TRUE.
666 IF FND_API.to_Boolean( p_init_msg_list ) THEN
667 FND_MSG_PUB.initialize;
668 END IF;
669
670 -- Initialize API return status to SUCCESS
671 x_return_status := FND_API.G_RET_STS_SUCCESS;
672
673 --
674 -- Api body
675 -- ----------------------------------------------------------------
676 -- validate loan_id
677 lns_utility_pub.validate_any_id(p_api_version => 1.0
678 ,p_init_msg_list => p_init_msg_list
679 ,x_msg_count => l_msg_count
680 ,x_msg_data => l_msg_data
681 ,x_return_status => l_return_status
682 ,p_col_id => p_loan_id
683 ,p_col_name => 'LOAN_ID'
684 ,p_table_name => 'LNS_LOAN_HEADERS_ALL');
685
686 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
687 FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
688 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
689 FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
690 FND_MSG_PUB.ADD;
691 RAISE FND_API.G_EXC_ERROR;
692 end if;
693 /*
694 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting customization status');
695
696 open c_customized(p_loan_id);
697 fetch c_customized into l_customized;
698 close c_customized;
699
700 if l_customized = 'N' then
701 */
702
703 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
704 ,p_based_on_terms => p_based_on_terms
705 ,p_phase => 'TERM');
706
707 if (l_loan_details.CUSTOM_SCHEDULE = 'N' or
708 (l_loan_details.CUSTOM_SCHEDULE = 'Y' and l_loan_details.loan_status <> 'INCOMPLETE' and
709 p_based_on_terms <> 'CURRENT' and l_loan_details.ORIG_PAY_CALC_METHOD is not null))
710 then
711
712 -- preProcess will add a re-amortization row if the remaining amount < funded amount
713 -- bug# 5664316
714
715 if p_based_on_terms = 'CURRENT' then
716
717 -- call preProcessInstallment only for current amortization
718 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - preProcess the loan');
719 preProcessInstallment(p_api_version => 1.0
720 ,p_init_msg_list => p_init_msg_list
721 ,p_commit => FND_API.G_FALSE --p_commit
722 ,p_loan_ID => p_loan_id
723 ,p_installment_number => lns_billing_util_pub.last_payment_number(p_loan_id)
724 ,x_amortization_rec => l_amortization_rec
725 ,x_return_status => l_return_status
726 ,x_msg_count => l_msg_count
727 ,x_msg_data => l_msg_data);
728
729 end if;
730
731 -- call amortization API
732 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
733 ,p_based_on_terms => p_based_on_terms
734 ,p_installment_number => null
735 ,x_loan_amort_tbl => l_amort_tbl);
736 else
737
738 -- call LNS_CUSTOM_PUB.loadCustomSchedule for customized loan
739
740 -- we will overlay fee structures on top of schedule
741 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan is customized');
742
743 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting origination fee structures');
744 l_orig_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => p_loan_id
745 ,p_fee_category => 'EVENT'
746 ,p_fee_type => 'EVENT_ORIGINATION'
747 ,p_installment => null
748 ,p_fee_id => null);
749 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig structures count is ' || l_orig_fee_structures.count);
750
751 -- calculate the origination fees for the 0 installment if appropriate
752 if l_orig_fee_structures.count > 0 then
753 open c_fees(p_loan_id, 0);
754 fetch c_fees into l_fee_amount;
755 close c_fees;
756
757 if l_fee_amount > 0 then
758 i := i + 1;
759 l_amort_tbl(i).installment_number := 0;
760 l_amort_tbl(i).due_date := l_loan_details.loan_start_date;
761 l_amort_tbl(i).PERIOD_START_DATE := l_loan_details.loan_start_date;
762 l_amort_tbl(i).PERIOD_END_DATE := l_loan_details.loan_start_date;
763 l_amort_tbl(i).principal_amount := 0;
764 l_amort_tbl(i).interest_amount := 0;
765 l_amort_tbl(i).fee_amount := l_fee_amount;
766 l_amort_tbl(i).other_amount := 0;
767 l_amort_tbl(i).begin_balance := l_loan_details.funded_amount;
768 l_amort_tbl(i).end_balance := l_loan_details.funded_amount;
769 l_amort_tbl(i).interest_cumulative := 0;
770 l_amort_tbl(i).principal_cumulative := 0;
771 l_amort_tbl(i).fees_cumulative := l_fee_amount;
772 l_amort_tbl(i).other_cumulative := 0;
773 l_amort_tbl(i).INTEREST_RATE := 0;
774 l_amort_tbl(i).UNPAID_PRIN := 0;
775 l_amort_tbl(i).UNPAID_INT := 0;
776 l_amort_tbl(i).NORMAL_INT_AMOUNT := 0;
777 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT := 0;
778 l_amort_tbl(i).ADD_INT_INT_AMOUNT := 0;
779 l_amort_tbl(i).PENAL_INT_AMOUNT := 0;
780 -- add the record to the amortization table
781 l_amort_tbl(i).total := l_fee_amount;
782 end if;
783
784 end if;
785
786 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting recurring fee structures');
787 l_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => p_loan_id
788 ,p_fee_category => 'RECUR'
789 ,p_fee_type => null
790 ,p_installment => null
791 ,p_fee_id => null);
792 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': fee structures count is ' || l_fee_structures.count);
793
794 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting memo fee structures');
795 l_memo_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => p_loan_id
796 ,p_fee_category => 'MEMO'
797 ,p_fee_type => null
798 ,p_installment => null
799 ,p_fee_id => null);
800 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': memo fee structures count is ' || l_memo_fee_structures.count);
801
802 -- load custom schedule
803 LNS_CUSTOM_PUB.loadCustomSchedule(
804 P_API_VERSION => 1.0,
805 P_INIT_MSG_LIST => FND_API.G_TRUE,
806 P_COMMIT => FND_API.G_FALSE,
807 P_VALIDATION_LEVEL => FND_API.G_VALID_LEVEL_FULL,
808 P_LOAN_ID => P_LOAN_ID,
809 P_BASED_ON_TERMS => p_based_on_terms,
810 X_AMORT_METHOD => l_AMORT_METHOD,
811 X_CUSTOM_TBL => l_custom_tbl,
812 x_return_status => l_return_status,
813 x_msg_count => l_msg_count,
814 x_msg_data => l_msg_data);
815
816 IF l_return_status <> 'S' THEN
817 RAISE FND_API.G_EXC_ERROR;
818 END IF;
819
820 for p in 1..l_custom_tbl.count loop
821
822 i := i + 1;
823 l_amort_tbl(i).installment_number := l_custom_tbl(p).PAYMENT_NUMBER;
824 l_amort_tbl(i).due_date := l_custom_tbl(p).DUE_DATE;
825 l_amort_tbl(i).PERIOD_START_DATE := l_custom_tbl(p).PERIOD_START_DATE;
826 l_amort_tbl(i).PERIOD_END_DATE := l_custom_tbl(p).PERIOD_END_DATE;
827 l_amort_tbl(i).principal_amount := l_custom_tbl(p).PRINCIPAL_AMOUNT;
828 l_amort_tbl(i).interest_amount := l_custom_tbl(p).INTEREST_AMOUNT;
829 l_amort_tbl(i).begin_balance := l_custom_tbl(p).INSTALLMENT_BEGIN_BALANCE;
830 l_amort_tbl(i).end_balance := l_custom_tbl(p).INSTALLMENT_END_BALANCE;
831 l_amort_tbl(i).UNPAID_PRIN := l_custom_tbl(p).UNPAID_PRIN;
832 l_amort_tbl(i).UNPAID_INT := l_custom_tbl(p).UNPAID_INT;
833 l_amort_tbl(i).INTEREST_RATE := l_custom_tbl(p).INTEREST_RATE;
834 l_amort_tbl(i).NORMAL_INT_AMOUNT := l_custom_tbl(p).NORMAL_INT_AMOUNT;
835 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT := l_custom_tbl(p).ADD_PRIN_INT_AMOUNT;
836 l_amort_tbl(i).ADD_INT_INT_AMOUNT := l_custom_tbl(p).ADD_INT_INT_AMOUNT;
837 l_amort_tbl(i).PENAL_INT_AMOUNT := l_custom_tbl(p).PENAL_INT_AMOUNT;
838 l_other_amount := 0;
839 l_fee_amount := 0;
840
841 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
842 l_fee_basis_tbl(1).fee_basis_amount := l_amort_tbl(i).begin_balance + l_amort_tbl(i).UNPAID_PRIN; --fix for bug 6908366
843 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
844 l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.FUNDED_AMOUNT; --fix for bug 6908366
845
846 l_installment_number := l_amort_tbl(i).installment_number;
847 -- calculate the origination fees
848 if l_installment_number = 1 then
849 if l_orig_fee_structures.count > 0 then
850 lns_fee_engine.calculateFees(p_loan_id => p_loan_id
851 ,p_installment => l_installment_number
852 ,p_fee_basis_tbl => l_fee_basis_tbl
853 ,p_fee_structures => l_orig_fee_structures
854 ,x_fees_tbl => l_orig_fees_tbl
855 ,x_return_status => l_return_status
856 ,x_msg_count => l_msg_count
857 ,x_msg_data => l_msg_data);
858 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated origination fees ' || l_orig_fee_structures.count);
859
860 end if;
861 end if;
862
863 -- calculate the memo fees
864 if l_memo_fee_structures.count > 0 then
865 lns_fee_engine.calculateFees(p_loan_id => p_loan_id
866 ,p_installment => l_installment_number
867 ,p_fee_basis_tbl => l_fee_basis_tbl
868 ,p_fee_structures => l_memo_fee_structures
869 ,x_fees_tbl => l_memo_fees_tbl
870 ,x_return_status => l_return_status
871 ,x_msg_count => l_msg_count
872 ,x_msg_data => l_msg_data);
873 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated memo fees ' || l_memo_fees_tbl.count);
874
875 end if;
876
877 -- calculate the recurring fees
878 if l_fee_structures.count > 0 then
879 lns_fee_engine.calculateFees(p_loan_id => p_loan_id
880 ,p_installment => l_installment_number
881 ,p_fee_basis_tbl => l_fee_basis_tbl
882 ,p_fee_structures => l_fee_structures
883 ,x_fees_tbl => l_fees_tbl
884 ,x_return_status => l_return_status
885 ,x_msg_count => l_msg_count
886 ,x_msg_data => l_msg_data);
887 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated fees ' || l_fees_tbl.count);
888
889 end if;
890
891 for m in 1..l_orig_fees_tbl.count loop
892 l_fee_amount := l_fee_amount + l_orig_fees_tbl(m).FEE_AMOUNT;
893 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
894 end loop;
895
896 for k in 1..l_fees_tbl.count loop
897 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
898 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': recurring calculated fees ' || l_fee_amount);
899 end loop;
900
901 for j in 1..l_memo_fees_tbl.count loop
902 l_other_amount := l_other_amount + l_memo_fees_tbl(j).FEE_AMOUNT;
903 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': other calculated fees ' || l_other_amount);
904 end loop;
905
906 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': total calculated fees ' || l_fee_amount);
907 l_amort_tbl(i).fee_amount := l_fee_amount;
908 l_amort_tbl(i).other_amount := l_other_amount;
909 l_amort_tbl(i).total := l_amort_tbl(i).principal_amount + l_amort_tbl(i).interest_amount + l_amort_tbl(i).fee_amount + l_amort_tbl(i).other_amount;
910 l_orig_fees_tbl.delete;
911 l_memo_fees_tbl.delete;
912 l_fees_tbl.delete;
913
914 END LOOP;
915
916 end if;
917
918 -- delete predicted records based on ORIGINAL amortization
919 if p_based_on_terms = 'CURRENT' then
920
921 l_num_records := l_amort_tbl.count;
922 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - amortization returns # records '|| l_num_records);
923 l_last_installment_billed := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER_EXT(p_loan_id);
924 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - last installment billed '|| l_last_installment_billed);
925
926 -- copy the records not billed to a temp collection
927 m := 0;
928 for i in 1..l_num_records
929 loop
930 if l_amort_tbl(i).installment_number > l_last_installment_billed then
931 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - copying record ' || i);
932 m := m + 1;
933 l_amort_tbl2(m) := l_amort_tbl(i);
934 end if;
935 end loop;
936
937 -- copy back to original table
938 l_amort_tbl.delete;
939 m := 0;
940 for i in 1..l_amort_tbl2.count
941 loop
942 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - re-copying record ' || i);
943 m := m + 1;
944 l_amort_tbl(m) := l_amort_tbl2(i);
945 end loop;
946
947
948 end if;
949
950 -- fix for bug 7207609
951 if l_amort_tbl.count > 0 then
952
953 -- finally get the manual fees for the 1st record and add them to the total "other Amount"
954 -- there has got to be a better way to do this
955 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - late + manual fee amount is '|| l_manual_fee_amount);
956 begin
957 open c_manual_fees(p_loan_id, l_last_installment_billed + 1);
958 fetch c_manual_fees into l_manual_fee_amount;
959 close c_manual_fees;
960 end;
961
962 if l_manual_fee_amount is null then
963 l_manual_fee_amount := 0;
964 end if;
965 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - manual fee amount is '|| l_manual_fee_amount);
966
967 if l_amort_tbl.count > 0 then
968 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': adding fees...');
969 l_amort_tbl(1).fee_amount := l_amort_tbl(1).fee_amount + l_manual_fee_amount;
970 l_amort_tbl(1).total := l_amort_tbl(1).total + l_manual_fee_amount;
971 end if;
972
973 end if;
974
975 x_amort_tbl := l_amort_tbl;
976 --
977 -- End of API body
978 --
979
980 -- Standard check for p_commit
981 IF FND_API.to_Boolean(p_commit) THEN
982 COMMIT WORK;
983 END IF;
984
985 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
986 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
987
988 EXCEPTION
989 WHEN FND_API.G_EXC_ERROR THEN
990 ROLLBACK TO runAmortization_PVT;
991 x_return_status := FND_API.G_RET_STS_ERROR;
992 x_msg_count := l_msg_count;
993 x_msg_data := l_msg_data;
994 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
995 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
996
997 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
998 ROLLBACK TO runAmortization_PVT;
999 x_return_status := FND_API.G_RET_STS_ERROR;
1000 x_msg_count := l_msg_count;
1001 x_msg_data := l_msg_data;
1002 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1003 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1004
1005 WHEN OTHERS THEN
1006 ROLLBACK TO runAmortization_PVT;
1007 x_return_status := FND_API.G_RET_STS_ERROR;
1008 x_msg_count := l_msg_count;
1009 x_msg_data := l_msg_data;
1010 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1011 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1012
1013 END runAmortization;
1014
1015 /*=========================================================================
1016 | PUBLIC PROCEDURE termlyPayment
1017 |
1018 | DESCRIPTION
1019 ||
1020 || Overview: number of periods to pay off a loan according to formula
1021 || periods_to_payoff = [ LN(1-(rate*loanAmount)/(payment*payments_per_period)) /
1022 || LN(1 + rate/payments_per_period)]
1023 ||
1024 || Parameter: p_termly amount = periodic amount to pay
1025 || p_annual_rate = annual interest rate on the loan
1026 || p_loan_amount = amount of the loan
1027 || p_payments_per_year = payments @ termly_amount per year
1028 || p_period_type = 'YEARS', 'QUARTERS', 'MONTHS'
1029 ||
1030 || Source Tables: NA
1031 ||
1032 || Target Tables: NA
1033 ||
1034 || Return value: number of periods to pay off the loan
1035 || if return value = -1 then the loan can never be payed off
1036 || at that termly amount and rate
1037 ||
1038 || KNOWN ISSUES
1039 ||
1040 || NOTES
1041 || NOTE: INSTALLMENT_NUMBER WILL NOT GET YOU THE GIVEN INSTALLMENT
1042 || NUMBER CORRESPONDING ON THE LOAN AMORTIZATION SCHEDULE
1043 ||
1044 || MODIFICATION HISTORY
1045 || Date Author Description of Changes
1046 || 12/11/2003 6:42PM raverma Created
1047 ||
1048 *=======================================================================*/
1049 function termlyPayment(p_termly_amount in number
1050 ,p_annual_rate in number
1051 ,p_loan_amount in number
1052 ,p_payments_per_year in number
1053 ,p_period_type in varchar2) return number
1054 is
1055 l_periodic_rate number;
1056 l_num_periods number;
1057 l_api_name varchar2(15);
1058
1059 begin
1060
1061 l_api_name := 'termlyPayment';
1062 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1063
1064 l_periodic_rate := p_annual_rate / 100;
1065
1066 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate: ' || l_periodic_rate);
1067 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': termly amount: ' || p_termly_amount);
1068 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payments per year: ' || p_payments_per_year);
1069 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan amount : ' || p_loan_amount);
1070
1071 if l_periodic_rate <> 0 then
1072 -- we cannot have LN < 0
1073 -- this will be a loan that will never be paid off
1074 if ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount) >= 1 then
1075 FND_MESSAGE.Set_Name('LNS', 'LNS_NEVER_PAYOFF');
1076 FND_MSG_PUB.Add;
1077 RAISE FND_API.G_EXC_ERROR;
1078 end if;
1079
1080 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate * p_loan_amount :' || l_periodic_rate * p_loan_amount);
1081 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);
1082 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))));
1083 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);
1084 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': LN(1+d) : ' || LN(1 + (l_periodic_rate / p_payments_per_year)));
1085 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': - p_payments_per_year : ' || (- p_payments_per_year));
1086
1087 l_num_periods := (LN(1 - ( ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount))) /
1088 LN(1 + (l_periodic_rate / p_payments_per_year))) / (- p_payments_per_year) ;
1089 else
1090 l_num_periods := p_loan_amount / p_termly_amount / p_payments_per_year;
1091
1092 end if;
1093
1094 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': num years to pay off = ' || l_num_periods);
1095
1096 if p_period_type = 'MONTHS' then
1097 l_num_periods := l_num_periods * 12;
1098
1099 elsif p_period_type = 'QUARTERS' then
1100 l_num_periods := l_num_periods * 4;
1101
1102 elsif p_period_type = 'YEARS' then
1103 null;
1104
1105 end if;
1106
1107 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1108
1109 return l_num_periods;
1110
1111 Exception
1112
1113 When FND_API.G_EXC_ERROR then
1114 return -1;
1115
1116 When others then
1117 return -1;
1118
1119 end termlyPayment;
1120
1121 /*=========================================================================
1122 || PUBLIC PROCEDURE preProcessInstallment
1123 ||
1124 || DESCRIPTION
1125 ||
1126 || Overview: this procedure will recalculate an installment for reamortization
1127 ||
1128 || PSEUDO CODE/LOGIC
1129 ||
1130 || PARAMETERS
1131 ||
1132 || Parameter: p_loan_id => in loanID
1133 || p_installment_number = FLAG to notify to get the
1134 || latest installment
1135 ||
1136 || Return value: AMORTIZATION_REC => contains billing and payment information
1137 ||
1138 || Source Tables: NA
1139 ||
1140 || Target Tables: NA
1141 ||
1142 || KNOWN ISSUES
1143 ||
1144 || NOTES
1145 || NOTE: api used by Billing Engine
1146 ||
1147 || MODIFICATION HISTORY
1148 || Date Author Description of Changes
1149 || 03/12/2004 12:40PM raverma Created
1150 ||
1151 *=======================================================================*/
1152 procedure preProcessInstallment(p_api_version IN NUMBER
1153 ,p_init_msg_list IN VARCHAR2
1154 ,p_commit IN VARCHAR2
1155 ,p_loan_ID IN NUMBER
1156 ,p_installment_number IN NUMBER
1157 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1158 ,x_return_status OUT NOCOPY VARCHAR2
1159 ,x_msg_count OUT NOCOPY NUMBER
1160 ,x_msg_data OUT NOCOPY VARCHAR2)
1161 is
1162 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
1163 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
1164 l_count NUMBER;
1165 l_api_name varchar2(40);
1166 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
1167
1168 l_theoretical_balance NUMBER;
1169 l_actual_balance NUMBER;
1170 l_api_version_number number;
1171 l_return_status VARCHAR2(1);
1172 l_msg_count NUMBER;
1173 l_msg_data VARCHAR2(32767);
1174 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL; -- define what event(s) we are processing fees for
1175 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
1176 l_overdue_amount number;
1177 i number;
1178 l_due_date date;
1179 l_installment number;
1180 l_arr_pos number;
1181
1182 -- this is for get custom dates
1183 cursor c_customized (p_loan_id number) is
1184 SELECT nvl(h.custom_payments_flag, 'N')
1185 FROM lns_loan_headers_all h
1186 WHERE loan_id = p_loan_id;
1187
1188 cursor c_customSchedule(p_loan_id number, p_installment number) is
1189 select payment_number installment_number
1190 ,due_date due_date
1191 from lns_custom_paymnt_scheds
1192 where loan_id = p_loan_id
1193 and payment_number = p_installment;
1194
1195 begin
1196
1197 l_api_name := 'preProcessInstallment';
1198 l_api_version_number := 1;
1199
1200 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1201 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1202 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1203
1204 -- Standard Start of API savepoint
1205 SAVEPOINT preProcessInstallment;
1206
1207 -- Standard call to check for call compatibility.
1208 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
1209 l_api_name, G_PKG_NAME)
1210 THEN
1211 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1212 END IF;
1213
1214 -- Initialize message list IF p_init_msg_list is set to TRUE.
1215 IF FND_API.to_Boolean(p_init_msg_list) THEN
1216 FND_MSG_PUB.initialize;
1217 END IF;
1218 -- Initialize API return status to SUCCESS
1219 x_return_status := FND_API.G_RET_STS_SUCCESS;
1220
1221 -- Api body
1222 -- get the loan details
1223 -- compare the actual balance to the theoretical balance
1224 -- if they are inconsistent and reamorization flag is set
1225 -- then insert reamortization information into LNS_AMORTIZATION_SCHEDS
1226 /*
1227 if p_installment_number = 0 then
1228 i := p_installment_number + 1;
1229 else
1230 i := p_installment_number;
1231 end if;
1232 */
1233 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
1234 ,p_based_on_terms => 'CURRENT'
1235 ,p_phase => 'TERM');
1236
1237 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting next installment info...');
1238 if l_loan_details.custom_schedule = 'N' then
1239 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - regular loan');
1240
1241 -- this is a standard non-customized loan
1242 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
1243 ,p_based_on_terms => 'CURRENT'
1244 ,p_installment_number => p_installment_number
1245 ,x_loan_amort_tbl => l_amort_tbl);
1246 l_count := l_amort_tbl.count;
1247 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' table count is ' || l_count);
1248
1249 for i in REVERSE 1..l_amort_tbl.count loop
1250 if p_installment_number = l_amort_tbl(i).INSTALLMENT_NUMBER then
1251 l_due_date := l_amort_tbl(i).due_date;
1252 l_installment := l_amort_tbl(i).installment_number;
1253 exit;
1254 end if;
1255 end loop;
1256
1257 else
1258 -- we are on a customized loan
1259 -- check if this is 0th installment or not
1260 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - custom loan');
1261 if p_installment_number > 0 then
1262 open c_customSchedule(p_loan_id, p_installment_number);
1263 fetch c_customSchedule into
1264 l_installment
1265 ,l_due_date;
1266 close c_customSchedule;
1267 else
1268 -- we are on 0th installment
1269 l_installment := p_installment_number;
1270 l_due_date := l_loan_details.loan_start_date;
1271 end if;
1272 end if;
1273
1274 -- assign to output record
1275 l_amortization_rec.installment_number := l_installment;
1276 l_amortization_rec.due_date := l_due_date;
1277 --l_amortization_rec.principal_amount := l_amort_tbl(i).principal_amount;
1278 --l_amortization_rec.interest_amount := l_amort_tbl(i).interest_amount;
1279 --l_amortization_rec.fee_amount := l_amort_tbl(i).fee_amount;
1280 --l_amortization_rec.other_amount := l_amort_tbl(i).other_amount;
1281 --l_amortization_rec.total := l_amort_tbl(i).total;
1282 --l_amortization_rec.begin_balance := l_amort_tbl(i).begin_balance;
1283 --l_amortization_rec.end_balance := l_amort_tbl(i).end_balance;
1284 --l_amortization_rec.principal_cumulative := l_amort_tbl(i).principal_cumulative;
1285 --l_amortization_rec.interest_cumulative := l_amort_tbl(i).interest_cumulative;
1286 --l_amortization_rec.fees_cumulative := l_amort_tbl(i).fees_cumulative;
1287 --l_amortization_rec.other_cumulative := l_amort_tbl(i).other_cumulative;
1288 --l_amortization_rec.rate_id := l_amort_tbl(i).rate_id;
1289
1290 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' next installment due: ' || l_amortization_rec.installment_number);
1291 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' next due date: ' || l_amortization_rec.due_date);
1292
1293 -- get theoretical balance
1294 -- bug# 5664316 - remove installment number check
1295 if l_loan_details.reamortize_overpay = 'Y' and
1296 l_loan_details.custom_schedule = 'N' -- fix for bug 6902221
1297 then --and p_installment_number > 1 then
1298
1299 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - checking if we need to reamortize...');
1300
1301 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
1302 ,p_based_on_terms => 'ORIGINAL'
1303 ,p_installment_number => p_installment_number
1304 ,x_loan_amort_tbl => l_amort_tbl);
1305
1306 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' comparing balances...');
1307 l_actual_balance := l_loan_details.remaining_balance;
1308
1309 if p_installment_number > 0 then
1310
1311 -- l_arr_pos is array index
1312 l_arr_pos := p_installment_number;
1313
1314 -- will get inside if only if there is origination fee
1315 if l_amort_tbl(1).INSTALLMENT_NUMBER = 0 then
1316 l_arr_pos := p_installment_number + 1;
1317 end if;
1318
1319 if l_amort_tbl.count < l_arr_pos then
1320 l_theoretical_balance := 0;
1321 else
1322 l_theoretical_balance := l_amort_tbl(l_arr_pos).end_balance;
1323 end if;
1324 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' p_installment_number ' || p_installment_number);
1325 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' l_arr_pos ' || l_arr_pos);
1326
1327 elsif p_installment_number = 0 then
1328 -- this check will take care of multiple reAmortizations on 0th installment
1329 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize zero installment');
1330 if l_loan_details.reamortize_amount = 0 or l_loan_details.reamortize_amount is null then
1331
1332 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize amount is zero - no previous reamortization ');
1333 l_theoretical_balance := l_loan_details.funded_amount;
1334 else
1335
1336 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize amount is not zero - previous reamort amount');
1337 l_theoretical_balance := l_loan_details.reamortize_amount;
1338 end if;
1339 end if;
1340
1341 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' actual balance ' || l_actual_balance);
1342 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' theoretical balance ' || l_theoretical_balance);
1343 -- end bug# 5664316 11-23-2006
1344
1345 if l_actual_balance < l_theoretical_balance then
1346
1347 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZING...');
1348
1349 -- remove all reAmortize rows from amortization schedule
1350 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' removing previous reAmortize rows');
1351
1352 delete
1353 from lns_amortization_scheds
1354 where loan_id = p_loan_id
1355 and reamortization_amount is not null
1356 and reamortize_from_installment is not null;
1357
1358 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZE OVERPAY LOAN');
1359 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' insert record into amortizations');
1360 insert into LNS_AMORTIZATION_SCHEDS(amortization_schedule_id
1361 ,loan_id
1362 ,reamortization_amount
1363 ,reamortize_from_installment
1364 ,reamortize_to_installment
1365 ,created_by
1366 ,creation_date
1367 ,last_updated_by
1368 ,last_update_date
1369 ,object_version_number)
1370 values
1371 (LNS_AMORTIZATION_SCHEDS_S.NEXTVAL
1372 ,p_loan_id
1373 ,l_actual_balance
1374 ,p_installment_number
1375 ,null
1376 ,lns_utility_pub.created_by
1377 ,lns_utility_pub.creation_date
1378 ,lns_utility_pub.last_updated_by
1379 ,lns_utility_pub.last_update_date
1380 ,1);
1381 -- bug #3718480
1382 -- we will need to credit out all unpaid principal documents
1383 /*
1384 elsif l_loan_details.reamortize_underpay = 'Y' and l_actual_balance > l_theoretical_balance then
1385 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZE UNDERPAY LOAN');
1386 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' insert record into amortizations');
1387 insert into LNS_AMORTIZATION_SCHEDS(amortization_schedule_id
1388 ,loan_id
1389 ,reamortization_amount
1390 ,reamortize_from_installment
1391 ,reamortize_to_installment
1392 ,created_by
1393 ,creation_date
1394 ,last_updated_by
1395 ,last_update_date
1396 ,object_version_number)
1397 values
1398 (LNS_AMORTIZATION_SCHEDS_S.NEXTVAL
1399 ,p_loan_id
1400 ,l_actual_balance
1401 ,p_installment_number
1402 ,null
1403 ,lns_utility_pub.created_by
1404 ,lns_utility_pub.creation_date
1405 ,lns_utility_pub.last_updated_by
1406 ,lns_utility_pub.last_update_date
1407 ,1);
1408 */
1409 else
1410 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' WILL NOT REAMORTIZE!');
1411 end if;
1412 end if;
1413
1414 -- processFees for servicing
1415 x_amortization_rec := l_amortization_rec;
1416
1417 --
1418 -- End of API body
1419 -- ---------------------------------------------------------------
1420
1421 -- Standard check for p_commit
1422 IF FND_API.to_Boolean(p_commit) THEN
1423 COMMIT WORK;
1424 END IF;
1425
1426 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1427 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1428
1429 Exception
1430 WHEN FND_API.G_EXC_ERROR THEN
1431 ROLLBACK TO preProcessInstallment;
1432 x_return_status := FND_API.G_RET_STS_ERROR;
1433 x_msg_count := l_msg_count;
1434 x_msg_data := l_msg_data;
1435 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1436 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1437
1438 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1439 ROLLBACK TO preProcessInstallment;
1440 x_return_status := FND_API.G_RET_STS_ERROR;
1441 x_msg_count := l_msg_count;
1442 x_msg_data := l_msg_data;
1443 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1444 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
1445
1446 WHEN OTHERS THEN
1447 ROLLBACK TO preProcessInstallment;
1448 x_return_status := FND_API.G_RET_STS_ERROR;
1449 x_msg_count := l_msg_count;
1450 x_msg_data := l_msg_data;
1451 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1452 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1453
1454 end preProcessInstallment;
1455
1456 /*=========================================================================
1457 || PUBLIC PROCEDURE preProcessOpenInstallment
1458 ||
1459 || DESCRIPTION
1460 ||
1461 || Overview: this procedure will preProcess an installment
1462 ||
1463 || PSEUDO CODE/LOGIC
1464 ||
1465 || PARAMETERS
1466 ||
1467 || Parameter: p_loan_id => in loanID
1468 || p_installment_number = FLAG to notify to get the
1469 || latest installment
1470 ||
1471 || Return value: AMORTIZATION_REC => contains billing and payment information
1472 ||
1473 || Source Tables: NA
1474 ||
1475 || Target Tables: NA
1476 ||
1477 || KNOWN ISSUES
1478 ||
1479 || NOTES
1480 || NOTE: api used by Billing Engine
1481 ||
1482 || MODIFICATION HISTORY
1483 || Date Author Description of Changes
1484 || 03/12/2004 12:40PM raverma Created
1485 ||
1486 *=======================================================================*/
1487 procedure preProcessOpenInstallment(p_init_msg_list IN VARCHAR2
1488 ,p_commit IN VARCHAR2
1489 ,p_loan_ID IN NUMBER
1490 ,p_installment_number IN NUMBER
1491 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1492 ,x_return_status OUT NOCOPY VARCHAR2
1493 ,x_msg_count OUT NOCOPY NUMBER
1494 ,x_msg_data OUT NOCOPY VARCHAR2)
1495 is
1496 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
1497 l_count NUMBER;
1498 l_api_name varchar2(40);
1499 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
1500
1501 l_return_status VARCHAR2(1);
1502 l_msg_count NUMBER;
1503 l_msg_data VARCHAR2(32767);
1504 l_fees_tbl LNS_FINANCIALS.FEES_TBL;
1505 i number;
1506 l_installment number;
1507
1508 begin
1509
1510 l_api_name := 'preProcessOpenInstallment';
1511 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1512 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1513 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1514
1515 -- Standard Start of API savepoint
1516 SAVEPOINT preProcessOpenInstallment;
1517
1518 -- Initialize message list IF p_init_msg_list is set to TRUE.
1519 IF FND_API.to_Boolean(p_init_msg_list) THEN
1520 FND_MSG_PUB.initialize;
1521 END IF;
1522
1523 -- Initialize API return status to SUCCESS
1524 x_return_status := FND_API.G_RET_STS_SUCCESS;
1525
1526 -- ---------------------------------------------------------------
1527 -- Beginning of API body
1528 --
1529 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting loan details');
1530 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
1531 ,p_based_on_terms => 'CURRENT'
1532 ,p_phase => 'OPEN');
1533
1534 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting Open Installment');
1535 lns_financials.getOpenInstallment(p_init_msg_list => 'T'
1536 ,p_loan_ID => p_loan_ID
1537 ,p_installment_number => p_installment_number
1538 ,x_fees_tbl => l_fees_tbl
1539 ,x_amortization_rec => l_amortization_rec
1540 ,x_return_status => l_return_Status
1541 ,x_msg_count => l_msg_count
1542 ,x_msg_data => l_msg_data);
1543
1544 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1545 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1546 FND_MSG_PUB.ADD;
1547 RAISE FND_API.G_EXC_ERROR;
1548 end if;
1549
1550 -- processFees for servicing
1551 x_amortization_rec := l_amortization_rec;
1552
1553 --
1554 -- End of API body
1555 -- ---------------------------------------------------------------
1556
1557 -- Standard check for p_commit
1558 IF FND_API.to_Boolean(p_commit) THEN
1559 COMMIT WORK;
1560 END IF;
1561
1562 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1563 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1564
1565 Exception
1566 WHEN FND_API.G_EXC_ERROR THEN
1567 ROLLBACK TO preProcessOpenInstallment;
1568 x_return_status := FND_API.G_RET_STS_ERROR;
1569 x_msg_count := l_msg_count;
1570 x_msg_data := l_msg_data;
1571 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1572 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1573
1574 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1575 ROLLBACK TO preProcessOpenInstallment;
1576 x_return_status := FND_API.G_RET_STS_ERROR;
1577 x_msg_count := l_msg_count;
1578 x_msg_data := l_msg_data;
1579 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1580 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
1581
1582 WHEN OTHERS THEN
1583 ROLLBACK TO preProcessOpenInstallment;
1584 x_return_status := FND_API.G_RET_STS_ERROR;
1585 x_msg_count := l_msg_count;
1586 x_msg_data := l_msg_data;
1587 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1588 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1589
1590 end preProcessOpenInstallment;
1591
1592
1593 /*=========================================================================
1594 || PUBLIC PROCEDURE getInstallment
1595 ||
1596 || DESCRIPTION
1597 ||
1598 || Overview: returns interest and principal for a single installment
1599 || this is used for the billing concurrent program
1600 ||
1601 || PSEUDO CODE/LOGIC
1602 ||
1603 || PARAMETERS
1604 ||
1605 || Parameter: p_loan_id => in loanID
1606 || p_installment_number = FLAG to notify to get the
1607 || latest installment
1608 ||
1609 || Return value: AMORTIZATION_REC => contains billing and payment information
1610 ||
1611 || Source Tables: NA
1612 ||
1613 || Target Tables: NA
1614 ||
1615 || KNOWN ISSUES
1616 ||
1617 || NOTES
1618 || NOTE: api used by Billing Engine
1619 ||
1620 || MODIFICATION HISTORY
1621 || Date Author Description of Changes
1622 || 12/11/2003 12:40PM raverma Created
1623 ||
1624 *=======================================================================*/
1625 procedure getInstallment(p_api_version IN NUMBER
1626 ,p_init_msg_list IN VARCHAR2
1627 ,p_commit IN VARCHAR2
1628 ,p_loan_Id in number
1629 ,p_installment_number in number
1630 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1631 ,x_fees_tbl OUT NOCOPY LNS_FINANCIALS.FEES_TBL
1632 ,x_return_status OUT NOCOPY VARCHAR2
1633 ,x_msg_count OUT NOCOPY NUMBER
1634 ,x_msg_data OUT NOCOPY VARCHAR2)
1635 is
1636 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
1637 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
1638 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
1639 l_count NUMBER;
1640 l_api_version_number number;
1641 l_return_status VARCHAR2(1);
1642 l_msg_count NUMBER;
1643 l_msg_data VARCHAR2(32767);
1644 l_api_name varchar2(25);
1645 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
1646 l_fees_tbl_1 LNS_FEE_ENGINE.FEE_CALC_TBL;
1647 l_fees_tbl_2 LNS_FINANCIALS.FEES_TBL;
1648 l_total_fees number;
1649 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
1650 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL; -- define what event(s) we are processing fees for
1651 i number;
1652 --l_begin_balance number; -- used for fees calculation
1653 l_customized varchar2(1);
1654 l_loan_start_date date;
1655 l_funded_amount number;
1656 l_custom_tbl LNS_CUSTOM_PUB.CUSTOM_TBL;
1657 l_AMORT_METHOD varchar2(30);
1658
1659 /* query custom amortization */
1660 CURSOR cust_amort_cur(P_LOAN_ID number, P_PAYMENT_NUMBER number) IS
1661 select
1662 cust.DUE_DATE
1663 ,nvl(cust.PRINCIPAL_AMOUNT, 0)
1664 ,nvl(cust.INTEREST_AMOUNT, 0)
1665 ,cust.installment_begin_balance
1666 ,cust.installment_end_balance
1667 --cust.FEE_AMOUNT
1668 from LNS_CUSTOM_PAYMNT_SCHEDS cust
1669 where cust.LOAN_ID = P_LOAN_ID and
1670 cust.PAYMENT_NUMBER = P_PAYMENT_NUMBER;
1671
1672 begin
1673
1674 l_api_version_number := 1;
1675 l_api_name := 'getInstallment';
1676 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1677 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1678 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1679
1680 -- Standard Start of API savepoint
1681 SAVEPOINT getInstallment;
1682
1683 -- Standard call to check for call compatibility.
1684 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
1685 l_api_name, G_PKG_NAME)
1686 THEN
1687 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1688 END IF;
1689
1690 -- Initialize message list IF p_init_msg_list is set to TRUE.
1691 IF FND_API.to_Boolean(p_init_msg_list) THEN
1692 FND_MSG_PUB.initialize;
1693 END IF;
1694
1695 -- Initialize API return status to SUCCESS
1696 x_return_status := FND_API.G_RET_STS_SUCCESS;
1697
1698 -- --------------------------------------------------------------------
1699 -- Api body
1700 -- --------------------------------------------------------------------
1701 l_total_fees := 0;
1702 l_amortization_rec.principal_amount := 0;
1703 l_amortization_rec.interest_amount := 0;
1704 l_amortization_rec.total := 0;
1705 l_amortization_rec.fee_amount := 0;
1706 l_amortization_rec.other_amount := 0;
1707 l_amortization_rec.begin_balance := 0;
1708 l_amortization_rec.end_balance := 0;
1709
1710 -- move logic for billing custom loans into FINANCIALS API
1711 l_loan_Details := lns_financials.getLoanDetails(p_loan_id, 'CURRENT', 'TERM');
1712
1713 if l_loan_details.custom_schedule = 'N' then
1714
1715 -- preProcess will add a re-amortization row if the remaining amount < funded amount
1716 -- bug# 5664316 11-23-2006
1717 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - preProcess the loan');
1718 preProcessInstallment(p_api_version => 1.0
1719 ,p_init_msg_list => p_init_msg_list
1720 ,p_commit => p_commit
1721 ,p_loan_ID => p_loan_id
1722 ,p_installment_number => lns_billing_util_pub.last_payment_number(p_loan_id)
1723 ,x_amortization_rec => l_amortization_rec
1724 ,x_return_status => l_return_status
1725 ,x_msg_count => l_msg_count
1726 ,x_msg_data => l_msg_data);
1727
1728 lns_financials.amortizeLoan(p_loan_Id => p_loan_id
1729 ,p_installment_number => p_installment_number
1730 ,p_based_on_terms => 'CURRENT'
1731 ,x_loan_amort_tbl => l_amortization_tbl);
1732 if p_installment_number = 0 then
1733 i := p_installment_number + 1;
1734 else
1735 i := l_amortization_tbl.count;
1736 end if;
1737
1738 l_amortization_rec := l_amortization_tbl(i);
1739 /*
1740 l_amortization_rec.installment_number := l_amortization_tbl(i).installment_number;
1741 l_amortization_rec.due_date := l_amortization_tbl(i).due_date;
1742 l_amortization_rec.principal_amount := l_amortization_tbl(i).principal_amount;
1743 l_amortization_rec.interest_amount := l_amortization_tbl(i).interest_amount;
1744 l_amortization_rec.total := l_amortization_tbl(i).total;
1745 l_amortization_rec.fee_amount := l_amortization_tbl(i).fee_amount;
1746 l_amortization_rec.other_amount := l_amortization_tbl(i).other_amount;
1747 l_amortization_rec.begin_balance := l_amortization_tbl(i).begin_balance;
1748 l_amortization_rec.end_balance := l_amortization_tbl(i).end_balance;
1749 l_amortization_rec.interest_cumulative := l_amortization_tbl(i).interest_cumulative;
1750 l_amortization_rec.principal_cumulative := l_amortization_tbl(i).principal_cumulative;
1751 l_amortization_rec.other_cumulative := l_amortization_tbl(i).other_cumulative;
1752 l_amortization_rec.rate_id := l_amortization_tbl(i).rate_id;
1753 l_amortization_rec.rate_unadj := l_amortization_tbl(i).rate_unadj;
1754 l_amortization_rec.RATE_CHANGE_FREQ := l_amortization_tbl(i).RATE_CHANGE_FREQ;
1755 */
1756 else -- this is a customized loan
1757
1758 if p_installment_number > 0 then
1759 /*
1760 open cust_amort_cur(p_loan_id, p_installment_number);
1761 fetch cust_amort_cur into
1762 l_amortization_rec.due_date
1763 ,l_amortization_rec.principal_amount
1764 ,l_amortization_rec.interest_amount
1765 ,l_amortization_rec.begin_balance
1766 ,l_amortization_rec.end_balance;
1767
1768 close cust_amort_cur;
1769 */
1770 -- load custom schedule
1771 LNS_CUSTOM_PUB.loadCustomSchedule(
1772 P_API_VERSION => 1.0,
1773 P_INIT_MSG_LIST => FND_API.G_TRUE,
1774 P_COMMIT => FND_API.G_FALSE,
1775 P_VALIDATION_LEVEL => FND_API.G_VALID_LEVEL_FULL,
1776 P_LOAN_ID => p_loan_id,
1777 P_BASED_ON_TERMS => 'CURRENT',
1778 X_AMORT_METHOD => l_AMORT_METHOD,
1779 X_CUSTOM_TBL => l_custom_tbl,
1780 x_return_status => l_return_status,
1781 x_msg_count => l_msg_count,
1782 x_msg_data => l_msg_data);
1783
1784 IF l_return_status <> 'S' THEN
1785 RAISE FND_API.G_EXC_ERROR;
1786 END IF;
1787
1788 for p in 1..l_custom_tbl.count loop
1789
1790 if l_custom_tbl(p).PAYMENT_NUMBER = p_installment_number then
1791 l_amortization_rec.installment_number := l_custom_tbl(p).PAYMENT_NUMBER;
1792 l_amortization_rec.due_date := l_custom_tbl(p).DUE_DATE;
1793 l_amortization_rec.PERIOD_START_DATE := l_custom_tbl(p).PERIOD_START_DATE;
1794 l_amortization_rec.PERIOD_END_DATE := l_custom_tbl(p).PERIOD_END_DATE;
1795 l_amortization_rec.principal_amount := l_custom_tbl(p).PRINCIPAL_AMOUNT;
1796 l_amortization_rec.interest_amount := l_custom_tbl(p).INTEREST_AMOUNT;
1797 l_amortization_rec.begin_balance := l_custom_tbl(p).INSTALLMENT_BEGIN_BALANCE;
1798 l_amortization_rec.end_balance := l_custom_tbl(p).INSTALLMENT_END_BALANCE;
1799 l_amortization_rec.UNPAID_PRIN := l_custom_tbl(p).UNPAID_PRIN;
1800 l_amortization_rec.UNPAID_INT := l_custom_tbl(p).UNPAID_INT;
1801 l_amortization_rec.INTEREST_RATE := l_custom_tbl(p).INTEREST_RATE;
1802 l_amortization_rec.NORMAL_INT_AMOUNT := l_custom_tbl(p).NORMAL_INT_AMOUNT;
1803 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_custom_tbl(p).ADD_PRIN_INT_AMOUNT;
1804 l_amortization_rec.ADD_INT_INT_AMOUNT := l_custom_tbl(p).ADD_INT_INT_AMOUNT;
1805 l_amortization_rec.PENAL_INT_AMOUNT := l_custom_tbl(p).PENAL_INT_AMOUNT;
1806 exit;
1807 end if;
1808 end loop;
1809 else
1810 l_amortization_rec.begin_balance := l_loan_details.funded_amount;
1811 l_amortization_rec.due_date := l_loan_details.loan_start_date;
1812 l_amortization_rec.installment_number := p_installment_number;
1813 end if;
1814 end if;
1815
1816 -- bug # 3839974
1817 if l_amortization_rec.principal_amount > l_loan_details.unbilled_principal then
1818 l_amortization_rec.principal_amount := l_loan_details.unbilled_principal;
1819 l_amortization_rec.principal_cumulative := l_amortization_rec.principal_cumulative - l_amortization_rec.principal_amount + l_loan_details.unbilled_principal;
1820 end if;
1821
1822 if p_installment_number > 0 then
1823 -- add the recurring fees for the installment onto the fee schedule
1824
1825 l_fee_structures(1).fee_category := 'RECUR';
1826 l_fee_structures(1).fee_type := null;
1827
1828 -- only 2 types of fee basis are valid for RECURRING FEE
1829 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
1830 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
1831 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
1832 l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.FUNDED_AMOUNT;
1833 l_fee_basis_tbl(3).fee_basis_name := 'OVERDUE_PRIN';
1834 -- l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.principal_amount;
1835 l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
1836 l_fee_basis_tbl(4).fee_basis_name := 'OVERDUE_PRIN_INT';
1837 -- l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
1838 l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
1839
1840 lns_fee_engine.processFees(p_init_msg_list => FND_API.G_FALSE
1841 ,p_commit => FND_API.G_FALSE
1842 ,p_loan_id => p_loan_id
1843 ,p_installment_number => p_installment_number
1844 ,p_fee_basis_tbl => l_fee_basis_tbl
1845 ,p_fee_structures => l_fee_structures
1846 ,x_fees_tbl => l_fees_tbl
1847 ,x_return_status => l_return_Status
1848 ,x_msg_count => l_msg_count
1849 ,x_msg_data => l_msg_data);
1850
1851 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1852 FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1853 FND_MSG_PUB.ADD;
1854 RAISE FND_API.G_EXC_ERROR;
1855 end if;
1856 end if;
1857
1858 -- 12-21-2004 raverma added for lns.b
1859 -- only get the dis
1860 lns_fee_engine.getFeeSchedule(p_init_msg_list => FND_API.G_FALSE
1861 ,p_loan_id => p_loan_id
1862 ,p_installment_number => p_installment_number
1863 ,p_disb_header_id => null
1864 ,x_fees_tbl => l_fees_tbl_1
1865 ,x_return_status => l_return_status
1866 ,x_msg_count => l_msg_count
1867 ,x_msg_data => l_msg_data);
1868
1869 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1870 FND_MESSAGE.SET_NAME('LNS', 'LNS_READ_FEE_ERROR');
1871 FND_MSG_PUB.ADD;
1872 RAISE FND_API.G_EXC_ERROR;
1873 end if;
1874
1875 for k in 1..l_fees_tbl_1.count loop
1876 l_fees_tbl_2(k).FEE_ID := l_fees_tbl_1(k).FEE_ID;
1877 l_fees_tbl_2(k).FEE_NAME := l_fees_tbl_1(k).FEE_NAME;
1878 l_fees_tbl_2(k).FEE_AMOUNT := l_fees_tbl_1(k).FEE_AMOUNT;
1879 l_fees_tbl_2(k).FEE_INSTALLMENT := l_fees_tbl_1(k).FEE_INSTALLMENT;
1880 l_fees_tbl_2(k).FEE_DESCRIPTION := l_fees_tbl_1(k).FEE_DESCRIPTION;
1881 l_fees_tbl_2(k).FEE_SCHEDULE_ID := l_fees_tbl_1(k).FEE_SCHEDULE_ID;
1882 l_fees_tbl_2(k).FEE_WAIVABLE_FLAG := l_fees_tbl_1(k).FEE_WAIVABLE_FLAG;
1883 l_fees_tbl_2(k).WAIVE_AMOUNT := l_fees_tbl_1(k).WAIVE_AMOUNT;
1884 l_fees_tbl_2(k).BILLED_FLAG := l_fees_tbl_1(k).BILLED_FLAG;
1885 l_fees_tbl_2(k).ACTIVE_FLAG := l_fees_tbl_1(k).ACTIVE_FLAG;
1886 l_total_fees := l_total_fees + l_fees_tbl_1(k).FEE_AMOUNT;
1887 end loop;
1888
1889 -- overwrite amortization record returned from amortizationAPI
1890 l_amortization_rec.fee_amount := l_total_fees;
1891 x_fees_tbl := l_fees_tbl_2;
1892 x_amortization_rec := l_amortization_rec;
1893 -- --------------------------------------------------------------------
1894 -- End of API body
1895 -- --------------------------------------------------------------------
1896
1897 -- Standard check for p_commit
1898 IF FND_API.to_Boolean(p_commit) THEN
1899 COMMIT WORK;
1900 END IF;
1901
1902 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1903 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1904
1905 EXCEPTION
1906 WHEN FND_API.G_EXC_ERROR THEN
1907 ROLLBACK TO getInstallment;
1908 x_return_status := FND_API.G_RET_STS_ERROR;
1909 x_msg_count := l_msg_count;
1910 x_msg_data := l_msg_data;
1911 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1912 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1913
1914 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1915 ROLLBACK TO getInstallment;
1916 x_return_status := FND_API.G_RET_STS_ERROR;
1917 x_msg_count := l_msg_count;
1918 x_msg_data := l_msg_data;
1919 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1920 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1921
1922 WHEN OTHERS THEN
1923 ROLLBACK TO getInstallment;
1924 x_return_status := FND_API.G_RET_STS_ERROR;
1925 x_msg_count := l_msg_count;
1926 x_msg_data := l_msg_data;
1927 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1928 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1929
1930 end getInstallment;
1931
1932
1933 -- created for bug 6599682: EQUALLY SPREAD PRINCIPAL FROM IO PERIODS FOR EPRP LOANS
1934 function get_num_non_ro_instal(p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
1935 ,p_from_installment in NUMBER
1936 ,p_to_installment in NUMBER) return NUMBER
1937 is
1938 l_local_rate_schedule LNS_FINANCIALS.RATE_SCHEDULE_TBL;
1939 l_num_non_ro_payments number;
1940 l_total_installments number;
1941 i number;
1942 j number;
1943 l_api_name varchar2(30);
1944 l_from_installment number;
1945
1946 begin
1947
1948 l_api_name := 'get_num_non_ro_instal';
1949 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - BEGIN');
1950 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_from_installment=' || p_from_installment);
1951
1952 l_from_installment := p_from_installment;
1953 if (l_from_installment is null or l_from_installment = 0) then
1954 l_from_installment := 1;
1955 end if;
1956 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_from_installment=' || l_from_installment);
1957
1958 -- build normal rate schedule table
1959 for i in 1..p_rate_schedule.count loop
1960
1961 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);
1962
1963 for j in p_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER..p_rate_schedule(i).END_INSTALLMENT_NUMBER loop
1964
1965 l_local_rate_schedule(j) := p_rate_schedule(i);
1966 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'adding local rate schedule row ' || j);
1967
1968 end loop;
1969
1970 end loop;
1971
1972 l_num_non_ro_payments := 0;
1973 l_total_installments := l_local_rate_schedule.count;
1974
1975 if p_to_installment is not null then
1976 l_total_installments := p_to_installment;
1977 end if;
1978
1979 for i in l_from_installment..l_total_installments loop
1980
1981 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'local rate schedule row ' || i || ': IO ' || l_local_rate_schedule(i).INTEREST_ONLY_FLAG);
1982
1983 if (l_local_rate_schedule(i).INTEREST_ONLY_FLAG = 'N' or i = l_total_installments) then
1984 l_num_non_ro_payments := l_num_non_ro_payments + 1;
1985 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_num_non_ro_payments ' || l_num_non_ro_payments);
1986 end if;
1987
1988 end loop;
1989
1990 if (l_num_non_ro_payments = 0) then
1991 l_num_non_ro_payments := 1;
1992 end if;
1993
1994 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Result num_payments ' || l_num_non_ro_payments);
1995 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - END');
1996
1997 return l_num_non_ro_payments;
1998
1999 end;
2000
2001
2002
2003 /*=========================================================================
2004 || PUBLIC PROCEDURE getOpenInstallment
2005 ||
2006 || DESCRIPTION
2007 ||
2008 || Overview: returns interest for an installment during openend loan
2009 || this is used for the billing concurrent program
2010 ||
2011 || PSEUDO CODE/LOGIC
2012 ||
2013 || PARAMETERS
2014 ||
2015 || Parameter: p_loan_id => in loanID
2016 || p_installment_number = installment
2017 ||
2018 || Return value: AMORTIZATION_REC => contains billing and payment information
2019 ||
2020 || Source Tables: NA
2021 ||
2022 || Target Tables: NA
2023 ||
2024 || KNOWN ISSUES
2025 ||
2026 || NOTES
2027 || NOTE: api used by Billing Engine
2028 ||
2029 || MODIFICATION HISTORY
2030 || Date Author Description of Changes
2031 || 12/11/2003 12:40PM raverma Created
2032 ||
2033 *=======================================================================*/
2034 procedure getOpenInstallment(p_init_msg_list IN VARCHAR2
2035 ,p_loan_Id in number
2036 ,p_installment_number in number
2037 ,x_amortization_rec OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
2038 ,x_fees_tbl OUT NOCOPY LNS_FINANCIALS.FEES_TBL
2039 ,x_return_status OUT NOCOPY VARCHAR2
2040 ,x_msg_count OUT NOCOPY NUMBER
2041 ,x_msg_data OUT NOCOPY VARCHAR2)
2042 is
2043 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
2044 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
2045 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2046 l_rate_schedule_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2047 l_rates_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2048 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
2049
2050 l_count NUMBER;
2051 l_return_status VARCHAR2(1);
2052 l_msg_count NUMBER;
2053 l_msg_data VARCHAR2(32767);
2054 l_api_name varchar2(25);
2055
2056 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
2057 l_fees_tbl_1 LNS_FEE_ENGINE.FEE_CALC_TBL;
2058 l_fees_tbl_2 LNS_FINANCIALS.FEES_TBL;
2059 l_total_fees number;
2060 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
2061 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL; -- define what event(s) we are processing fees for
2062 i number;
2063 m number;
2064 l_wtd_balance number;
2065 l_periodic_rate number;
2066 l_annualized_rate number; -- needs to be converted to periodic rate
2067 l_periodic_interest number;
2068 l_periodic_principal number;
2069 l_installments number;
2070 l_weigted_rate number;
2071 l_days_at_rate number;
2072 l_total_days number;
2073 l_running_rate number;
2074 l_max_date date;
2075 l_spread number;
2076 l_rate_schedule_id number;
2077 l_rate_to_store number;
2078 l_raw_rate number;
2079 l_next_rate_change date;
2080
2081 cursor c_int_rates(p_rate_id number, p_rate_date date) is
2082 select interest_rate
2083 from lns_int_rate_lines
2084 where start_date_active <= p_rate_date
2085 and end_date_active >= p_rate_date
2086 and interest_rate_id = p_rate_id;
2087
2088 cursor c_rate_info(p_loan_id number) is
2089 select spread
2090 ,rate_id
2091 from lns_rate_schedules rs
2092 ,lns_terms t
2093 where t.loan_id = p_loan_id
2094 and t.term_id = rs.term_id
2095 and phase = 'OPEN';
2096 begin
2097
2098 l_api_name := 'getOpenInstallment';
2099 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2100 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
2101 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
2102
2103 -- Standard Start of API savepoint
2104 SAVEPOINT getOpenInstallment;
2105
2106 -- Initialize message list IF p_init_msg_list is set to TRUE.
2107 IF FND_API.to_Boolean(p_init_msg_list) THEN
2108 FND_MSG_PUB.initialize;
2109 END IF;
2110
2111 -- Initialize API return status to SUCCESS
2112 x_return_status := FND_API.G_RET_STS_SUCCESS;
2113
2114 -- --------------------------------------------------------------------
2115 -- Api body
2116 -- --------------------------------------------------------------------
2117 l_total_fees := 0;
2118 l_amortization_rec.principal_amount := 0;
2119 l_amortization_rec.interest_amount := 0;
2120 l_amortization_rec.total := 0;
2121 l_amortization_rec.fee_amount := 0;
2122 l_amortization_rec.begin_balance := 0;
2123 l_amortization_rec.end_balance := 0;
2124
2125 -- move logic for billing custom loans into FINANCIALS API
2126 l_loan_Details := lns_financials.getLoanDetails(p_loan_id, 'CURRENT', 'OPEN');
2127 l_rates_tbl := lns_financials.getRateSchedule(p_loan_id, 'OPEN');
2128
2129 -- 0. buildPaymentSchedule
2130 -- 1. calculate wtd balance
2131 -- 2. calculateInterest
2132 -- 3. return record
2133 l_payment_tbl := lns_fin_utils.buildPaymentSchedule(p_loan_start_date => l_loan_Details.loan_start_date
2134 ,p_loan_maturity_date => l_loan_details.maturity_date
2135 ,p_first_pay_date => l_loan_details.first_payment_date
2136 ,p_num_intervals => l_loan_details.number_installments
2137 ,p_interval_type => l_loan_details.payment_frequency
2138 ,p_pay_in_arrears => l_loan_details.pay_in_arrears_boolean);
2139
2140 -- get the weighted balance for the period
2141 begin
2142 l_wtd_balance := lns_financials.getWeightedBalance(p_loan_id => p_loan_id
2143 ,p_from_date => l_payment_tbl(1).period_begin_date
2144 ,p_to_date => l_payment_tbl(p_installment_number).period_end_date
2145 ,p_calc_method => 'ACTUAL'
2146 ,p_phase => 'OPEN'
2147 ,p_day_count_method => l_loan_Details.day_count_method);
2148 exception
2149 when others then
2150 FND_MESSAGE.SET_NAME('LNS', 'LNS_COMPUTE_BALANCE_ERROR');
2151 FND_MSG_PUB.ADD;
2152 RAISE FND_API.G_EXC_ERROR;
2153
2154 end;
2155 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - l_wtd_balance is ' || l_wtd_balance);
2156
2157 -- now caculate the interest due for this period
2158 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_wtd_balance);
2159 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': period start ' || l_payment_tbl(p_installment_number).period_begin_date);
2160 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': period end ' || l_payment_tbl(p_installment_number).period_end_date);
2161
2162 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate type = ' || l_loan_details.rate_type );
2163 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
2164 l_rate_details := getRateDetails(p_installment => p_installment_number
2165 ,p_rate_tbl => l_rates_tbl);
2166 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate details ' || l_rate_details.annual_rate);
2167
2168 if l_loan_details.rate_type = 'FIXED' OR (l_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'N') then
2169
2170 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FIXED OR NOT FLOATING ');
2171 l_annualized_rate := l_rate_details.ANNUAL_RATE;
2172
2173 elsif l_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'Y' then
2174
2175 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING ');
2176 -- if float and no rate then error;
2177 -- we only need to get the new rate if
2178 -- 1. no rate has ever been calculated (i.e. 1st installment)
2179 -- 2. the billing date is beyond the next_rate_change_date
2180 -- 3. make sure to add spread and abide by rate rules
2181 if l_payment_tbl(p_installment_number).period_begin_date < l_loan_details.NEXT_RATE_CHANGE_DATE then
2182
2183 -- no need to recalculate interest
2184 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING NO RECALC');
2185 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_loan_details.last_interest_rate:' || l_loan_details.last_interest_rate);
2186 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': spread:' || l_rate_details.spread);
2187 l_annualized_rate := l_loan_details.last_interest_rate + l_rate_details.spread;
2188
2189 elsif p_installment_number = 1 OR l_payment_tbl(p_installment_number).period_begin_date > l_loan_details.NEXT_RATE_CHANGE_DATE then
2190 l_rate_details.ANNUAL_RATE := lns_fin_utils.getRateForDate(l_loan_details.OPEN_INDEX_RATE_ID
2191 ,l_payment_tbl(p_installment_number).period_begin_date);
2192
2193 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING RECALCULATE');
2194 -- raise error as rates does not exist
2195 if l_rate_details.ANNUAL_RATE is null then
2196 FND_MESSAGE.SET_NAME('LNS', 'LNS_RATES_ERROR');
2197 FND_MSG_PUB.ADD;
2198 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for INDEX_ID ' || l_loan_details.OPEN_INDEX_RATE_ID);
2199 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for DATE ' || l_loan_details.NEXT_RATE_CHANGE_DATE);
2200 RAISE FND_API.G_EXC_ERROR;
2201 end if;
2202
2203 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_rate_details.ANNUAL_RATE ' || l_rate_details.ANNUAL_RATE );
2204 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_rate_details.spread ' || l_rate_details.spread);
2205 -- add the spread into the rate
2206 l_raw_rate := l_rate_details.ANNUAL_RATE + l_rate_details.spread;
2207 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_raw_rate ' || l_raw_rate);
2208
2209 -- adjust the rate as per rate rules
2210 l_annualized_rate := calculateInterestRate(p_initial_rate => l_loan_details.INITIAL_INTEREST_RATE
2211 ,p_rate_to_compare => l_raw_rate
2212 ,p_last_period_rate => l_loan_details.LAST_INTEREST_RATE
2213 ,p_max_first_adjustment => l_loan_details.OPEN_FIRST_PERCENT_INCREASE
2214 ,p_max_period_adjustment => l_loan_details.OPEN_ADJ_PERCENT_INCREASE
2215 ,p_max_lifetime_adjustment => l_loan_details.OPEN_LIFE_PERCENT_INCREASE
2216 ,p_ceiling_rate => l_loan_details.OPEN_CEILING_RATE
2217 ,p_floor_rate => l_loan_details.OPEN_FLOOR_RATE
2218 ,p_installment_number => p_installment_number);
2219 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate ' || l_annualized_rate);
2220
2221 end if; -- recalc or not
2222
2223 end if; -- floating or not
2224
2225 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate ' || l_annualized_rate);
2226 l_periodic_rate := lns_financials.getPeriodicRate(p_period_start_date => l_payment_tbl(p_installment_number).period_begin_date
2227 ,p_period_end_date => l_payment_tbl(p_installment_number).period_end_date
2228 ,p_annualized_rate => l_annualized_rate
2229 ,p_days_count_method => l_loan_Details.day_count_method);
2230
2231 l_periodic_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
2232 ,p_periodic_rate => l_periodic_rate
2233 ,p_compounding_period => null);
2234
2235 l_periodic_interest := round(l_periodic_interest, l_loan_Details.currency_precision);
2236
2237 if p_installment_number = l_loan_details.number_installments and
2238 (l_loan_details.OPEN_TO_TERM_FLAG = 'N' OR l_loan_details.SECONDARY_STATUS = 'REMAINING_DISB_CANCELLED') then
2239 l_periodic_principal := l_loan_details.funded_amount;
2240 else
2241 l_periodic_principal := 0;
2242 end if;
2243
2244
2245 -- this information is needed to calculate fees
2246 -- rest of the record can be built after fees are calculated
2247 l_amortization_rec.installment_number := p_installment_number; /* needed to calculate fees */
2248 l_amortization_rec.due_date := l_payment_tbl(p_installment_number).period_due_date;
2249 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
2250 l_amortization_rec.interest_amount := l_periodic_interest;
2251
2252 -- 12-21-2004 raverma added for lns.b
2253 lns_fee_engine.getFeeSchedule(p_init_msg_list => FND_API.G_FALSE
2254 ,p_loan_id => p_loan_id
2255 ,p_installment_number => p_installment_number
2256 ,p_disb_header_id => null
2257 ,x_fees_tbl => l_fees_tbl_1
2258 ,x_return_status => l_return_status
2259 ,x_msg_count => l_msg_count
2260 ,x_msg_data => l_msg_data);
2261
2262 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
2263 FND_MESSAGE.SET_NAME('LNS', 'LNS_READ_FEE_ERROR');
2264 FND_MSG_PUB.ADD;
2265 RAISE FND_API.G_EXC_ERROR;
2266 end if;
2267
2268 for k in 1..l_fees_tbl_1.count loop
2269 l_fees_tbl_2(k).FEE_ID := l_fees_tbl_1(k).FEE_ID;
2270 l_fees_tbl_2(k).FEE_NAME := l_fees_tbl_1(k).FEE_NAME;
2271 l_fees_tbl_2(k).FEE_AMOUNT := l_fees_tbl_1(k).FEE_AMOUNT;
2272 l_fees_tbl_2(k).FEE_INSTALLMENT := l_fees_tbl_1(k).FEE_INSTALLMENT;
2273 l_fees_tbl_2(k).FEE_DESCRIPTION := l_fees_tbl_1(k).FEE_DESCRIPTION;
2274 l_fees_tbl_2(k).FEE_SCHEDULE_ID := l_fees_tbl_1(k).FEE_SCHEDULE_ID;
2275 l_fees_tbl_2(k).FEE_WAIVABLE_FLAG := l_fees_tbl_1(k).FEE_WAIVABLE_FLAG;
2276 l_fees_tbl_2(k).WAIVE_AMOUNT := l_fees_tbl_1(k).WAIVE_AMOUNT;
2277 l_fees_tbl_2(k).BILLED_FLAG := l_fees_tbl_1(k).BILLED_FLAG;
2278 l_fees_tbl_2(k).ACTIVE_FLAG := l_fees_tbl_1(k).ACTIVE_FLAG;
2279 l_total_fees := l_total_fees + l_fees_tbl_1(k).FEE_AMOUNT;
2280 end loop;
2281
2282 -- overwrite amortization record returned from amortizationAPI
2283 l_amortization_rec.rate_id := l_rate_Details.rate_id;
2284 l_amortization_rec.rate_unadj := l_annualized_rate;
2285 l_amortization_rec.RATE_CHANGE_FREQ:= l_loan_details.OPEN_RATE_CHG_FREQ;
2286 l_amortization_rec.fee_amount := l_total_fees;
2287 x_fees_tbl := l_fees_tbl_2;
2288 x_amortization_rec := l_amortization_rec;
2289 -- --------------------------------------------------------------------
2290 -- End of API body
2291 -- --------------------------------------------------------------------
2292
2293 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2294 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
2295
2296 EXCEPTION
2297 WHEN FND_API.G_EXC_ERROR THEN
2298 ROLLBACK TO getOpenInstallment;
2299 x_return_status := FND_API.G_RET_STS_ERROR;
2300 x_msg_count := l_msg_count;
2301 x_msg_data := l_msg_data;
2302 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2303 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2304
2305 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
2306 ROLLBACK TO getOpenInstallment;
2307 x_return_status := FND_API.G_RET_STS_ERROR;
2308 x_msg_count := l_msg_count;
2309 x_msg_data := l_msg_data;
2310 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2311 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2312
2313 WHEN OTHERS THEN
2314 ROLLBACK TO getOpenInstallment;
2315 x_return_status := FND_API.G_RET_STS_ERROR;
2316 x_msg_count := l_msg_count;
2317 x_msg_data := l_msg_data;
2318 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2319 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2320
2321 end getOpenInstallment;
2322
2323 /*=========================================================================
2324 || PUBLIC PROCEDURE getRatesTable
2325 ||
2326 || DESCRIPTION
2327 ||
2328 || Overview: function will return a table of dates for interest rates
2329 ||
2330 || Parameter: p_index_rate_id => index reference
2331 || p_index_date => date to start pulling rates
2332 || p_rate_change_frequency => frequency of rate changes
2333 || p_maturity_date => final date to get rates
2334 ||
2335 || Source Tables: NA
2336 ||
2337 || Target Tables:
2338 ||
2339 ||
2340 || KNOWN ISSUES
2341 ||
2342 || NOTES
2343 ||
2344 || MODIFICATION HISTORY
2345 || Date Author Description of Changes
2346 || 08/15/2005 11:35AM raverma Created
2347 *=======================================================================*/
2348 function getRatesTable(p_index_rate_id in number
2349 ,p_index_date in date
2350 ,p_rate_change_frequency in varchar2
2351 ,p_maturity_date in date) return LNS_FINANCIALS.RATE_SCHEDULE_TBL is
2352
2353 l_intial_date date;
2354 l_rate_date date;
2355 l_rate number;
2356 l_Rates_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2357 i number;
2358 l_api_name varchar2(25);
2359
2360 begin
2361
2362 l_api_name := 'getRatesTable';
2363
2364 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2365 i := 1;
2366 l_Rates_tbl(i).begin_date := p_index_date;
2367 l_rate_date := p_index_date;
2368 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_index_date ' || p_index_date);
2369 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_rate_change_frequency ' || p_rate_change_frequency);
2370 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_maturity_date ' || p_maturity_date );
2371 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_index_rate_id ' || p_index_rate_id );
2372
2373 WHILE l_rate_date <= p_maturity_date LOOP
2374 l_rate_date := lns_fin_utils.getNextDate(l_rate_date, p_rate_change_frequency, 1);
2375 i := i + 1;
2376 l_Rates_tbl(i).begin_date := l_rate_date;
2377 --logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_date ' || l_rate_date);
2378 END LOOP;
2379 /*
2380 for k in 1..l_Rates_tbl.count loop
2381 dbms_output.put_line(l_Rates_tbl(k).begin_date);
2382 end loop;
2383 */
2384 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
2385 return l_Rates_tbl;
2386
2387 end getRatesTable;
2388
2389
2390 -- created for bug 6498771
2391 function get_remain_num_prin_instal(p_payment_tbl in LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL
2392 ,p_from_installment in NUMBER) return NUMBER
2393 is
2394 l_num_prin_payments number;
2395 l_total_installments number;
2396 i number;
2397 begin
2398
2399 -- loop throught the amortization schedule and count number of PRIN and PRIN_INT rows
2400 l_num_prin_payments := 0;
2401 l_total_installments := p_payment_tbl.count;
2402 for i in p_from_installment..l_total_installments loop
2403 if (p_payment_tbl(i).CONTENTS = 'PRIN' or p_payment_tbl(i).CONTENTS = 'PRIN_INT') then
2404 l_num_prin_payments := l_num_prin_payments + 1;
2405 end if;
2406 end loop;
2407
2408 return l_num_prin_payments;
2409
2410 end;
2411
2412
2413 /*=========================================================================
2414 || PUBLIC PROCEDURE amortizeSIPLoan
2415 ||
2416 || DESCRIPTION
2417 ||
2418 || Overview: procedure generates seperate interest and principal amortization
2419 || this is the main calculation API for amortization
2420 || THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
2421 || 1. Amortization UI - when creating a loan
2422 || 2. Billing Engine - to generate installment bills
2423 ||
2424 || Parameter: p_loan_details = details of the loan
2425 || p_rate_schedule = rate schedule for the loan
2426 || p_installment_number => billing will pass in an installment
2427 || number to generate a billt
2428 || x_loan_amort_tbl => table of amortization records
2429 ||
2430 || Source Tables: NA
2431 ||
2432 || Target Tables: LNS_TEMP_AMORTIZATIONS
2433 ||
2434 ||
2435 || KNOWN ISSUES
2436 ||
2437 || NOTES
2438 ||
2439 || MODIFICATION HISTORY
2440 ||
2441 || Date Author Description of Changes
2442 || 10/08/2007 scherkas Created: fix for bug 6498771
2443 || 16/01/2008 scherkas Fixed bug 6749924
2444 || 08/04/2008 scherkas Fixed bug 6945153: change procedure to query past installments
2445 || 18/06/2008 scherkas Fixed bug 7184830
2446 *=======================================================================*/
2447 procedure amortizeSIPLoan(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
2448 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
2449 ,p_based_on_terms in varchar2
2450 ,p_installment_number in number
2451 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
2452 is
2453 l_return_status varchar2(1);
2454 l_msg_count NUMBER;
2455 l_msg_data VARCHAR2(32767);
2456 -- loan_details
2457 l_loan_id number;
2458 l_original_loan_amount number; -- loan amount
2459 l_amortized_term number;
2460 l_amortized_term_period varchar2(30);
2461 l_amortization_frequency varchar2(30);
2462 l_loan_period_number number;
2463 l_loan_period_type varchar2(30);
2464 l_first_payment_date date;
2465 l_pay_in_arrears boolean;
2466 l_payment_frequency varchar2(30);
2467 l_day_count_method varchar2(30);
2468 l_interest_comp_freq varchar2(30);
2469 l_calculation_method varchar2(30);
2470 l_reamortize_from_installment number;
2471 l_reamortize_amount number;
2472 l_annualized_rate number; -- annual rate on the loan
2473 l_intervals_original number;
2474 l_intervals number;
2475 l_intervals_remaining number;
2476 l_amortization_intervals_orig number;
2477 l_amortization_intervals_rem number;
2478 l_amortization_intervals number; -- number of intervals to amortize over
2479 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
2480 l_current_rate_id number;
2481 l_previous_rate_id number;
2482 l_precision number;
2483
2484 l_period_start_Date date;
2485 l_period_end_date date;
2486 l_periodic_rate number;
2487 l_maturity_date date;
2488
2489 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
2490 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
2491 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2492 --l_pay_dates LNS_FINANCIALS.DATE_TBL;
2493 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2494 l_loan_start_date date;
2495 l_num_pay_dates number; -- number of dates on installment schedule
2496 l_periodic_payment number;
2497 l_periodic_principal number;
2498 l_periodic_interest number;
2499 l_interest_based_on_amount number; -- do we calculate interest from actual or predicted remaining balance
2500 l_pay_date date;
2501 l_total_principal number;
2502 l_payment_number number;
2503 l_fee_amount number;
2504 l_fee_amount1 number;
2505 l_other_amount number;
2506 l_begin_balance number;
2507 l_end_balance number;
2508 l_unbilled_principal number;
2509 l_unpaid_principal number;
2510 l_unpaid_interest number;
2511
2512 l_remaining_balance_actual number;
2513 l_remaining_balance_theory number;
2514 l_total number;
2515 l_interest_cumulative number;
2516 l_principal_cumulative number;
2517 l_fees_cumulative number;
2518 l_other_cumulative number;
2519 i number;
2520 l_installment_number number;
2521 l_billing boolean; -- switch to notify if billing is calling API
2522 l_api_name varchar2(20);
2523 l_last_installment_billed number;
2524 l_rate_to_calculate number;
2525 l_previous_annualized number;
2526 l_interest_only_flag varchar2(1);
2527 l_calc_method varchar2(30);
2528 l_compound_freq varchar2(30);
2529 l_interest number;
2530 l_hidden_cumul_interest number;
2531 l_num_prin_payments number;
2532 l_hidden_periodic_prin number;
2533 l_prin_first_pay_date date;
2534 l_prin_payment_frequency varchar2(30);
2535 l_prin_intervals number;
2536 l_prin_pay_in_arrears boolean;
2537 l_prin_amortized_intervals number;
2538 l_prin_intervals_diff number;
2539 l_remaining_balance_actual1 number;
2540 l_extend_from_installment number;
2541 l_force_reamortization boolean;
2542 l_norm_interest number;
2543 l_add_prin_interest number;
2544 l_add_int_interest number;
2545 l_add_start_date date;
2546 l_add_end_date date;
2547 l_start_installment number;
2548 l_end_installment number;
2549 l_first_installment_billed number;
2550 l_hidden_cumul_norm_int number;
2551 l_hidden_cumul_add_prin_int number;
2552 l_hidden_cumul_add_int_int number;
2553 l_hidden_cumul_penal_int number;
2554 l_periodic_norm_int number;
2555 l_periodic_add_prin_int number;
2556 l_periodic_add_int_int number;
2557 l_periodic_penal_int number;
2558 l_penal_prin_interest number;
2559 l_penal_int_interest number;
2560 l_penal_interest number;
2561 l_prev_grace_end_date date;
2562 l_raw_rate number;
2563 l_balloon_amount number;
2564 l_remaining_balance number;
2565
2566 -- for fees
2567 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
2568 l_memo_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
2569 l_orig_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
2570 l_conv_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
2571 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
2572 l_memo_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
2573 l_orig_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
2574 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
2575
2576 -- total fees on the schedule by installment
2577 cursor c_fees(p_loan_id number, p_installment number) is
2578 select nvl(sum(sched.fee_amount), 0)
2579 from lns_fee_schedules sched
2580 ,lns_fees struct
2581 where sched.loan_id = p_loan_id
2582 and sched.fee_id = struct.fee_id
2583 and struct.fee_type = 'EVENT_ORIGINATION'
2584 and fee_installment = p_installment
2585 and active_flag = 'Y';
2586
2587 cursor c_conv_fees(p_loan_id number) is
2588 select nvl(sum(fee),0)
2589 from lns_fee_assignments
2590 where loan_id = p_loan_id
2591 and fee_type = 'EVENT_CONVERSION';
2592
2593 -- get first billed installment number
2594 cursor c_first_billed_instal(p_loan_id number) is
2595 select min(PAYMENT_NUMBER)
2596 from LNS_AMORTIZATION_SCHEDS
2597 where loan_id = p_loan_id
2598 and PAYMENT_NUMBER > 0
2599 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
2600 and PARENT_AMORTIZATION_ID is null
2601 and nvl(PHASE, 'TERM') = 'TERM';
2602
2603 -- get last bill date
2604 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
2605 select ACTIVITY_DATE
2606 from LNS_PRIN_TRX_ACTIVITIES_V
2607 where loan_id = p_loan_id
2608 and PAYMENT_NUMBER = p_installment_number
2609 and PARENT_AMORTIZATION_ID is null
2610 and ACTIVITY_CODE in ('BILLING', 'START');
2611
2612 begin
2613
2614 -- initialize all variables
2615 l_api_name := 'amortizeSIPLoan MAIN';
2616
2617 l_original_loan_amount := 0; -- loan amount
2618 l_loan_period_number := 0;
2619 l_previous_rate_id := -1;
2620 l_previous_annualized := -1;
2621 l_periodic_payment := 0;
2622 l_periodic_principal := 0;
2623 l_periodic_interest := 0;
2624 l_balloon_amount := 0;
2625 l_total_principal := 0;
2626 l_payment_number := 0;
2627 l_fee_amount := 0;
2628 l_other_amount := 0;
2629 l_begin_balance := 0;
2630 l_unbilled_principal := 0;
2631 l_unpaid_principal := 0;
2632 l_remaining_balance_actual := 0;
2633 l_remaining_balance_theory := 0;
2634 l_total := 0;
2635 l_interest_cumulative := 0;
2636 l_principal_cumulative := 0;
2637 l_fees_cumulative := 0;
2638 l_other_cumulative := 0;
2639 i := 0;
2640 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
2641 l_rate_to_calculate := 0;
2642 l_billing := false; -- switch to notify if billing is calling API
2643 l_hidden_cumul_interest := 0;
2644 l_hidden_periodic_prin := 0;
2645 l_force_reamortization := false;
2646
2647 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2648 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
2649 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
2650
2651 l_amortized_term := p_loan_details.amortized_term;
2652 l_amortized_term_period := p_loan_details.amortized_term_period;
2653 l_amortization_frequency := p_loan_details.amortization_frequency;
2654 l_payment_frequency := p_loan_details.payment_frequency;
2655 l_first_payment_date := p_loan_details.first_payment_date;
2656 l_original_loan_amount := p_loan_details.requested_amount;
2657 l_remaining_balance_actual := p_loan_details.remaining_balance;
2658 l_remaining_balance_actual1 := p_loan_details.remaining_balance;
2659 l_maturity_date := p_loan_details.maturity_date;
2660 l_intervals := p_loan_details.number_installments;
2661 l_intervals_original := p_loan_details.number_installments;
2662 l_amortization_intervals_orig := p_loan_details.num_amortization_intervals;
2663 l_amortization_intervals := p_loan_details.num_amortization_intervals;
2664 l_amortization_intervals_rem := p_loan_details.num_amortization_intervals;
2665 l_balloon_amount := p_loan_details.balloon_payment_amount;
2666 l_last_installment_billed := p_loan_details.last_installment_billed;
2667 l_day_count_method := p_loan_details.day_count_method;
2668 l_loan_start_date := p_loan_details.loan_start_date;
2669 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
2670 l_precision := p_loan_details.currency_precision;
2671 l_reamortize_from_installment := p_loan_details.reamortize_from_installment;
2672 l_reamortize_amount := p_loan_details.reamortize_amount;
2673 l_loan_id := p_loan_details.loan_id;
2674 l_calc_method := p_loan_details.CALCULATION_METHOD;
2675 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
2676 l_prin_first_pay_date := p_loan_details.PRIN_FIRST_PAY_DATE;
2677 l_prin_payment_frequency := p_loan_details.PRIN_PAYMENT_FREQUENCY;
2678 l_prin_intervals := p_loan_details.PRIN_NUMBER_INSTALLMENTS;
2679 l_prin_amortized_intervals := p_loan_details.PRIN_AMORT_INSTALLMENTS;
2680 l_prin_pay_in_arrears := p_loan_details.PRIN_PAY_IN_ARREARS_BOOL;
2681 l_prin_intervals_diff := l_prin_amortized_intervals - l_prin_intervals;
2682 l_extend_from_installment := p_loan_details.EXTEND_FROM_INSTALLMENT;
2683
2684 -- get the interest rate schedule
2685 l_rate_tbl := p_rate_schedule;
2686 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count: ' || l_rate_tbl.count);
2687
2688 -- get payment schedule
2689 -- this will return the acutal dates that payments will be due on
2690 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
2691
2692 l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
2693 p_loan_start_date => l_loan_start_date
2694 ,p_loan_maturity_date => l_maturity_date
2695 ,p_int_first_pay_date => l_first_payment_date
2696 ,p_int_num_intervals => l_intervals
2697 ,p_int_interval_type => l_payment_frequency
2698 ,p_int_pay_in_arrears => l_pay_in_arrears
2699 ,p_prin_first_pay_date => l_prin_first_pay_date
2700 ,p_prin_num_intervals => l_prin_intervals
2701 ,p_prin_interval_type => l_prin_payment_frequency
2702 ,p_prin_pay_in_arrears => l_prin_pay_in_arrears);
2703
2704 l_num_pay_dates := l_payment_tbl.count;
2705
2706 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count: ' || l_num_pay_dates);
2707
2708 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting conv fee structures');
2709 l_conv_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
2710 ,p_fee_category => 'EVENT'
2711 ,p_fee_type => 'EVENT_CONVERSION'
2712 ,p_installment => null
2713 ,p_fee_id => null);
2714 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': conv structures count is ' || l_conv_fee_structures.count);
2715
2716 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting origination fee structures');
2717 l_orig_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
2718 ,p_fee_category => 'EVENT'
2719 ,p_fee_type => 'EVENT_ORIGINATION'
2720 ,p_installment => null
2721 ,p_fee_id => null);
2722 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig structures count is ' || l_orig_fee_structures.count);
2723
2724 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting recurring fee structures');
2725 l_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
2726 ,p_fee_category => 'RECUR'
2727 ,p_fee_type => null
2728 ,p_installment => null
2729 ,p_fee_id => null);
2730 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': fee structures count is ' || l_fee_structures.count);
2731
2732 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting memo fee structures');
2733 l_memo_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
2734 ,p_fee_category => 'MEMO'
2735 ,p_fee_type => null
2736 ,p_installment => null
2737 ,p_fee_id => null);
2738 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': memo fee structures count is ' || l_memo_fee_structures.count);
2739
2740 -- 2-24-2005 raverma add 0 installment to amortization schedule
2741 if l_orig_fee_structures.count > 0 or l_conv_fee_structures.count > 0 then
2742
2743 open c_fees(l_loan_id, 0);
2744 fetch c_fees into l_fee_amount1;
2745 close c_fees;
2746 l_fee_amount := l_fee_amount1;
2747
2748 open c_conv_fees(l_loan_id);
2749 fetch c_conv_fees into l_fee_amount1;
2750 close c_conv_fees;
2751 l_fee_amount := l_fee_amount1 + l_fee_amount;
2752
2753 if l_fee_amount > 0 then
2754 i := i + 1;
2755 l_amortization_rec.installment_number := 0;
2756 l_amortization_rec.due_date := l_loan_start_date;
2757 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
2758 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
2759 l_amortization_rec.principal_amount := 0;
2760 l_amortization_rec.interest_amount := 0;
2761 l_amortization_rec.fee_amount := l_fee_amount;
2762 l_amortization_rec.other_amount := 0;
2763 l_amortization_rec.begin_balance := l_original_loan_amount;
2764 l_amortization_rec.end_balance := l_original_loan_amount;
2765 l_amortization_rec.interest_cumulative := 0;
2766 l_amortization_rec.principal_cumulative := 0;
2767 l_amortization_rec.fees_cumulative := l_fee_amount;
2768 l_amortization_rec.other_cumulative := 0;
2769 l_amortization_rec.rate_id := 0;
2770 l_amortization_rec.SOURCE := 'PREDICTED';
2771 -- add the record to the amortization table
2772 l_amortization_rec.total := l_fee_amount;
2773 l_amortization_rec.UNPAID_PRIN := 0;
2774 l_amortization_rec.UNPAID_INT := 0;
2775 l_amortization_rec.INTEREST_RATE := 0;
2776 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
2777 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
2778 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
2779 l_amortization_rec.PENAL_INT_AMOUNT := 0;
2780 l_amortization_tbl(i) := l_amortization_rec;
2781 end if;
2782
2783 --l_orig_fees_tbl.delete;
2784 l_fee_amount := 0;
2785
2786 end if;
2787
2788 -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
2789 l_remaining_balance_theory := l_original_loan_amount;
2790 if p_installment_number is not null then
2791
2792 l_billing := true;
2793 if p_installment_number > 0 then
2794
2795 if p_installment_number > l_num_pay_dates then
2796 l_payment_number := l_num_pay_dates;
2797 else
2798 l_payment_number := p_installment_number;
2799 end if;
2800
2801 else
2802 i := i + 1;
2803 -- special we are on the 0th installment
2804 l_amortization_rec.installment_number := 0;
2805 l_amortization_rec.due_date := l_loan_start_date;
2806 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
2807 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
2808 l_amortization_rec.principal_amount := l_periodic_principal;
2809 l_amortization_rec.interest_amount := l_periodic_interest;
2810 l_amortization_rec.fee_amount := l_fee_amount;
2811 l_amortization_rec.begin_balance := l_remaining_balance_actual;
2812 l_amortization_rec.end_balance := l_remaining_balance_actual;
2813 l_amortization_rec.interest_cumulative := l_interest_cumulative;
2814 l_amortization_rec.principal_cumulative := l_principal_cumulative;
2815 l_amortization_rec.fees_cumulative := l_fees_cumulative + l_fee_amount;
2816 l_amortization_rec.other_cumulative := l_other_cumulative;
2817 l_amortization_rec.rate_id := l_current_rate_id;
2818 l_amortization_rec.UNPAID_PRIN := 0;
2819 l_amortization_rec.UNPAID_INT := 0;
2820 l_amortization_rec.INTEREST_RATE := 0;
2821 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
2822 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
2823 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
2824 l_amortization_rec.PENAL_INT_AMOUNT := 0;
2825 -- add the record to the amortization table
2826 l_amortization_tbl(i) := l_amortization_rec;
2827
2828 end if;
2829
2830 else
2831
2832 l_payment_number := l_num_pay_dates;
2833
2834 end if;
2835
2836 l_remaining_balance_actual := l_original_loan_amount;
2837
2838 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
2839 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
2840
2841 -- searching for start and end installments to calc additional interests
2842 if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
2843
2844 open c_first_billed_instal(l_loan_id);
2845 fetch c_first_billed_instal into l_first_installment_billed;
2846 close c_first_billed_instal;
2847
2848 if l_first_installment_billed > 1 then
2849 l_first_installment_billed := l_first_installment_billed + 1;
2850 end if;
2851 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_first_installment_billed = ' || l_first_installment_billed);
2852
2853 l_start_installment := l_last_installment_billed + 1;
2854 for j in REVERSE l_first_installment_billed..l_last_installment_billed loop
2855 if l_payment_tbl(j).CONTENTS <> 'PRIN' then
2856 exit;
2857 end if;
2858 l_start_installment := j;
2859 end loop;
2860 l_end_installment := l_last_installment_billed + 1;
2861 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_start_installment = ' || l_start_installment);
2862 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_end_installment = ' || l_end_installment);
2863
2864 end if;
2865
2866 l_hidden_cumul_norm_int := 0;
2867 l_hidden_cumul_add_prin_int := 0;
2868 l_hidden_cumul_add_int_int := 0;
2869 l_hidden_cumul_interest := 0;
2870 l_hidden_cumul_penal_int := 0;
2871
2872 -- loop to build the amortization schedule
2873 for l_installment_number in 1..l_payment_number
2874 loop
2875
2876 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2877 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || '-----');
2878
2879 i := i + 1;
2880 l_periodic_interest := 0;
2881 l_periodic_norm_int := 0;
2882 l_periodic_add_prin_int := 0;
2883 l_periodic_add_int_int := 0;
2884 l_periodic_penal_int := 0;
2885 l_periodic_principal := 0;
2886 l_fee_amount := 0;
2887 l_other_amount := 0;
2888 l_unpaid_principal := 0;
2889 l_unpaid_interest := 0;
2890 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
2891
2892 -- this is the main check for calculating interest on actual balance not theoretical
2893 -- intercept and overwrite the remaining balance theory with remain balance actual
2894 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number)
2895 and p_based_on_terms = 'CURRENT' then
2896 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': BASED ON CURRENT TERMS FROM INSTALLMENT: ' || l_installment_number);
2897
2898 l_principal_cumulative := 0;
2899 l_interest_cumulative := 0;
2900 l_fees_cumulative := 0;
2901 l_other_cumulative := 0;
2902 -- get the unbilled / unpaid principal at this point in time i.e. for this installment
2903 l_unbilled_principal := p_loan_details.unbilled_principal;
2904 l_unpaid_principal := p_loan_details.unpaid_principal;
2905 l_unpaid_interest := p_loan_details.UNPAID_INTEREST; -- + l_hidden_cumul_interest;
2906
2907 -- bug #3811298
2908 if p_loan_details.loan_status <> 'PAIDOFF' then
2909 -- begin fix for bug# 6663848
2910 if (l_calc_method = 'SIMPLE') then
2911 l_remaining_balance_actual := l_remaining_balance_actual1;
2912 elsif (l_calc_method = 'COMPOUND') then
2913 l_remaining_balance_actual := l_remaining_balance_actual1 + l_unpaid_interest;
2914 end if;
2915 -- end fix for bug# 6663848
2916 l_remaining_balance_theory := l_remaining_balance_actual1 - l_unpaid_principal;
2917 else
2918 l_remaining_balance_actual := 0;
2919 l_remaining_balance_theory := 0;
2920 end if;
2921 end if;
2922
2923 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_actual: ' || l_remaining_balance_actual);
2924 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory: ' || l_remaining_balance_theory);
2925
2926 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
2927 l_rate_details := getRateDetails(p_installment => l_installment_number
2928 ,p_rate_tbl => l_rate_tbl);
2929
2930 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate ' || l_rate_details.annual_rate);
2931 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread ' || l_rate_details.spread);
2932 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id ' || l_rate_details.rate_id);
2933 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate floating_flag ' || l_rate_details.floating_flag);
2934
2935 l_current_rate_id := l_rate_details.rate_id;
2936 l_annualized_rate := l_rate_details.annual_rate;
2937 l_interest_only_flag := l_rate_details.interest_only_flag;
2938
2939 -- add in support here for floating rate loans
2940 if p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'Y' then
2941
2942 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING ');
2943 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': period_begin_date ' || l_payment_tbl(l_installment_number).period_begin_date);
2944 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
2945 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.NEXT_RATE_CHANGE_DATE ' || p_loan_details.NEXT_RATE_CHANGE_DATE);
2946 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.OPEN_INDEX_RATE_ID ' || p_loan_details.OPEN_INDEX_RATE_ID);
2947 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.INITIAL_INTEREST_RATE ' || p_loan_details.INITIAL_INTEREST_RATE);
2948 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
2949 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_FIRST_PERCENT_INCREASE ' || p_loan_details.TERM_FIRST_PERCENT_INCREASE);
2950 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_ADJ_PERCENT_INCREASE ' || p_loan_details.TERM_ADJ_PERCENT_INCREASE);
2951 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_LIFE_PERCENT_INCREASE ' || p_loan_details.TERM_LIFE_PERCENT_INCREASE);
2952 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_CEILING_RATE ' || p_loan_details.TERM_CEILING_RATE);
2953 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_FLOOR_RATE ' || p_loan_details.TERM_FLOOR_RATE);
2954
2955 -- if float and no rate then error;
2956 -- we only need to get the new rate if
2957 -- 1. no rate has ever been calculated (i.e. 1st installment)
2958 -- 2. the billing date is beyond the next_rate_change_date
2959 -- 3. make sure to add spread and abide by rate rules
2960 if l_payment_tbl(l_installment_number).period_begin_date < p_loan_details.NEXT_RATE_CHANGE_DATE and l_installment_number > 1 then
2961
2962 -- no need to recalculate interest, use current interest rate found on last installment
2963 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING NO RECALC');
2964
2965 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
2966 l_annualized_rate := p_loan_details.LAST_INTEREST_RATE + l_rate_details.spread;
2967
2968 --elsif l_installment_number = 1 OR l_payment_tbl(l_installment_number).period_begin_date >= p_loan_details.NEXT_RATE_CHANGE_DATE then
2969 else
2970
2971 if p_based_on_terms = 'CURRENT' then
2972
2973 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING RECALCULATE');
2974
2975 l_rate_details.ANNUAL_RATE := lns_fin_utils.getRateForDate(p_loan_details.OPEN_INDEX_RATE_ID
2976 ,l_payment_tbl(l_installment_number).period_begin_date);
2977
2978 -- raise error as rates does not exist
2979 if l_rate_details.ANNUAL_RATE is null then
2980 FND_MESSAGE.SET_NAME('LNS', 'LNS_RATES_ERROR');
2981 FND_MSG_PUB.ADD;
2982 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for INDEX_ID ' || p_loan_details.TERM_INDEX_RATE_ID);
2983 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for DATE ' || p_loan_details.NEXT_RATE_CHANGE_DATE);
2984 RAISE FND_API.G_EXC_ERROR;
2985 end if;
2986
2987 -- add the spread into the rate
2988 l_raw_rate := l_rate_details.ANNUAL_RATE + l_rate_details.spread;
2989 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_raw_rate ' || l_raw_rate);
2990
2991 -- adjust the rate as per rate rules
2992 l_annualized_rate := calculateInterestRate(p_initial_rate => p_loan_details.INITIAL_INTEREST_RATE
2993 ,p_rate_to_compare => l_raw_rate
2994 ,p_last_period_rate => p_loan_details.LAST_INTEREST_RATE
2995 ,p_max_first_adjustment => p_loan_details.TERM_FIRST_PERCENT_INCREASE
2996 ,p_max_period_adjustment => p_loan_details.TERM_ADJ_PERCENT_INCREASE
2997 ,p_max_lifetime_adjustment => p_loan_details.TERM_LIFE_PERCENT_INCREASE
2998 ,p_ceiling_rate => p_loan_details.TERM_CEILING_RATE
2999 ,p_floor_rate => p_loan_details.TERM_FLOOR_RATE
3000 ,p_installment_number => l_installment_number);
3001
3002 else -- not billing
3003
3004 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ASSIGNING PROJECTED RATE ');
3005 l_annualized_rate := p_loan_details.TERM_PROJECTED_INTEREST_RATE;
3006
3007 end if; -- billing
3008
3009 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': converting rate for floating loan ');
3010 -- recalculate calculatePayment amount
3011 -- payment is based on original amortized portion of loan
3012 -- make sure to pass correct rate id back to billing
3013 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': assigning RATE_ID ' || l_rate_details.rate_id);
3014 l_current_rate_id := l_rate_details.rate_id;
3015
3016 end if; -- recalculate rate
3017
3018 end if; -- rate_type and / or float
3019
3020 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id ' || l_current_rate_id);
3021 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag ' || l_interest_only_flag);
3022 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized ' || l_previous_annualized);
3023 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate ' || l_annualized_rate);
3024 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed ' || l_last_installment_billed);
3025 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin ' || l_hidden_periodic_prin);
3026 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment ' || l_extend_from_installment);
3027
3028 -- conditions to recalculate principal payment
3029 -- 1. 1-st installment
3030 -- 2. reamortization from installment = current installment
3031 -- 3. reamortize because loan term has been extended
3032 -- 4. hidden_periodic_prin = 0
3033
3034 if ((l_installment_number = 1) OR
3035 (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
3036 (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
3037 (l_hidden_periodic_prin = 0 and (l_last_installment_billed + 1 = l_installment_number)))
3038 then
3039
3040 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- calculating periodic principal payment');
3041
3042 l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number) + l_prin_intervals_diff;
3043 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_num_prin_payments=' || l_num_prin_payments);
3044
3045 if l_installment_number = 1 and l_reamortize_from_installment is null then
3046 l_remaining_balance := l_original_loan_amount;
3047 else
3048 l_remaining_balance := l_remaining_balance_theory;
3049 end if;
3050
3051 l_hidden_periodic_prin := lns_financials.calculateEPPayment(p_loan_amount => l_remaining_balance
3052 ,p_num_intervals => l_num_prin_payments
3053 ,p_ending_balance=> l_balloon_amount
3054 ,p_pay_in_arrears=> l_prin_pay_in_arrears);
3055
3056 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic principal payment is ' || l_hidden_periodic_prin);
3057
3058 else
3059 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': INHERIT principal payment is ' || l_hidden_periodic_prin);
3060 end if;
3061
3062 l_previous_rate_id := l_current_rate_id;
3063 l_previous_annualized := l_annualized_rate;
3064
3065 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_interest = ' || l_hidden_cumul_interest);
3066 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_norm_int = ' || l_hidden_cumul_norm_int);
3067 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_prin_int = ' || l_hidden_cumul_add_prin_int);
3068 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_int_int = ' || l_hidden_cumul_add_int_int);
3069
3070 l_norm_interest := 0;
3071 l_add_prin_interest := 0;
3072 l_add_int_interest := 0;
3073 l_penal_prin_interest := 0;
3074 l_penal_int_interest := 0;
3075 l_penal_interest := 0;
3076 l_interest := 0;
3077
3078 -- now we will calculate the interest due for this period
3079 if p_based_on_terms = 'CURRENT' and
3080 l_installment_number >= l_start_installment and
3081 l_installment_number <= l_end_installment
3082 then
3083
3084 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
3085 l_norm_interest := LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
3086 p_calc_method => l_calc_method,
3087 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3088 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
3089 p_interest_rate => l_annualized_rate,
3090 p_day_count_method => l_day_count_method,
3091 p_payment_freq => l_payment_frequency,
3092 p_compound_freq => l_compound_freq);
3093
3094 l_norm_interest := round(l_norm_interest, l_precision);
3095
3096 if (l_installment_number-1) >= 0 then
3097
3098 -- get additional interest start date
3099 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
3100 fetch c_get_last_bill_date into l_add_start_date;
3101 close c_get_last_bill_date;
3102
3103 -- get additional interest end date
3104 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
3105 l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
3106 else
3107 l_add_end_date := sysdate;
3108 end if;
3109
3110 if (l_installment_number-1) > 0 then
3111 l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
3112 else
3113 l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
3114 end if;
3115
3116 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
3117 -- calculate additional interest on unpaid principal
3118 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
3119 p_calc_method => l_calc_method,
3120 p_period_start_date => l_add_start_date,
3121 p_period_end_date => l_add_end_date,
3122 p_interest_rate => l_annualized_rate,
3123 p_day_count_method => l_day_count_method,
3124 p_payment_freq => l_payment_frequency,
3125 p_compound_freq => l_compound_freq,
3126 p_prev_grace_end_date => l_prev_grace_end_date,
3127 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
3128 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3129 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
3130 p_target => 'UNPAID_PRIN',
3131 x_add_interest => l_add_prin_interest,
3132 x_penal_interest => l_penal_prin_interest);
3133 l_add_prin_interest := round(l_add_prin_interest, l_precision);
3134
3135 if (l_calc_method = 'COMPOUND') then
3136
3137 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
3138 -- calculate additional interest on unpaid interest
3139 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
3140 p_calc_method => l_calc_method,
3141 p_period_start_date => l_add_start_date,
3142 p_period_end_date => l_add_end_date,
3143 p_interest_rate => l_annualized_rate,
3144 p_day_count_method => l_day_count_method,
3145 p_payment_freq => l_payment_frequency,
3146 p_compound_freq => l_compound_freq,
3147 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
3148 p_prev_grace_end_date => l_prev_grace_end_date,
3149 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3150 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
3151 p_target => 'UNPAID_INT',
3152 x_add_interest => l_add_int_interest,
3153 x_penal_interest => l_penal_int_interest);
3154 l_add_int_interest := round(l_add_int_interest, l_precision);
3155
3156 end if;
3157
3158 end if;
3159
3160 elsif p_based_on_terms = 'CURRENT' and l_installment_number < l_start_installment then
3161
3162 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': DONT NEED TO CALCULATE INTEREST');
3163
3164 else
3165
3166 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_actual);
3167
3168 if (l_calc_method = 'SIMPLE') then
3169
3170 -- recalculate periodic rate for each period if day counting methodolgy varies
3171 l_periodic_rate := lns_financials.getPeriodicRate(
3172 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3173 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3174 ,p_annualized_rate => l_annualized_rate
3175 ,p_days_count_method => l_day_count_method);
3176
3177 elsif (l_calc_method = 'COMPOUND') then
3178
3179 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
3180 ,p_payment_freq => l_payment_frequency
3181 ,p_annualized_rate => l_annualized_rate
3182 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3183 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3184 ,p_days_count_method => l_day_count_method);
3185
3186 end if;
3187
3188 l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_actual
3189 ,p_periodic_rate => l_periodic_rate
3190 ,p_compounding_period => null);
3191 l_norm_interest := round(l_norm_interest, l_precision);
3192 end if;
3193
3194 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
3195 l_interest := l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest;
3196 l_hidden_cumul_norm_int := l_hidden_cumul_norm_int + l_norm_interest;
3197 l_hidden_cumul_add_prin_int := l_hidden_cumul_add_prin_int + l_add_prin_interest;
3198 l_hidden_cumul_add_int_int := l_hidden_cumul_add_int_int + l_add_int_interest;
3199 l_hidden_cumul_interest := l_hidden_cumul_interest + l_interest;
3200 l_hidden_cumul_penal_int := l_hidden_cumul_penal_int + l_penal_interest;
3201
3202 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_norm_interest = ' || l_norm_interest);
3203 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_prin_interest = ' || l_add_prin_interest);
3204 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_interest = ' || l_add_int_interest);
3205 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
3206 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest = ' || l_interest);
3207 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest = ' || l_interest);
3208
3209 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CONTENTS = ' || l_payment_tbl(l_installment_number).CONTENTS);
3210
3211 if (l_payment_tbl(l_installment_number).CONTENTS = 'PRIN') then
3212
3213 l_periodic_interest := 0;
3214 l_periodic_norm_int := 0;
3215 l_periodic_add_prin_int := 0;
3216 l_periodic_add_int_int := 0;
3217 l_periodic_penal_int := 0;
3218
3219 l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number);
3220
3221 if l_remaining_balance_theory < l_hidden_periodic_prin then
3222 l_periodic_principal := l_remaining_balance_theory;
3223 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3224 else
3225 if (l_num_prin_payments = 1) then
3226 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
3227 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal is ' || l_unbilled_principal);
3228 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory is ' || l_remaining_balance_theory);
3229 if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
3230 l_periodic_principal := l_unbilled_principal;
3231 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
3232 else
3233 l_periodic_principal := l_remaining_balance_theory;
3234 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3235 end if;
3236 else
3237 l_periodic_principal := l_hidden_periodic_prin;
3238 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_hidden_periodic_prin');
3239 end if;
3240 end if;
3241
3242 elsif (l_payment_tbl(l_installment_number).CONTENTS = 'INT') then
3243
3244 l_periodic_interest := l_hidden_cumul_interest;
3245 l_periodic_norm_int := l_hidden_cumul_norm_int;
3246 l_periodic_add_prin_int := l_hidden_cumul_add_prin_int;
3247 l_periodic_add_int_int := l_hidden_cumul_add_int_int;
3248 l_periodic_penal_int := l_hidden_cumul_penal_int;
3249 l_hidden_cumul_interest := 0;
3250 l_hidden_cumul_norm_int := 0;
3251 l_hidden_cumul_add_prin_int := 0;
3252 l_hidden_cumul_add_int_int := 0;
3253 l_hidden_cumul_penal_int := 0;
3254 l_periodic_principal := 0;
3255
3256 else
3257
3258 l_periodic_interest := l_hidden_cumul_interest;
3259 l_periodic_norm_int := l_hidden_cumul_norm_int;
3260 l_periodic_add_prin_int := l_hidden_cumul_add_prin_int;
3261 l_periodic_add_int_int := l_hidden_cumul_add_int_int;
3262 l_periodic_penal_int := l_hidden_cumul_penal_int;
3263 l_hidden_cumul_interest := 0;
3264 l_hidden_cumul_norm_int := 0;
3265 l_hidden_cumul_add_prin_int := 0;
3266 l_hidden_cumul_add_int_int := 0;
3267 l_hidden_cumul_penal_int := 0;
3268
3269 l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number);
3270
3271 if l_remaining_balance_theory < l_hidden_periodic_prin then
3272 l_periodic_principal := l_remaining_balance_theory;
3273 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3274 else
3275 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
3276 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal is ' || l_unbilled_principal);
3277 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory is ' || l_remaining_balance_theory);
3278 if (l_num_prin_payments = 1) then
3279 if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
3280 l_periodic_principal := l_unbilled_principal;
3281 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
3282 else
3283 l_periodic_principal := l_remaining_balance_theory;
3284 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3285 end if;
3286 else
3287 l_periodic_principal := l_hidden_periodic_prin;
3288 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_hidden_periodic_prin');
3289 end if;
3290 end if;
3291
3292 end if;
3293
3294 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_norm_int = ' || l_hidden_cumul_norm_int);
3295 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_prin_int = ' || l_hidden_cumul_add_prin_int);
3296 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_int_int = ' || l_hidden_cumul_add_int_int);
3297 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_interest = ' || l_hidden_cumul_interest);
3298 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_penal_int = ' || l_hidden_cumul_penal_int);
3299 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
3300
3301 -- round int and prin and calc total
3302 l_periodic_principal := round(l_periodic_principal, l_precision);
3303 l_periodic_interest := round(l_periodic_interest, l_precision);
3304 l_periodic_payment := l_periodic_principal + l_periodic_interest;
3305
3306 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': principal is ' || l_periodic_principal);
3307 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is ' || l_periodic_interest);
3308 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': total is ' || l_periodic_payment);
3309
3310 -- calculate balances and total payment
3311 l_begin_balance := l_remaining_balance_theory;
3312 l_end_balance := l_remaining_balance_theory - l_periodic_principal;
3313
3314 -- check to see if this loan has been billed
3315 if l_unbilled_principal > 0 then
3316 l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
3317 end if;
3318
3319 -- build the amortization record
3320 -- this information is needed to calculate fees
3321 -- rest of the record can be built after fees are calculated
3322 l_amortization_rec.installment_number := l_installment_number; /* needed to calculate fees */
3323 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
3324 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
3325 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
3326 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
3327 l_amortization_rec.interest_amount := l_periodic_interest;
3328 l_amortization_rec.begin_balance := l_begin_balance; /* needed to calculate fees */
3329 l_amortization_rec.end_balance := l_end_balance;
3330 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
3331 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
3332 l_amortization_rec.INTEREST_RATE := l_annualized_rate;
3333 l_amortization_rec.NORMAL_INT_AMOUNT := l_periodic_norm_int;
3334 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_periodic_add_prin_int;
3335 l_amortization_rec.ADD_INT_INT_AMOUNT := l_periodic_add_int_int;
3336 l_amortization_rec.PENAL_INT_AMOUNT := l_periodic_penal_int;
3337
3338 -- calculate fees here
3339 -- should be new routine to simply get the fees from the fee schedule
3340 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
3341 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance;
3342 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
3343 l_fee_basis_tbl(2).fee_basis_amount := l_original_loan_amount;
3344
3345 if l_installment_number = 1 then
3346 if l_orig_fee_structures.count > 0 then
3347
3348 -- fix for bug 7207609
3349 open c_fees(l_loan_id, l_installment_number);
3350 fetch c_fees into l_fee_amount;
3351 close c_fees;
3352 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
3353 /*
3354 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
3355 ,p_installment => l_installment_number
3356 ,p_fee_basis_tbl => l_fee_basis_tbl
3357 ,p_fee_structures => l_orig_fee_structures
3358 ,x_fees_tbl => l_orig_fees_tbl
3359 ,x_return_status => l_return_status
3360 ,x_msg_count => l_msg_count
3361 ,x_msg_data => l_msg_data);
3362 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated origination fees ' || l_orig_fee_structures.count);
3363 */
3364 -- l_other_amount := lns_fee_engine.calculateFees(p_amortization_rec => l_amortization_rec
3365 -- ,p_fee_structures => l_memo_fee_structures);
3366 end if;
3367 end if;
3368
3369 if l_memo_fee_structures.count > 0 then
3370 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
3371 ,p_installment => l_installment_number
3372 ,p_fee_basis_tbl => l_fee_basis_tbl
3373 ,p_fee_structures => l_memo_fee_structures
3374 ,x_fees_tbl => l_memo_fees_tbl
3375 ,x_return_status => l_return_status
3376 ,x_msg_count => l_msg_count
3377 ,x_msg_data => l_msg_data);
3378 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated memo fees ' || l_memo_fees_tbl.count);
3379
3380 -- l_other_amount := lns_fee_engine.calculateFees(p_amortization_rec => l_amortization_rec
3381 -- ,p_fee_structures => l_memo_fee_structures);
3382 end if;
3383
3384
3385 if l_fee_structures.count > 0 then
3386 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
3387 ,p_installment => l_installment_number
3388 ,p_fee_basis_tbl => l_fee_basis_tbl
3389 ,p_fee_structures => l_fee_structures
3390 ,x_fees_tbl => l_fees_tbl
3391 ,x_return_status => l_return_status
3392 ,x_msg_count => l_msg_count
3393 ,x_msg_data => l_msg_data);
3394 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated fees ' || l_fees_tbl.count);
3395
3396 -- l_fee_amount := lns_fee_engine.calculateFees(p_amortization_rec => l_amortization_rec
3397 -- ,p_fee_structures => l_fee_structures);
3398 end if;
3399 /*
3400 for i in 1..l_orig_fees_tbl.count loop
3401 l_fee_amount := l_fee_amount + l_orig_fees_tbl(i).FEE_AMOUNT;
3402 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
3403 end loop;
3404 */
3405 for k in 1..l_fees_tbl.count loop
3406 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
3407 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': recurring calculated fees ' || l_fee_amount);
3408 end loop;
3409
3410 for j in 1..l_memo_fees_tbl.count loop
3411 l_other_amount := l_other_amount + l_memo_fees_tbl(j).FEE_AMOUNT;
3412 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': other calculated fees ' || l_other_amount);
3413 end loop;
3414
3415 l_total := l_fee_amount + l_periodic_principal + l_periodic_interest + l_other_amount;
3416 l_amortization_rec.total := l_total;
3417 l_amortization_rec.fee_amount := l_fee_amount;
3418 l_amortization_rec.other_amount := l_other_amount;
3419
3420 -- running totals calculated here
3421 l_principal_cumulative := l_principal_cumulative + l_periodic_principal;
3422 l_interest_cumulative := l_interest_cumulative + l_periodic_interest;
3423 l_fees_cumulative := l_fees_cumulative + l_fee_amount;
3424 l_other_cumulative := l_other_cumulative + l_other_amount;
3425
3426 l_amortization_rec.interest_cumulative := l_interest_cumulative;
3427 l_amortization_rec.principal_cumulative := l_principal_cumulative;
3428 l_amortization_rec.fees_cumulative := l_fees_cumulative;
3429 l_amortization_rec.other_cumulative := l_other_cumulative;
3430 l_amortization_rec.rate_id := l_current_rate_id;
3431 l_amortization_rec.SOURCE := 'PREDICTED';
3432
3433 -- add the record to the amortization table
3434 l_amortization_tbl(i) := l_amortization_rec;
3435
3436 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: due date ' || l_amortization_rec.due_date);
3437 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_principal ' || l_amortization_rec.principal_amount);
3438 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_interest ' || l_amortization_rec.interest_amount);
3439 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fee_amount is ' || l_amortization_rec.fee_amount);
3440 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: other_amount is ' || l_amortization_rec.other_amount);
3441 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: total is ' || l_amortization_rec.total);
3442 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: begin_balance is ' || l_amortization_rec.begin_balance);
3443 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: end_balance is ' || l_amortization_rec.end_balance);
3444 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: interest_cumulative is ' || l_amortization_rec.interest_cumulative);
3445 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: principal_cumulative is ' || l_amortization_rec.principal_cumulative);
3446 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fees_cumulative is ' || l_amortization_rec.fees_cumulative);
3447 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: other_cumulative is ' || l_amortization_rec.other_cumulative);
3448 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: current_rate_id is ' || l_amortization_rec.rate_id );
3449
3450 -- adjust new loan amount to reflect less periodic principal paid
3451 -- theoretically without over/underpayments l_loan_amount should = l_remaining_balance
3452 -- if they diverge then we will calculate interest based from l_remaining_balance
3453 -- rather than l_loan_amount
3454 l_remaining_balance_theory := l_end_balance;
3455
3456 -- for next installment to bill: calculate interest based on real situation including unpaid amounts
3457 -- for all other installments: project ideal schedule (meaning that all unpaid amounts are paid)
3458 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number)
3459 and p_based_on_terms = 'CURRENT' then
3460 l_remaining_balance_actual := l_remaining_balance_theory;
3461 else
3462 l_remaining_balance_actual := l_remaining_balance_actual - l_periodic_principal;
3463 end if;
3464
3465 -- clean up
3466 l_orig_fees_tbl.delete;
3467 l_memo_fees_tbl.delete;
3468 l_fees_tbl.delete;
3469
3470 end loop;
3471
3472 --printAmortizationTable(p_amort_tbl => l_amortization_tbl);
3473
3474 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT IS ' || l_amortization_tbl.count);
3475 x_loan_amort_tbl := l_amortization_tbl;
3476
3477 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
3478
3479 Exception
3480 WHEN FND_API.G_EXC_ERROR THEN
3481 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
3482
3483 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
3484 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
3485
3486 WHEN OTHERS THEN
3487 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
3488
3489 end amortizeSIPLoan;
3490
3491
3492
3493 /*=========================================================================
3494 || PUBLIC PROCEDURE amortizeEPLoan
3495 ||
3496 || DESCRIPTION
3497 ||
3498 || Overview: this is the main calculation API for EP amortization
3499 || THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
3500 || 1. Amortization UI - when creating a loan
3501 || 2. Billing Engine - to generate installment bills
3502 ||
3503 || Parameter: p_loan_details = details of the loan
3504 || p_rate_schedule = rate schedule for the loan
3505 || p_installment_number => billing will pass in an installment
3506 || number to generate a billt
3507 || x_loan_amort_tbl => table of amortization records
3508 ||
3509 || Source Tables: NA
3510 ||
3511 || Target Tables: LNS_TEMP_AMORTIZATIONS
3512 ||
3513 ||
3514 || KNOWN ISSUES
3515 ||
3516 || NOTES
3517 ||
3518 || MODIFICATION HISTORY
3519 |
3520 | Date Author Description of Changes
3521 || 09/13/2007 scherkas Created
3522 || 16/01/2008 scherkas Fixed bug 6749924
3523 *=======================================================================*/
3524 procedure amortizeEPLoan(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
3525 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
3526 ,p_based_on_terms in varchar2
3527 ,p_installment_number in number
3528 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
3529 is
3530 l_return_status varchar2(1);
3531 l_msg_count NUMBER;
3532 l_msg_data VARCHAR2(32767);
3533 -- loan_details
3534 l_loan_id number;
3535 l_original_loan_amount number; -- loan amount
3536 l_amortized_term number;
3537 l_amortized_term_period varchar2(30);
3538 l_amortization_frequency varchar2(30);
3539 l_loan_period_number number;
3540 l_loan_period_type varchar2(30);
3541 l_first_payment_date date;
3542 l_pay_in_arrears boolean;
3543 l_payment_frequency varchar2(30);
3544 l_day_count_method varchar2(30);
3545 l_interest_comp_freq varchar2(30);
3546 l_calculation_method varchar2(30);
3547 l_reamortize_from_installment number;
3548 l_reamortize_amount number;
3549 l_annualized_rate number; -- annual rate on the loan
3550 l_intervals_original number;
3551 l_intervals number;
3552 l_intervals_remaining number;
3553 l_amortization_intervals_orig number;
3554 l_amortization_intervals_rem number;
3555 l_amortization_intervals number; -- number of intervals to amortize over
3556 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
3557 l_current_rate_id number;
3558 l_previous_rate_id number;
3559 l_precision number;
3560
3561 l_period_start_Date date;
3562 l_period_end_date date;
3563 l_periodic_rate number;
3564 l_maturity_date date;
3565
3566 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
3567 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
3568 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
3569 --l_pay_dates LNS_FINANCIALS.DATE_TBL;
3570 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
3571 l_loan_start_date date;
3572 l_num_pay_dates number; -- number of dates on installment schedule
3573 l_periodic_payment number;
3574 l_periodic_principal number;
3575 l_periodic_interest number;
3576 l_interest_based_on_amount number; -- do we calculate interest from actual or predicted remaining balance
3577 l_pay_date date;
3578 l_total_principal number;
3579 l_payment_number number;
3580 l_fee_amount number;
3581 l_fee_amount1 number;
3582 l_other_amount number;
3583 l_begin_balance number;
3584 l_end_balance number;
3585 l_unbilled_principal number;
3586 l_unpaid_principal number;
3587 l_unpaid_interest number;
3588
3589 l_remaining_balance_actual number;
3590 l_remaining_balance_theory number;
3591 l_total number;
3592 l_interest_cumulative number;
3593 l_principal_cumulative number;
3594 l_fees_cumulative number;
3595 l_other_cumulative number;
3596 i number;
3597 l_installment_number number;
3598 l_billing boolean; -- switch to notify if billing is calling API
3599 l_api_name varchar2(20);
3600 l_last_installment_billed number;
3601 l_rate_to_calculate number;
3602 l_previous_annualized number;
3603 l_previous_interest_only_flag varchar2(1);
3604 l_interest_only_flag varchar2(1);
3605 l_calc_method varchar2(30);
3606 l_compound_freq varchar2(30);
3607 l_non_ro_intervals number;
3608 l_prev_periodic_principal number;
3609 -- l_calc_from_amount number;
3610 l_intervals_diff number;
3611 l_remaining_balance_actual1 number;
3612 l_extend_from_installment number;
3613 l_force_reamortization boolean;
3614 l_orig_num_install number;
3615 l_first_installment_billed number;
3616 l_begin number;
3617 l_norm_interest number;
3618 l_add_prin_interest number;
3619 l_add_int_interest number;
3620 l_add_start_date date;
3621 l_add_end_date date;
3622 l_penal_prin_interest number;
3623 l_penal_int_interest number;
3624 l_penal_interest number;
3625 l_prev_grace_end_date date;
3626 l_raw_rate number;
3627 l_balloon_amount number;
3628 l_remaining_balance number;
3629
3630 -- for fees
3631 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
3632 l_memo_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
3633 l_orig_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
3634 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
3635 l_memo_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
3636 l_orig_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
3637 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
3638 l_conv_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
3639
3640 -- total fees on the schedule by installment
3641 cursor c_fees(p_loan_id number, p_installment number) is
3642 select nvl(sum(sched.fee_amount), 0)
3643 from lns_fee_schedules sched
3644 ,lns_fees struct
3645 where sched.loan_id = p_loan_id
3646 and sched.fee_id = struct.fee_id
3647 and struct.fee_type = 'EVENT_ORIGINATION'
3648 and fee_installment = p_installment
3649 and active_flag = 'Y';
3650
3651 cursor c_conv_fees(p_loan_id number) is
3652 select nvl(sum(fee),0)
3653 from lns_fee_assignments
3654 where loan_id = p_loan_id
3655 and fee_type = 'EVENT_CONVERSION';
3656
3657 -- get last bill date
3658 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
3659 select ACTIVITY_DATE
3660 from LNS_PRIN_TRX_ACTIVITIES_V
3661 where loan_id = p_loan_id
3662 and PAYMENT_NUMBER = p_installment_number
3663 and PARENT_AMORTIZATION_ID is null
3664 and ACTIVITY_CODE in ('BILLING', 'START');
3665
3666 -- get last billed payment info
3667 cursor c_get_last_payment(p_loan_id number, p_installment_number number) is
3668 select PRINCIPAL_AMOUNT
3669 from lns_amortization_scheds
3670 where loan_id = p_loan_id
3671 and PAYMENT_NUMBER > 0
3672 and PAYMENT_NUMBER <= p_installment_number
3673 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
3674 and PARENT_AMORTIZATION_ID is null
3675 and PRINCIPAL_AMOUNT > 0
3676 and nvl(PHASE, 'TERM') = 'TERM'
3677 order by PAYMENT_NUMBER desc;
3678
3679 -- get first billed installment number
3680 cursor c_first_billed_instal(p_loan_id number) is
3681 select min(PAYMENT_NUMBER)
3682 from LNS_AMORTIZATION_SCHEDS
3683 where loan_id = p_loan_id
3684 and PAYMENT_NUMBER > 0
3685 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
3686 and PARENT_AMORTIZATION_ID is null
3687 and nvl(PHASE, 'TERM') = 'TERM';
3688
3689 begin
3690
3691 -- initialize all variables
3692 l_original_loan_amount := 0; -- loan amount
3693 l_loan_period_number := 0;
3694 l_previous_rate_id := -1;
3695 l_previous_annualized := -1;
3696 l_previous_interest_only_flag := 'N'; -- default to regular interest + principal
3697 l_periodic_payment := 0;
3698 l_periodic_principal := 0;
3699 l_periodic_interest := 0;
3700 l_balloon_amount := 0;
3701 l_total_principal := 0;
3702 l_payment_number := 0;
3703 l_fee_amount := 0;
3704 l_other_amount := 0;
3705 l_begin_balance := 0;
3706 l_unbilled_principal := 0;
3707 l_unpaid_principal := 0;
3708 l_remaining_balance_actual := 0;
3709 l_remaining_balance_theory := 0;
3710 l_total := 0;
3711 l_interest_cumulative := 0;
3712 l_principal_cumulative := 0;
3713 l_fees_cumulative := 0;
3714 l_other_cumulative := 0;
3715 i := 0;
3716 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
3717 l_rate_to_calculate := 0;
3718 l_billing := false; -- switch to notify if billing is calling API
3719 l_api_name := 'amortizeEPLoan MAIN';
3720
3721 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
3722 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
3723 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
3724
3725 l_amortized_term := p_loan_details.amortized_term;
3726 l_amortized_term_period := p_loan_details.amortized_term_period;
3727 l_amortization_frequency := p_loan_details.amortization_frequency;
3728 l_payment_frequency := p_loan_details.payment_frequency;
3729 l_first_payment_date := p_loan_details.first_payment_date;
3730 l_original_loan_amount := p_loan_details.requested_amount; --funded_amount;
3731 l_remaining_balance_actual := p_loan_details.remaining_balance;
3732 l_remaining_balance_actual1 := p_loan_details.remaining_balance;
3733 l_maturity_date := p_loan_details.maturity_date;
3734 l_intervals := p_loan_details.number_installments;
3735 l_intervals_original := p_loan_details.number_installments;
3736 l_amortization_intervals_orig := p_loan_details.num_amortization_intervals;
3737 l_amortization_intervals := p_loan_details.num_amortization_intervals;
3738 l_amortization_intervals_rem := p_loan_details.num_amortization_intervals;
3739 l_balloon_amount := p_loan_details.balloon_payment_amount;
3740 l_last_installment_billed := p_loan_details.last_installment_billed;
3741 l_day_count_method := p_loan_details.day_count_method;
3742 l_loan_start_date := p_loan_details.loan_start_date;
3743 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
3744 l_precision := p_loan_details.currency_precision;
3745 l_reamortize_from_installment := p_loan_details.reamortize_from_installment;
3746 l_reamortize_amount := p_loan_details.reamortize_amount;
3747 l_loan_id := p_loan_details.loan_id;
3748 l_calc_method := p_loan_details.CALCULATION_METHOD;
3749 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
3750 l_intervals_diff := l_amortization_intervals_orig - l_intervals_original;
3751 l_extend_from_installment := p_loan_details.EXTEND_FROM_INSTALLMENT;
3752 l_orig_num_install := p_loan_details.ORIG_NUMBER_INSTALLMENTS;
3753
3754 -- get the interest rate schedule
3755 l_rate_tbl := p_rate_schedule;
3756 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count: ' || l_rate_tbl.count);
3757
3758 -- get payment schedule
3759 -- this will return the acutal dates that payments will be due on
3760 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
3761 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
3762 ,p_loan_maturity_date => l_maturity_date
3763 ,p_first_pay_date => l_first_payment_date
3764 ,p_num_intervals => l_intervals
3765 ,p_interval_type => l_payment_frequency
3766 ,p_pay_in_arrears => l_pay_in_arrears);
3767
3768 l_num_pay_dates := l_payment_tbl.count;
3769 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count: ' || l_num_pay_dates);
3770
3771 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting conv fee structures');
3772 l_conv_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
3773 ,p_fee_category => 'EVENT'
3774 ,p_fee_type => 'EVENT_CONVERSION'
3775 ,p_installment => null
3776 ,p_fee_id => null);
3777 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': conv structures count is ' || l_conv_fee_structures.count);
3778
3779 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting origination fee structures');
3780 l_orig_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
3781 ,p_fee_category => 'EVENT'
3782 ,p_fee_type => 'EVENT_ORIGINATION'
3783 ,p_installment => null
3784 ,p_fee_id => null);
3785 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig structures count is ' || l_orig_fee_structures.count);
3786
3787 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting recurring fee structures');
3788 l_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
3789 ,p_fee_category => 'RECUR'
3790 ,p_fee_type => null
3791 ,p_installment => null
3792 ,p_fee_id => null);
3793 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': fee structures count is ' || l_fee_structures.count);
3794
3795 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting memo fee structures');
3796 l_memo_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
3797 ,p_fee_category => 'MEMO'
3798 ,p_fee_type => null
3799 ,p_installment => null
3800 ,p_fee_id => null);
3801 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': memo fee structures count is ' || l_memo_fee_structures.count);
3802
3803 -- 2-24-2005 raverma add 0 installment to amortization schedule
3804 if l_orig_fee_structures.count > 0 or l_conv_fee_structures.count > 0 then
3805
3806 open c_fees(l_loan_id, 0);
3807 fetch c_fees into l_fee_amount1;
3808 close c_fees;
3809 l_fee_amount := l_fee_amount1;
3810
3811 open c_conv_fees(l_loan_id);
3812 fetch c_conv_fees into l_fee_amount1;
3813 close c_conv_fees;
3814 l_fee_amount := l_fee_amount1 + l_fee_amount;
3815
3816 if l_fee_amount > 0 then
3817 i := i + 1;
3818 l_amortization_rec.installment_number := 0;
3819 l_amortization_rec.due_date := l_loan_start_date;
3820 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
3821 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
3822 l_amortization_rec.principal_amount := 0;
3823 l_amortization_rec.interest_amount := 0;
3824 l_amortization_rec.fee_amount := l_fee_amount;
3825 l_amortization_rec.other_amount := 0;
3826 l_amortization_rec.begin_balance := l_original_loan_amount;
3827 l_amortization_rec.end_balance := l_original_loan_amount;
3828 l_amortization_rec.interest_cumulative := 0;
3829 l_amortization_rec.principal_cumulative := 0;
3830 l_amortization_rec.fees_cumulative := l_fee_amount;
3831 l_amortization_rec.other_cumulative := 0;
3832 l_amortization_rec.rate_id := 0;
3833 l_amortization_rec.SOURCE := 'PREDICTED';
3834 -- add the record to the amortization table
3835 l_amortization_rec.total := l_fee_amount;
3836 l_amortization_rec.UNPAID_PRIN := 0;
3837 l_amortization_rec.UNPAID_INT := 0;
3838 l_amortization_rec.INTEREST_RATE := 0;
3839 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
3840 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
3841 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
3842 l_amortization_rec.PENAL_INT_AMOUNT := 0;
3843 l_amortization_tbl(i) := l_amortization_rec;
3844 end if;
3845
3846 --l_orig_fees_tbl.delete;
3847 l_fee_amount := 0;
3848
3849 end if;
3850
3851 -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
3852 l_remaining_balance_theory := l_original_loan_amount;
3853 if p_installment_number is not null then
3854
3855 l_billing := true;
3856 if p_installment_number > 0 then
3857
3858 if p_installment_number > l_num_pay_dates then
3859 l_payment_number := l_num_pay_dates;
3860 else
3861 l_payment_number := p_installment_number;
3862 end if;
3863
3864 else
3865 i := i + 1;
3866 -- special we are on the 0th installment
3867 l_amortization_rec.installment_number := 0;
3868 l_amortization_rec.due_date := l_loan_start_date;
3869 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
3870 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
3871 l_amortization_rec.principal_amount := l_periodic_principal;
3872 l_amortization_rec.interest_amount := l_periodic_interest;
3873 l_amortization_rec.fee_amount := l_fee_amount;
3874 l_amortization_rec.begin_balance := l_remaining_balance_actual;
3875 l_amortization_rec.end_balance := l_remaining_balance_actual;
3876 l_amortization_rec.interest_cumulative := l_interest_cumulative;
3877 l_amortization_rec.principal_cumulative := l_principal_cumulative;
3878 l_amortization_rec.fees_cumulative := l_fees_cumulative + l_fee_amount;
3879 l_amortization_rec.other_cumulative := l_other_cumulative;
3880 l_amortization_rec.rate_id := l_current_rate_id;
3881 l_amortization_rec.UNPAID_PRIN := 0;
3882 l_amortization_rec.UNPAID_INT := 0;
3883 l_amortization_rec.INTEREST_RATE := 0;
3884 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
3885 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
3886 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
3887 l_amortization_rec.PENAL_INT_AMOUNT := 0;
3888 -- add the record to the amortization table
3889 l_amortization_tbl(i) := l_amortization_rec;
3890
3891 end if;
3892
3893 else
3894
3895 l_payment_number := l_num_pay_dates;
3896
3897 end if;
3898
3899 l_remaining_balance_actual := l_original_loan_amount;
3900 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
3901 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
3902
3903 l_begin := 1;
3904
3905 if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
3906
3907 open c_first_billed_instal(l_loan_id);
3908 fetch c_first_billed_instal into l_first_installment_billed;
3909 close c_first_billed_instal;
3910 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_first_installment_billed = ' || l_first_installment_billed);
3911
3912 if l_first_installment_billed < l_last_installment_billed then
3913 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_last_installment_billed || '-----');
3914 open c_get_last_payment(l_loan_id, l_last_installment_billed);
3915 fetch c_get_last_payment into l_periodic_principal;
3916 close c_get_last_payment;
3917
3918 if l_periodic_principal is null then
3919 l_periodic_principal := 0;
3920 end if;
3921 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Last periodic principal = ' || l_periodic_principal);
3922
3923 l_prev_periodic_principal := l_periodic_principal;
3924 l_begin := l_last_installment_billed + 1;
3925
3926
3927 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
3928 l_rate_details := getRateDetails(p_installment => l_last_installment_billed
3929 ,p_rate_tbl => l_rate_tbl);
3930
3931 if p_loan_details.rate_type = 'FIXED' OR (p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'N')
3932 then
3933
3934 if l_rate_tbl.count = 1 then
3935 l_previous_annualized := l_rate_tbl(1).annual_rate;
3936 l_previous_interest_only_flag := l_rate_tbl(1).interest_only_flag;
3937 else
3938 l_previous_annualized := l_rate_details.annual_rate;
3939 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
3940 end if;
3941
3942 elsif p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'Y' then
3943
3944 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
3945 l_rate_details.ANNUAL_RATE := lns_fin_utils.getRateForDate(p_loan_details.OPEN_INDEX_RATE_ID
3946 ,l_payment_tbl(l_last_installment_billed).period_begin_date);
3947
3948 l_raw_rate := l_rate_details.ANNUAL_RATE + l_rate_details.spread;
3949 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_raw_rate ' || l_raw_rate);
3950
3951 -- adjust the rate as per rate rules
3952 l_previous_annualized := calculateInterestRate(p_initial_rate => p_loan_details.INITIAL_INTEREST_RATE
3953 ,p_rate_to_compare => l_raw_rate
3954 ,p_last_period_rate => p_loan_details.LAST_INTEREST_RATE
3955 ,p_max_first_adjustment => p_loan_details.TERM_FIRST_PERCENT_INCREASE
3956 ,p_max_period_adjustment => p_loan_details.TERM_ADJ_PERCENT_INCREASE
3957 ,p_max_lifetime_adjustment => p_loan_details.TERM_LIFE_PERCENT_INCREASE
3958 ,p_ceiling_rate => p_loan_details.TERM_CEILING_RATE
3959 ,p_floor_rate => p_loan_details.TERM_FLOOR_RATE
3960 ,p_installment_number => l_last_installment_billed);
3961 end if;
3962 end if;
3963
3964 end if;
3965
3966 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_begin = ' || l_begin);
3967
3968 -- loop to build the amortization schedule
3969 for l_installment_number in l_begin..l_payment_number
3970 loop
3971
3972 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
3973 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || '-----');
3974
3975 i := i + 1;
3976 l_periodic_interest := 0;
3977 -- l_periodic_principal := 0;
3978 l_fee_amount := 0;
3979 l_other_amount := 0;
3980 l_unpaid_principal := 0;
3981 l_unpaid_interest := 0;
3982 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
3983
3984 -- this is the main check for calculating interest on actual balance not theoretical
3985 -- intercept and overwrite the remaining balance theory with remain balance actual
3986 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number)
3987 and p_based_on_terms = 'CURRENT' then
3988 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': BASED ON CURRENT TERMS FROM INSTALLMENT: ' || l_installment_number);
3989
3990 l_principal_cumulative := 0;
3991 l_interest_cumulative := 0;
3992 l_fees_cumulative := 0;
3993 l_other_cumulative := 0;
3994 -- get the unbilled / unpaid principal at this point in time i.e. for this installment
3995 l_unbilled_principal := p_loan_details.unbilled_principal;
3996 l_unpaid_principal := p_loan_details.unpaid_principal;
3997 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
3998
3999 -- bug #3811298
4000 if p_loan_details.loan_status <> 'PAIDOFF' then
4001 -- begin fix for bug# 6663848
4002 if (l_calc_method = 'SIMPLE') then
4003 l_remaining_balance_actual := l_remaining_balance_actual1;
4004 elsif (l_calc_method = 'COMPOUND') then
4005 l_remaining_balance_actual := l_remaining_balance_actual1 + l_unpaid_interest;
4006 end if;
4007 -- end fix for bug# 6663848
4008 l_remaining_balance_theory := l_remaining_balance_actual1 - l_unpaid_principal;
4009 else
4010 l_remaining_balance_actual := 0;
4011 l_remaining_balance_theory := 0;
4012 end if;
4013 end if;
4014
4015 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_actual: ' || l_remaining_balance_actual);
4016 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory: ' || l_remaining_balance_theory);
4017
4018 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
4019 l_rate_details := getRateDetails(p_installment => l_installment_number
4020 ,p_rate_tbl => l_rate_tbl);
4021
4022 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate ' || l_rate_details.annual_rate);
4023 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread ' || l_rate_details.spread);
4024 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id ' || l_rate_details.rate_id);
4025 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate floating_flag ' || l_rate_details.floating_flag);
4026
4027 l_current_rate_id := l_rate_details.rate_id;
4028 l_annualized_rate := l_rate_details.annual_rate;
4029 l_interest_only_flag := l_rate_details.interest_only_flag;
4030
4031 -- add in support here for floating rate loans
4032 if p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'Y' then
4033
4034 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING ');
4035 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': period_begin_date ' || l_payment_tbl(l_installment_number).period_begin_date);
4036 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
4037 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.NEXT_RATE_CHANGE_DATE ' || p_loan_details.NEXT_RATE_CHANGE_DATE);
4038 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.OPEN_INDEX_RATE_ID ' || p_loan_details.OPEN_INDEX_RATE_ID);
4039 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.INITIAL_INTEREST_RATE ' || p_loan_details.INITIAL_INTEREST_RATE);
4040 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
4041 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_FIRST_PERCENT_INCREASE ' || p_loan_details.TERM_FIRST_PERCENT_INCREASE);
4042 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_ADJ_PERCENT_INCREASE ' || p_loan_details.TERM_ADJ_PERCENT_INCREASE);
4043 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_LIFE_PERCENT_INCREASE ' || p_loan_details.TERM_LIFE_PERCENT_INCREASE);
4044 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_CEILING_RATE ' || p_loan_details.TERM_CEILING_RATE);
4045 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_FLOOR_RATE ' || p_loan_details.TERM_FLOOR_RATE);
4046
4047 -- if float and no rate then error;
4048 -- we only need to get the new rate if
4049 -- 1. no rate has ever been calculated (i.e. 1st installment)
4050 -- 2. the billing date is beyond the next_rate_change_date
4051 -- 3. make sure to add spread and abide by rate rules
4052 if l_payment_tbl(l_installment_number).period_begin_date < p_loan_details.NEXT_RATE_CHANGE_DATE and l_installment_number > 1 then
4053
4054 -- no need to recalculate interest, use current interest rate found on last installment
4055 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING NO RECALC');
4056
4057 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
4058 l_annualized_rate := p_loan_details.LAST_INTEREST_RATE + l_rate_details.spread;
4059
4060 --elsif l_installment_number = 1 OR l_payment_tbl(l_installment_number).period_begin_date >= p_loan_details.NEXT_RATE_CHANGE_DATE then
4061 else
4062
4063 if p_based_on_terms = 'CURRENT' then
4064
4065 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING RECALCULATE');
4066
4067 l_rate_details.ANNUAL_RATE := lns_fin_utils.getRateForDate(p_loan_details.OPEN_INDEX_RATE_ID
4068 ,l_payment_tbl(l_installment_number).period_begin_date);
4069
4070 -- raise error as rates does not exist
4071 if l_rate_details.ANNUAL_RATE is null then
4072 FND_MESSAGE.SET_NAME('LNS', 'LNS_RATES_ERROR');
4073 FND_MSG_PUB.ADD;
4074 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for INDEX_ID ' || p_loan_details.TERM_INDEX_RATE_ID);
4075 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for DATE ' || p_loan_details.NEXT_RATE_CHANGE_DATE);
4076 RAISE FND_API.G_EXC_ERROR;
4077 end if;
4078
4079 -- add the spread into the rate
4080 l_raw_rate := l_rate_details.ANNUAL_RATE + l_rate_details.spread;
4081 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_raw_rate ' || l_raw_rate);
4082
4083 -- adjust the rate as per rate rules
4084 l_annualized_rate := calculateInterestRate(p_initial_rate => p_loan_details.INITIAL_INTEREST_RATE
4085 ,p_rate_to_compare => l_raw_rate
4086 ,p_last_period_rate => p_loan_details.LAST_INTEREST_RATE
4087 ,p_max_first_adjustment => p_loan_details.TERM_FIRST_PERCENT_INCREASE
4088 ,p_max_period_adjustment => p_loan_details.TERM_ADJ_PERCENT_INCREASE
4089 ,p_max_lifetime_adjustment => p_loan_details.TERM_LIFE_PERCENT_INCREASE
4090 ,p_ceiling_rate => p_loan_details.TERM_CEILING_RATE
4091 ,p_floor_rate => p_loan_details.TERM_FLOOR_RATE
4092 ,p_installment_number => l_installment_number);
4093
4094 else -- not billing
4095
4096 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ASSIGNING PROJECTED RATE ');
4097 l_annualized_rate := p_loan_details.TERM_PROJECTED_INTEREST_RATE;
4098
4099 end if; -- billing
4100
4101 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': converting rate for floating loan ');
4102 -- recalculate calculatePayment amount
4103 -- payment is based on original amortized portion of loan
4104 -- make sure to pass correct rate id back to billing
4105 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': assigning RATE_ID ' || l_rate_details.rate_id);
4106 l_current_rate_id := l_rate_details.rate_id;
4107
4108 end if; -- recalculate rate
4109
4110 end if; -- rate_type and / or float
4111
4112 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id ' || l_current_rate_id);
4113 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_interest_only_flag ' || l_previous_interest_only_flag);
4114 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag ' || l_interest_only_flag);
4115 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized ' || l_previous_annualized);
4116 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate ' || l_annualized_rate);
4117 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed ' || l_last_installment_billed);
4118 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_periodic_principal ' || l_prev_periodic_principal);
4119 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment ' || l_extend_from_installment);
4120
4121 -- conditions to recalculate principal payment
4122 -- 1. 1-st installment
4123 -- 2. reamortization from installment = current installment
4124 -- 3. reamortize because loan term has been extended
4125 -- 4. emerging from interest only period
4126
4127 if ((l_installment_number = 1) OR
4128 (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
4129 (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
4130 (l_previous_interest_only_flag = 'Y' and l_interest_only_flag = 'N' and l_prev_periodic_principal = 0))
4131 then
4132
4133 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- RE-calculating periodic principal payment');
4134
4135 -- fix for bug 6599682: EQUALLY SPREAD PRINCIPAL FROM IO PERIODS FOR EPRP LOANS
4136 l_non_ro_intervals := get_num_non_ro_instal(l_rate_tbl, l_installment_number, l_orig_num_install) + l_intervals_diff;
4137
4138 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_amortization_intervals=' || l_amortization_intervals);
4139 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_non_ro_intervals=' || l_non_ro_intervals);
4140
4141 if l_installment_number = 1 and l_reamortize_from_installment is null then
4142 l_remaining_balance := l_original_loan_amount;
4143 else
4144 l_remaining_balance := l_remaining_balance_theory;
4145 end if;
4146
4147 l_periodic_principal := lns_financials.calculateEPPayment(p_loan_amount => l_remaining_balance
4148 ,p_num_intervals => l_non_ro_intervals
4149 --,p_num_intervals => l_amortization_intervals
4150 ,p_ending_balance=> l_balloon_amount
4151 ,p_pay_in_arrears=> l_pay_in_arrears);
4152 l_prev_periodic_principal := l_periodic_principal;
4153
4154 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic principal = ' || l_periodic_principal);
4155
4156 else
4157 l_periodic_principal := l_prev_periodic_principal;
4158 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': INHERIT periodic principal is ' || l_periodic_principal);
4159 end if;
4160
4161 l_previous_interest_only_flag := l_interest_only_flag;
4162 l_previous_rate_id := l_current_rate_id;
4163 l_previous_annualized := l_annualized_rate;
4164
4165 l_norm_interest := 0;
4166 l_add_prin_interest := 0;
4167 l_add_int_interest := 0;
4168 l_penal_prin_interest := 0;
4169 l_penal_int_interest := 0;
4170 l_penal_interest := 0;
4171
4172 -- now we will caculate the interest due for this period
4173 -- now we will calculate the interest due
4174 if p_based_on_terms = 'CURRENT' and
4175 l_last_installment_billed >= 0 and
4176 l_last_installment_billed + 1 = l_installment_number
4177 then
4178
4179 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
4180 l_norm_interest := LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
4181 p_calc_method => l_calc_method,
4182 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4183 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
4184 p_interest_rate => l_annualized_rate,
4185 p_day_count_method => l_day_count_method,
4186 p_payment_freq => l_payment_frequency,
4187 p_compound_freq => l_compound_freq);
4188
4189 l_norm_interest := round(l_norm_interest, l_precision);
4190
4191 if (l_installment_number-1) >= 0 then
4192
4193 -- get additional interest start date
4194 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
4195 fetch c_get_last_bill_date into l_add_start_date;
4196 close c_get_last_bill_date;
4197
4198 -- get additional interest end date
4199 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
4200 l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
4201 else
4202 l_add_end_date := sysdate;
4203 end if;
4204
4205 if (l_installment_number-1) > 0 then
4206 l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
4207 else
4208 l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
4209 end if;
4210
4211 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
4212 -- calculate additional interest on unpaid principal
4213 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
4214 p_calc_method => l_calc_method,
4215 p_period_start_date => l_add_start_date,
4216 p_period_end_date => l_add_end_date,
4217 p_interest_rate => l_annualized_rate,
4218 p_day_count_method => l_day_count_method,
4219 p_payment_freq => l_payment_frequency,
4220 p_compound_freq => l_compound_freq,
4221 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
4222 p_prev_grace_end_date => l_prev_grace_end_date,
4223 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4224 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
4225 p_target => 'UNPAID_PRIN',
4226 x_add_interest => l_add_prin_interest,
4227 x_penal_interest => l_penal_prin_interest);
4228 l_add_prin_interest := round(l_add_prin_interest, l_precision);
4229
4230 if (l_calc_method = 'COMPOUND') then
4231
4232 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
4233 -- calculate additional interest on unpaid interest
4234 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
4235 p_calc_method => l_calc_method,
4236 p_period_start_date => l_add_start_date,
4237 p_period_end_date => l_add_end_date,
4238 p_interest_rate => l_annualized_rate,
4239 p_day_count_method => l_day_count_method,
4240 p_payment_freq => l_payment_frequency,
4241 p_compound_freq => l_compound_freq,
4242 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
4243 p_prev_grace_end_date => l_prev_grace_end_date,
4244 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4245 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
4246 p_target => 'UNPAID_INT',
4247 x_add_interest => l_add_int_interest,
4248 x_penal_interest => l_penal_int_interest);
4249 l_add_int_interest := round(l_add_int_interest, l_precision);
4250
4251 end if;
4252
4253 end if;
4254
4255 else
4256
4257 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_actual);
4258
4259 if (l_calc_method = 'SIMPLE') then
4260
4261 -- recalculate periodic rate for each period if day counting methodolgy varies
4262 l_periodic_rate := lns_financials.getPeriodicRate(
4263 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4264 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4265 ,p_annualized_rate => l_annualized_rate
4266 ,p_days_count_method => l_day_count_method);
4267
4268 elsif (l_calc_method = 'COMPOUND') then
4269
4270 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
4271 ,p_payment_freq => l_payment_frequency
4272 ,p_annualized_rate => l_annualized_rate
4273 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4274 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4275 ,p_days_count_method => l_day_count_method);
4276
4277 end if;
4278
4279 l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_actual
4280 ,p_periodic_rate => l_periodic_rate
4281 ,p_compounding_period => null);
4282 l_norm_interest := round(l_norm_interest, l_precision);
4283 end if;
4284
4285 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
4286 l_periodic_interest := round(l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest, l_precision);
4287
4288 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal = ' || l_periodic_principal);
4289 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
4290 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
4291 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_intervals_remaining = ' || l_intervals_remaining);
4292 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled_principal = ' || l_unbilled_principal);
4293
4294 if l_interest_only_flag <> 'Y' or l_intervals_remaining = 1 then
4295
4296 if l_remaining_balance_theory < l_periodic_principal or l_intervals_remaining = 1 then
4297 l_periodic_principal := l_remaining_balance_theory;
4298 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
4299 end if;
4300
4301 else
4302 -- we are in an interest only period
4303 l_periodic_principal := 0;
4304
4305 end if;
4306
4307 l_periodic_principal := round(l_periodic_principal, l_precision);
4308 l_periodic_payment := l_periodic_principal + l_periodic_interest;
4309
4310 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
4311 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_payment = ' || l_periodic_payment);
4312
4313 -- calculate balances and total payment
4314 l_begin_balance := l_remaining_balance_theory;
4315 l_end_balance := l_remaining_balance_theory - l_periodic_principal;
4316
4317 -- check to see if this loan has been billed
4318 if l_unbilled_principal > 0 then
4319 l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
4320 end if;
4321
4322 -- build the amortization record
4323 -- this information is needed to calculate fees
4324 -- rest of the record can be built after fees are calculated
4325 l_amortization_rec.installment_number := l_installment_number; /* needed to calculate fees */
4326 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
4327 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
4328 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
4329 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
4330 l_amortization_rec.interest_amount := l_periodic_interest;
4331 l_amortization_rec.begin_balance := l_begin_balance; /* needed to calculate fees */
4332 l_amortization_rec.end_balance := l_end_balance;
4333 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
4334 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
4335 l_amortization_rec.INTEREST_RATE := l_annualized_rate;
4336 l_amortization_rec.NORMAL_INT_AMOUNT := l_norm_interest;
4337 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_add_prin_interest;
4338 l_amortization_rec.ADD_INT_INT_AMOUNT := l_add_int_interest;
4339 l_amortization_rec.PENAL_INT_AMOUNT := l_penal_interest;
4340
4341 -- calculate fees here
4342 -- should be new routine to simply get the fees from the fee schedule
4343 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
4344 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance;
4345 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
4346 l_fee_basis_tbl(2).fee_basis_amount := l_original_loan_amount;
4347
4348 if l_installment_number = 1 then
4349 if l_orig_fee_structures.count > 0 then
4350
4351 -- fix for bug 7207609
4352 open c_fees(l_loan_id, l_installment_number);
4353 fetch c_fees into l_fee_amount;
4354 close c_fees;
4355 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
4356 /*
4357 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
4358 ,p_installment => l_installment_number
4359 ,p_fee_basis_tbl => l_fee_basis_tbl
4360 ,p_fee_structures => l_orig_fee_structures
4361 ,x_fees_tbl => l_orig_fees_tbl
4362 ,x_return_status => l_return_status
4363 ,x_msg_count => l_msg_count
4364 ,x_msg_data => l_msg_data);
4365 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated origination fees ' || l_orig_fee_structures.count);
4366 */
4367 -- l_other_amount := lns_fee_engine.calculateFees(p_amortization_rec => l_amortization_rec
4368 -- ,p_fee_structures => l_memo_fee_structures);
4369 end if;
4370 end if;
4371
4372 if l_memo_fee_structures.count > 0 then
4373 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
4374 ,p_installment => l_installment_number
4375 ,p_fee_basis_tbl => l_fee_basis_tbl
4376 ,p_fee_structures => l_memo_fee_structures
4377 ,x_fees_tbl => l_memo_fees_tbl
4378 ,x_return_status => l_return_status
4379 ,x_msg_count => l_msg_count
4380 ,x_msg_data => l_msg_data);
4381 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated memo fees ' || l_memo_fees_tbl.count);
4382
4383 -- l_other_amount := lns_fee_engine.calculateFees(p_amortization_rec => l_amortization_rec
4384 -- ,p_fee_structures => l_memo_fee_structures);
4385 end if;
4386
4387
4388 if l_fee_structures.count > 0 then
4389 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
4390 ,p_installment => l_installment_number
4391 ,p_fee_basis_tbl => l_fee_basis_tbl
4392 ,p_fee_structures => l_fee_structures
4393 ,x_fees_tbl => l_fees_tbl
4394 ,x_return_status => l_return_status
4395 ,x_msg_count => l_msg_count
4396 ,x_msg_data => l_msg_data);
4397 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated fees ' || l_fees_tbl.count);
4398
4399 -- l_fee_amount := lns_fee_engine.calculateFees(p_amortization_rec => l_amortization_rec
4400 -- ,p_fee_structures => l_fee_structures);
4401 end if;
4402 /*
4403 for i in 1..l_orig_fees_tbl.count loop
4404 l_fee_amount := l_fee_amount + l_orig_fees_tbl(i).FEE_AMOUNT;
4405 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
4406 end loop;
4407 */
4408 for k in 1..l_fees_tbl.count loop
4409 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
4410 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': recurring calculated fees ' || l_fee_amount);
4411 end loop;
4412
4413 for j in 1..l_memo_fees_tbl.count loop
4414 l_other_amount := l_other_amount + l_memo_fees_tbl(j).FEE_AMOUNT;
4415 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': other calculated fees ' || l_other_amount);
4416 end loop;
4417
4418 l_total := l_fee_amount + l_periodic_principal + l_periodic_interest + l_other_amount;
4419 l_amortization_rec.total := l_total;
4420 l_amortization_rec.fee_amount := l_fee_amount;
4421 l_amortization_rec.other_amount := l_other_amount;
4422
4423 -- running totals calculated here
4424 l_principal_cumulative := l_principal_cumulative + l_periodic_principal;
4425 l_interest_cumulative := l_interest_cumulative + l_periodic_interest;
4426 l_fees_cumulative := l_fees_cumulative + l_fee_amount;
4427 l_other_cumulative := l_other_cumulative + l_other_amount;
4428
4429 l_amortization_rec.interest_cumulative := l_interest_cumulative;
4430 l_amortization_rec.principal_cumulative := l_principal_cumulative;
4431 l_amortization_rec.fees_cumulative := l_fees_cumulative;
4432 l_amortization_rec.other_cumulative := l_other_cumulative;
4433 l_amortization_rec.rate_id := l_current_rate_id;
4434 l_amortization_rec.SOURCE := 'PREDICTED';
4435
4436 -- add the record to the amortization table
4437 l_amortization_tbl(i) := l_amortization_rec;
4438
4439 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: due date ' || l_amortization_rec.due_date);
4440 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_principal ' || l_amortization_rec.principal_amount);
4441 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_interest ' || l_amortization_rec.interest_amount);
4442 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fee_amount is ' || l_amortization_rec.fee_amount);
4443 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: total is ' || l_amortization_rec.total);
4444 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: other_amount is ' || l_amortization_rec.other_amount);
4445 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: begin_balance is ' || l_amortization_rec.begin_balance);
4446 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: end_balance is ' || l_amortization_rec.end_balance);
4447 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: interest_cumulative is ' || l_amortization_rec.interest_cumulative);
4448 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: principal_cumulative is ' || l_amortization_rec.principal_cumulative);
4449 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fees_cumulative is ' || l_amortization_rec.fees_cumulative);
4450 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: other_cumulative is ' || l_amortization_rec.other_cumulative);
4451 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: current_rate_id is ' || l_amortization_rec.rate_id );
4452
4453 -- adjust new loan amount to reflect less periodic principal paid
4454 -- theoretically without over/underpayments l_loan_amount should = l_remaining_balance
4455 -- if they diverge then we will calculate interest based from l_remaining_balance
4456 -- rather than l_loan_amount
4457 l_remaining_balance_theory := l_end_balance;
4458
4459 -- for next installment to bill: calculate interest based on real situation including unpaid amounts
4460 -- for all other installments: project ideal schedule (meaning that all unpaid amounts are paid)
4461 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number)
4462 and p_based_on_terms = 'CURRENT' then
4463 l_remaining_balance_actual := l_remaining_balance_theory;
4464 else
4465 l_remaining_balance_actual := l_remaining_balance_actual - l_periodic_principal;
4466 end if;
4467
4468 -- clean up
4469 l_orig_fees_tbl.delete;
4470 l_memo_fees_tbl.delete;
4471 l_fees_tbl.delete;
4472
4473 end loop;
4474
4475 --printAmortizationTable(p_amort_tbl => l_amortization_tbl);
4476
4477 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT IS ' || l_amortization_tbl.count);
4478 x_loan_amort_tbl := l_amortization_tbl;
4479
4480 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
4481
4482 Exception
4483 WHEN FND_API.G_EXC_ERROR THEN
4484 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
4485
4486 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
4487 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
4488
4489 WHEN OTHERS THEN
4490 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
4491
4492 end amortizeEPLoan;
4493
4494
4495
4496
4497 /*=========================================================================
4498 || PUBLIC PROCEDURE amortizeLoan
4499 ||
4500 || DESCRIPTION
4501 ||
4502 || Overview: procedure will run an amortization
4503 || this is the main calculation API for amortization
4504 || THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
4505 || 1. Amortization UI - when creating a loan
4506 || 2. Billing Engine - to generate installment bills
4507 ||
4508 || Parameter: p_loan_details = details of the loan
4509 || p_rate_schedule = rate schedule for the loan
4510 || p_installment_number => billing will pass in an installment
4511 || number to generate a billt
4512 || x_loan_amort_tbl => table of amortization records
4513 ||
4514 || Source Tables: NA
4515 ||
4516 || Target Tables:
4517 ||
4518 ||
4519 || KNOWN ISSUES
4520 ||
4521 || NOTES
4522 ||
4523 || MODIFICATION HISTORY
4524 || Date Author Description of Changes
4525 || 12/12/2003 11:35AM raverma Created
4526 || 2/26/2004 raverma coded in multiple rates
4527 || 10/28/2004 raverma added interest only flag
4528 || 06/20/2008 scherkas Synch amortizeLoan procedure with LNS_FINANCIALS 115.112 version
4529 *=======================================================================*/
4530 procedure amortizeLoan(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
4531 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
4532 ,p_based_on_terms in varchar2
4533 ,p_installment_number in number
4534 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
4535 is
4536 l_return_status varchar2(1);
4537 l_msg_count NUMBER;
4538 l_msg_data VARCHAR2(32767);
4539 -- loan_details
4540 l_loan_id number;
4541 l_original_loan_amount number; -- loan amount
4542 l_balloon_amount number;
4543 l_amortized_amount number; -- amount of loan less balloon amount
4544 l_amortized_term number;
4545 l_amortized_term_period varchar2(30);
4546 l_amortization_frequency varchar2(30);
4547 l_first_payment_date date;
4548 l_pay_in_arrears boolean;
4549 l_payment_frequency varchar2(30);
4550 l_day_count_method varchar2(30);
4551 l_interest_comp_freq varchar2(30);
4552 l_reamortize_from_installment number;
4553 l_reamortize_amount number;
4554 l_annualized_rate number; -- annual rate on the loan
4555 l_raw_rate number; --
4556 l_intervals_original number;
4557 l_intervals number;
4558 l_intervals_remaining number;
4559 l_amortization_intervals_orig number;
4560 l_amortization_intervals_rem number;
4561 l_amortization_intervals number; -- number of intervals to amortize over
4562 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
4563 l_current_rate_id number;
4564 l_previous_rate_id number;
4565 l_precision number;
4566 l_rate_type varchar2(30);
4567 l_open_rate_change_frequency varchar2(30);
4568 l_open_index_rate_id number;
4569 l_open_ceiling_rate number;
4570 l_open_floor_rate number;
4571 l_term_rate_change_frequency varchar2(30);
4572 l_term_index_rate_id number;
4573 l_term_ceiling_rate number;
4574 l_term_floor_rate number;
4575
4576 l_period_start_Date date;
4577 l_period_end_date date;
4578 l_periodic_rate number;
4579 l_maturity_date date;
4580
4581 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
4582 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
4583 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
4584 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
4585 l_loan_start_date date;
4586 l_num_pay_dates number; -- number of dates on installment schedule
4587 l_periodic_payment number;
4588 l_periodic_principal number;
4589 l_periodic_interest number;
4590 l_total_principal number;
4591 l_payment_number number;
4592 l_fee_amount number;
4593 l_fee_amount1 number;
4594 l_other_amount number;
4595 l_begin_balance number;
4596 l_end_balance number;
4597 l_unbilled_principal number;
4598 l_unpaid_principal number;
4599 l_unpaid_interest number;
4600
4601 l_remaining_balance_actual number;
4602 l_remaining_balance_theory number;
4603 l_total number;
4604 l_interest_cumulative number;
4605 l_principal_cumulative number;
4606 l_fees_cumulative number;
4607 l_other_cumulative number;
4608 i number;
4609 l_installment_number number;
4610 l_billing boolean; -- switch to notify if billing is calling API
4611 l_api_name varchar2(20);
4612 l_last_installment_billed number;
4613 l_rate_to_calculate number;
4614 l_previous_annualized number;
4615 l_previous_interest_only_flag varchar2(1);
4616 l_interest_only_flag varchar2(1);
4617 l_calc_method varchar2(30);
4618 l_compound_freq varchar2(30);
4619 l_remaining_balance_actual1 number;
4620 l_ending_balance number;
4621 l_due_date date;
4622 l_begin number;
4623 l_installment_number1 number;
4624 l_norm_interest number;
4625 l_add_prin_interest number;
4626 l_add_int_interest number;
4627 l_add_start_date date;
4628 l_add_end_date date;
4629 l_penal_prin_interest number;
4630 l_penal_int_interest number;
4631 l_penal_interest number;
4632 l_first_installment_billed number;
4633 l_extend_from_installment number;
4634 l_remaining_balance number;
4635 l_prev_grace_end_date date;
4636
4637 -- for fees
4638 l_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
4639 l_memo_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
4640 l_orig_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
4641 l_conv_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
4642 l_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
4643 l_memo_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
4644 l_orig_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
4645 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
4646
4647 -- total fees on the schedule by installment
4648 cursor c_fees(p_loan_id number, p_installment number) is
4649 select nvl(sum(sched.fee_amount), 0)
4650 from lns_fee_schedules sched
4651 ,lns_fees struct
4652 where sched.loan_id = p_loan_id
4653 and sched.fee_id = struct.fee_id
4654 and struct.fee_type = 'EVENT_ORIGINATION'
4655 and fee_installment = p_installment
4656 and active_flag = 'Y';
4657 --and billed_flag = 'N';
4658
4659 cursor c_conv_fees(p_loan_id number) is
4660 select nvl(sum(fee),0)
4661 from lns_fee_assignments
4662 where loan_id = p_loan_id
4663 and fee_type = 'EVENT_CONVERSION';
4664
4665 -- get last bill date
4666 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
4667 select ACTIVITY_DATE
4668 from LNS_PRIN_TRX_ACTIVITIES_V
4669 where loan_id = p_loan_id
4670 and PAYMENT_NUMBER = p_installment_number
4671 and PARENT_AMORTIZATION_ID is null
4672 and ACTIVITY_CODE in ('BILLING', 'START');
4673
4674 -- get last billed payment info
4675 cursor c_get_last_payment(p_loan_id number, p_installment_number number) is
4676 select (PRINCIPAL_AMOUNT + INTEREST_AMOUNT)
4677 from lns_amortization_scheds
4678 where loan_id = p_loan_id
4679 and PAYMENT_NUMBER > 0
4680 and PAYMENT_NUMBER <= p_installment_number
4681 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
4682 and PARENT_AMORTIZATION_ID is null
4683 and PRINCIPAL_AMOUNT > 0
4684 and nvl(PHASE, 'TERM') = 'TERM'
4685 order by PAYMENT_NUMBER desc;
4686
4687 -- get first billed installment number
4688 cursor c_first_billed_instal(p_loan_id number) is
4689 select min(PAYMENT_NUMBER)
4690 from LNS_AMORTIZATION_SCHEDS
4691 where loan_id = p_loan_id
4692 and PAYMENT_NUMBER > 0
4693 and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
4694 and PARENT_AMORTIZATION_ID is null
4695 and nvl(PHASE, 'TERM') = 'TERM';
4696
4697 begin
4698
4699 -- initialize all variables
4700 l_original_loan_amount := 0; -- loan amount
4701 l_amortized_amount := 0;
4702 l_previous_rate_id := -1;
4703 l_previous_annualized := -1;
4704 l_previous_interest_only_flag := 'N'; -- default to regular interest + principal
4705 l_periodic_payment := 0;
4706 l_periodic_principal := 0;
4707 l_periodic_interest := 0;
4708 l_balloon_amount := 0;
4709 l_total_principal := 0;
4710 l_payment_number := 0;
4711 l_fee_amount := 0;
4712 l_other_amount := 0;
4713 l_begin_balance := 0;
4714 l_unbilled_principal := 0;
4715 l_unpaid_principal := 0;
4716 l_remaining_balance_actual := 0;
4717 l_remaining_balance_theory := 0;
4718 l_total := 0;
4719 l_interest_cumulative := 0;
4720 l_principal_cumulative := 0;
4721 l_fees_cumulative := 0;
4722 l_other_cumulative := 0;
4723 i := 0;
4724 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
4725 l_rate_to_calculate := 0;
4726 l_billing := false; -- switch to notify if billing is calling API
4727 l_api_name := 'amortizeLoan MAIN';
4728
4729 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
4730 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
4731 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
4732
4733 l_amortized_amount := p_loan_details.amortized_amount;
4734 l_amortized_term := p_loan_details.amortized_term;
4735 l_amortized_term_period := p_loan_details.amortized_term_period;
4736 l_amortization_frequency := p_loan_details.amortization_frequency;
4737 l_amortization_intervals_orig := p_loan_details.num_amortization_intervals;
4738 l_amortization_intervals := p_loan_details.num_amortization_intervals;
4739 l_amortization_intervals_rem := p_loan_details.num_amortization_intervals;
4740 l_balloon_amount := p_loan_details.balloon_payment_amount;
4741 l_day_count_method := p_loan_details.day_count_method;
4742 l_first_payment_date := p_loan_details.first_payment_date;
4743 l_loan_id := p_loan_details.loan_id;
4744 l_intervals := p_loan_details.number_installments;
4745 l_intervals_original := p_loan_details.number_installments;
4746 l_last_installment_billed := p_loan_details.last_installment_billed;
4747 l_loan_start_date := p_loan_details.loan_start_date;
4748 l_maturity_date := p_loan_details.maturity_date;
4749 l_rate_type := p_loan_details.rate_type;
4750 l_open_rate_change_frequency := p_loan_details.open_rate_chg_freq;
4751 l_open_index_rate_id := p_loan_details.open_index_rate_id;
4752 l_open_ceiling_rate := p_loan_details.open_ceiling_rate;
4753 l_open_floor_rate := p_loan_details.open_floor_rate;
4754 l_original_loan_amount := p_loan_details.requested_amount;
4755 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
4756 l_payment_frequency := p_loan_details.payment_frequency;
4757 l_precision := p_loan_details.currency_precision;
4758 l_reamortize_from_installment := p_loan_details.reamortize_from_installment;
4759 l_reamortize_amount := p_loan_details.reamortize_amount;
4760 l_remaining_balance_actual := p_loan_details.remaining_balance;
4761 l_remaining_balance_actual1 := p_loan_details.remaining_balance;
4762 l_term_rate_change_frequency := p_loan_details.term_rate_chg_freq;
4763 l_term_index_rate_id := p_loan_details.term_index_rate_id;
4764 l_term_ceiling_rate := p_loan_details.term_ceiling_rate;
4765 l_term_floor_rate := p_loan_details.term_floor_rate;
4766 l_calc_method := p_loan_details.CALCULATION_METHOD;
4767 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
4768 l_extend_from_installment := p_loan_details.EXTEND_FROM_INSTALLMENT;
4769
4770 -- get the interest rate schedule
4771 l_rate_tbl := p_rate_schedule;
4772 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count: ' || l_rate_tbl.count);
4773
4774 -- get payment schedule
4775 -- this will return the acutal dates that payments will be due on
4776 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
4777 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
4778 ,p_loan_maturity_date => l_maturity_date
4779 ,p_first_pay_date => l_first_payment_date
4780 ,p_num_intervals => l_intervals
4781 ,p_interval_type => l_payment_frequency
4782 ,p_pay_in_arrears => l_pay_in_arrears);
4783
4784 l_num_pay_dates := l_payment_tbl.count;
4785 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count: ' || l_num_pay_dates);
4786
4787 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting conv fee structures');
4788 l_conv_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
4789 ,p_fee_category => 'EVENT'
4790 ,p_fee_type => 'EVENT_CONVERSION'
4791 ,p_installment => null
4792 ,p_fee_id => null);
4793 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': conv structures count is ' || l_conv_fee_structures.count);
4794
4795 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting origination fee structures');
4796 l_orig_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
4797 ,p_fee_category => 'EVENT'
4798 ,p_fee_type => 'EVENT_ORIGINATION'
4799 ,p_installment => null
4800 ,p_fee_id => null);
4801 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig structures count is ' || l_orig_fee_structures.count);
4802
4803 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting recurring fee structures');
4804 l_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
4805 ,p_fee_category => 'RECUR'
4806 ,p_fee_type => null
4807 ,p_installment => null
4808 ,p_fee_id => null);
4809 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': fee structures count is ' || l_fee_structures.count);
4810
4811 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting memo fee structures');
4812 l_memo_fee_structures := lns_fee_engine.getFeeStructures(p_loan_id => l_loan_id
4813 ,p_fee_category => 'MEMO'
4814 ,p_fee_type => null
4815 ,p_installment => null
4816 ,p_fee_id => null);
4817 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': memo fee structures count is ' || l_memo_fee_structures.count);
4818
4819 -- 2-24-2005 raverma add 0 installment to amortization schedule
4820 if l_orig_fee_structures.count > 0 or l_conv_fee_structures.count > 0 then
4821
4822 open c_fees(l_loan_id, 0);
4823 fetch c_fees into l_fee_amount1;
4824 close c_fees;
4825 l_fee_amount := l_fee_amount1;
4826
4827 open c_conv_fees(l_loan_id);
4828 fetch c_conv_fees into l_fee_amount1;
4829 close c_conv_fees;
4830 l_fee_amount := l_fee_amount1 + l_fee_amount;
4831
4832 if l_fee_amount > 0 then
4833 i := i + 1;
4834 l_amortization_rec.installment_number := 0;
4835 l_amortization_rec.due_date := l_loan_start_date;
4836 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
4837 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
4838 l_amortization_rec.principal_amount := 0;
4839 l_amortization_rec.interest_amount := 0;
4840 l_amortization_rec.fee_amount := l_fee_amount;
4841 l_amortization_rec.other_amount := 0;
4842 l_amortization_rec.begin_balance := l_original_loan_amount;
4843 l_amortization_rec.end_balance := l_original_loan_amount;
4844 l_amortization_rec.interest_cumulative := 0;
4845 l_amortization_rec.principal_cumulative := 0;
4846 l_amortization_rec.fees_cumulative := l_fee_amount;
4847 l_amortization_rec.other_cumulative := 0;
4848 l_amortization_rec.rate_id := 0;
4849 l_amortization_rec.SOURCE := 'PREDICTED';
4850 -- add the record to the amortization table
4851 l_amortization_rec.total := l_fee_amount;
4852 l_amortization_rec.UNPAID_PRIN := 0;
4853 l_amortization_rec.UNPAID_INT := 0;
4854 l_amortization_rec.INTEREST_RATE := 0;
4855 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
4856 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
4857 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
4858 l_amortization_rec.PENAL_INT_AMOUNT := 0;
4859 l_amortization_tbl(i) := l_amortization_rec;
4860 end if;
4861
4862 --l_orig_fees_tbl.delete;
4863 l_fee_amount := 0;
4864
4865 end if;
4866
4867 -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
4868 l_remaining_balance_theory := l_original_loan_amount;
4869 if p_installment_number is not null then
4870 -- we are billing
4871
4872 l_billing := true;
4873 if p_installment_number > 0 then
4874
4875 if p_installment_number > l_num_pay_dates then
4876 l_payment_number := l_num_pay_dates;
4877 else
4878 l_payment_number := p_installment_number;
4879 end if;
4880
4881 else
4882 i := i + 1;
4883 -- special we are on the 0th installment
4884 l_amortization_rec.installment_number := 0;
4885 l_amortization_rec.due_date := l_loan_start_date;
4886 l_amortization_rec.PERIOD_START_DATE := l_loan_start_date;
4887 l_amortization_rec.PERIOD_END_DATE := l_loan_start_date;
4888 l_amortization_rec.principal_amount := l_periodic_principal;
4889 l_amortization_rec.interest_amount := l_periodic_interest;
4890 l_amortization_rec.fee_amount := l_fee_amount;
4891 l_amortization_rec.begin_balance := l_remaining_balance_actual;
4892 l_amortization_rec.end_balance := l_remaining_balance_actual;
4893 l_amortization_rec.interest_cumulative := l_interest_cumulative;
4894 l_amortization_rec.principal_cumulative := l_principal_cumulative;
4895 l_amortization_rec.fees_cumulative := l_fees_cumulative + l_fee_amount;
4896 l_amortization_rec.other_cumulative := l_other_cumulative;
4897 l_amortization_rec.rate_id := l_current_rate_id;
4898 l_amortization_rec.UNPAID_PRIN := 0;
4899 l_amortization_rec.UNPAID_INT := 0;
4900 l_amortization_rec.INTEREST_RATE := 0;
4901 l_amortization_rec.NORMAL_INT_AMOUNT := 0;
4902 l_amortization_rec.ADD_PRIN_INT_AMOUNT := 0;
4903 l_amortization_rec.ADD_INT_INT_AMOUNT := 0;
4904 l_amortization_rec.PENAL_INT_AMOUNT := 0;
4905 -- add the record to the amortization table
4906 l_amortization_tbl(i) := l_amortization_rec;
4907
4908 end if;
4909
4910 else -- we are not billing, go thru entire amortization
4911
4912 l_payment_number := l_num_pay_dates;
4913
4914 end if;
4915
4916 l_remaining_balance_actual := l_original_loan_amount;
4917 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
4918 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
4919
4920 l_begin := 1;
4921
4922 if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
4923
4924 open c_first_billed_instal(l_loan_id);
4925 fetch c_first_billed_instal into l_first_installment_billed;
4926 close c_first_billed_instal;
4927 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_first_installment_billed = ' || l_first_installment_billed);
4928
4929 if l_first_installment_billed < l_last_installment_billed then
4930 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_last_installment_billed || '-----');
4931 open c_get_last_payment(l_loan_id, l_last_installment_billed);
4932 fetch c_get_last_payment into l_periodic_payment;
4933 close c_get_last_payment;
4934
4935 if l_periodic_payment is null then
4936 l_periodic_payment := 0;
4937 end if;
4938 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Last periodic payment = ' || l_periodic_payment);
4939
4940 l_begin := l_last_installment_billed + 1;
4941
4942 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
4943 l_rate_details := getRateDetails(p_installment => l_last_installment_billed
4944 ,p_rate_tbl => l_rate_tbl);
4945
4946 if p_loan_details.rate_type = 'FIXED' OR (p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'N')
4947 then
4948
4949 if l_rate_tbl.count = 1 then
4950 l_previous_annualized := l_rate_tbl(1).annual_rate;
4951 l_previous_interest_only_flag := l_rate_tbl(1).interest_only_flag;
4952 else
4953 l_previous_annualized := l_rate_details.annual_rate;
4954 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
4955 end if;
4956
4957 elsif p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'Y' then
4958
4959 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
4960 l_rate_details.ANNUAL_RATE := lns_fin_utils.getRateForDate(p_loan_details.OPEN_INDEX_RATE_ID
4961 ,l_payment_tbl(l_last_installment_billed).period_begin_date);
4962
4963 l_raw_rate := l_rate_details.ANNUAL_RATE + l_rate_details.spread;
4964 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_raw_rate ' || l_raw_rate);
4965
4966 -- adjust the rate as per rate rules
4967 l_previous_annualized := calculateInterestRate(p_initial_rate => p_loan_details.INITIAL_INTEREST_RATE
4968 ,p_rate_to_compare => l_raw_rate
4969 ,p_last_period_rate => p_loan_details.LAST_INTEREST_RATE
4970 ,p_max_first_adjustment => p_loan_details.TERM_FIRST_PERCENT_INCREASE
4971 ,p_max_period_adjustment => p_loan_details.TERM_ADJ_PERCENT_INCREASE
4972 ,p_max_lifetime_adjustment => p_loan_details.TERM_LIFE_PERCENT_INCREASE
4973 ,p_ceiling_rate => p_loan_details.TERM_CEILING_RATE
4974 ,p_floor_rate => p_loan_details.TERM_FLOOR_RATE
4975 ,p_installment_number => l_last_installment_billed);
4976 end if;
4977
4978 end if;
4979
4980 end if;
4981
4982 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_begin = ' || l_begin);
4983
4984 for l_installment_number in l_begin..l_payment_number
4985 loop
4986
4987 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || '-----');
4988
4989 i := i + 1;
4990 l_periodic_interest := 0;
4991 l_periodic_principal := 0;
4992 l_fee_amount := 0;
4993 l_other_amount := 0;
4994 l_unpaid_principal := 0;
4995 l_unpaid_interest := 0;
4996 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
4997
4998 -- this is the main check for calculating interest on actual balance not theoretical
4999 -- intercept and overwrite the remaining balance theory with remain balance actual
5000 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number)
5001 and p_based_on_terms = 'CURRENT' then
5002 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': BASED ON CURRENT TERMS FROM INSTALLMENT: ' || l_installment_number);
5003
5004 l_principal_cumulative := 0;
5005 l_interest_cumulative := 0;
5006 l_fees_cumulative := 0;
5007 l_other_cumulative := 0;
5008 -- get the unbilled / unpaid principal at this point in time i.e. for this installment
5009 l_unbilled_principal := p_loan_details.unbilled_principal;
5010 l_unpaid_principal := p_loan_details.unpaid_principal;
5011 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
5012
5013 -- bug #3811298
5014 if p_loan_details.loan_status <> 'PAIDOFF' then
5015 -- begin fix for bug# 6663848
5016 if (l_calc_method = 'SIMPLE') then
5017 l_remaining_balance_actual := l_remaining_balance_actual1;
5018 elsif (l_calc_method = 'COMPOUND') then
5019 l_remaining_balance_actual := l_remaining_balance_actual1 + l_unpaid_interest;
5020 end if;
5021 -- end fix for bug# 6663848
5022 l_remaining_balance_theory := l_remaining_balance_actual1 - l_unpaid_principal;
5023 else
5024 l_remaining_balance_actual := 0;
5025 l_remaining_balance_theory := 0;
5026 end if;
5027 end if;
5028
5029 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_actual: ' || l_remaining_balance_actual);
5030 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory: ' || l_remaining_balance_theory);
5031
5032 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
5033 l_rate_details := getRateDetails(p_installment => l_installment_number
5034 ,p_rate_tbl => l_rate_tbl);
5035
5036 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate ' || l_rate_details.annual_rate);
5037 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread ' || l_rate_details.spread);
5038 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id ' || l_rate_details.rate_id);
5039 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate floating_flag ' || l_rate_details.floating_flag);
5040
5041 -- get the rate details only need to get it once if a single interest rate exists
5042 l_current_rate_id := l_rate_details.rate_id;
5043 l_annualized_rate := l_rate_details.annual_rate;
5044 l_interest_only_flag := l_rate_details.interest_only_flag;
5045
5046 -- add in support here for floating rate loans
5047 if p_loan_details.rate_type = 'VARIABLE' and l_rate_details.floating_flag = 'Y' then
5048
5049 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING ');
5050 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': period_begin_date ' || l_payment_tbl(l_installment_number).period_begin_date);
5051 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
5052 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.NEXT_RATE_CHANGE_DATE ' || p_loan_details.NEXT_RATE_CHANGE_DATE);
5053 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.OPEN_INDEX_RATE_ID ' || p_loan_details.OPEN_INDEX_RATE_ID);
5054 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.INITIAL_INTEREST_RATE ' || p_loan_details.INITIAL_INTEREST_RATE);
5055 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.LAST_INTEREST_RATE ' || p_loan_details.LAST_INTEREST_RATE);
5056 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_FIRST_PERCENT_INCREASE ' || p_loan_details.TERM_FIRST_PERCENT_INCREASE);
5057 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_ADJ_PERCENT_INCREASE ' || p_loan_details.TERM_ADJ_PERCENT_INCREASE);
5058 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_LIFE_PERCENT_INCREASE ' || p_loan_details.TERM_LIFE_PERCENT_INCREASE);
5059 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_CEILING_RATE ' || p_loan_details.TERM_CEILING_RATE);
5060 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.TERM_FLOOR_RATE ' || p_loan_details.TERM_FLOOR_RATE);
5061
5062 -- if float and no rate then error;
5063 -- we only need to get the new rate if
5064 -- 1. no rate has ever been calculated (i.e. 1st installment)
5065 -- 2. the billing date is beyond the next_rate_change_date
5066 -- 3. make sure to add spread and abide by rate rules
5067 if l_payment_tbl(l_installment_number).period_begin_date < p_loan_details.NEXT_RATE_CHANGE_DATE and l_installment_number > 1 then
5068
5069 -- no need to recalculate interest, use current interest rate found on last installment
5070 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING NO RECALC');
5071
5072 l_annualized_rate := p_loan_details.LAST_INTEREST_RATE + l_rate_details.spread;
5073
5074 --elsif l_installment_number = 1 OR l_payment_tbl(l_installment_number).period_begin_date >= p_loan_details.NEXT_RATE_CHANGE_DATE then
5075 else
5076
5077 if p_based_on_terms = 'CURRENT' then
5078
5079 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLOATING RECALCULATE');
5080
5081 l_rate_details.ANNUAL_RATE := lns_fin_utils.getRateForDate(p_loan_details.OPEN_INDEX_RATE_ID
5082 ,l_payment_tbl(l_installment_number).period_begin_date);
5083
5084 -- raise error as rates does not exist
5085 if l_rate_details.ANNUAL_RATE is null then
5086 FND_MESSAGE.SET_NAME('LNS', 'LNS_RATES_ERROR');
5087 FND_MSG_PUB.ADD;
5088 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for INDEX_ID ' || p_loan_details.TERM_INDEX_RATE_ID);
5089 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rates missing for DATE ' || p_loan_details.NEXT_RATE_CHANGE_DATE);
5090 RAISE FND_API.G_EXC_ERROR;
5091 end if;
5092
5093 -- add the spread into the rate
5094 l_raw_rate := l_rate_details.ANNUAL_RATE + l_rate_details.spread;
5095 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_raw_rate ' || l_raw_rate);
5096
5097 -- adjust the rate as per rate rules
5098 l_annualized_rate := calculateInterestRate(p_initial_rate => p_loan_details.INITIAL_INTEREST_RATE
5099 ,p_rate_to_compare => l_raw_rate
5100 ,p_last_period_rate => p_loan_details.LAST_INTEREST_RATE
5101 ,p_max_first_adjustment => p_loan_details.TERM_FIRST_PERCENT_INCREASE
5102 ,p_max_period_adjustment => p_loan_details.TERM_ADJ_PERCENT_INCREASE
5103 ,p_max_lifetime_adjustment => p_loan_details.TERM_LIFE_PERCENT_INCREASE
5104 ,p_ceiling_rate => p_loan_details.TERM_CEILING_RATE
5105 ,p_floor_rate => p_loan_details.TERM_FLOOR_RATE
5106 ,p_installment_number => l_installment_number);
5107
5108 else -- not billing
5109
5110 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ASSIGNING PROJECTED RATE ');
5111 l_annualized_rate := p_loan_details.TERM_PROJECTED_INTEREST_RATE;
5112
5113 end if; -- billing
5114
5115 end if; -- recalculate rate
5116
5117 end if; -- rate_type and / or float
5118
5119 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_rate_id = ' || l_previous_rate_id);
5120 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id ' || l_current_rate_id);
5121 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized ' || l_previous_annualized);
5122 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate ' || l_annualized_rate);
5123 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_interest_only_flag ' || l_previous_interest_only_flag);
5124 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag ' || l_interest_only_flag);
5125 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed ' || l_last_installment_billed);
5126 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment ' || l_extend_from_installment);
5127
5128 -- conditions to recalculate payment
5129 -- 1. 1-st installment
5130 -- 2. previous interest rate <> current interest rate
5131 -- 3. reamortization from installment = current installment
5132 -- 4. emerging from interest only period
5133 -- 5. reamortize because loan term has been extended
5134
5135 if ((l_installment_number = 1) OR
5136 (l_annualized_rate <> l_previous_annualized) OR
5137 (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
5138 (l_previous_interest_only_flag = 'Y' and l_interest_only_flag = 'N') OR
5139 (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)))
5140 then
5141
5142 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- RE-calculating periodic payment');
5143 -- rate has changed so we know we are on a new rate schedule
5144 -- we need to recalculate the payment_amount
5145 l_amortization_intervals := l_amortization_intervals_orig - l_installment_number + 1;
5146
5147 if (l_calc_method = 'SIMPLE') then
5148
5149 l_rate_to_calculate := lns_fin_utils.convertRate(p_annualized_rate => l_annualized_rate
5150 ,p_amortization_frequency => l_amortization_frequency);
5151
5152 elsif (l_calc_method = 'COMPOUND') then
5153
5154 l_rate_to_calculate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5155 ,p_payment_freq => l_payment_frequency
5156 ,p_annualized_rate => l_annualized_rate
5157 ,p_period_start_date => null
5158 ,p_period_end_date => null
5159 ,p_days_count_method => l_day_count_method);
5160
5161 end if;
5162
5163 -- we need to calculate payment ONCE per interest rate change
5164 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_rate_to_calculate = ' || l_rate_to_calculate);
5165 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_amortization_intervals = ' || l_amortization_intervals);
5166
5167 if l_installment_number = 1 and l_reamortize_from_installment is null then
5168 l_remaining_balance := l_original_loan_amount;
5169 else
5170 l_remaining_balance := l_remaining_balance_theory;
5171 end if;
5172
5173 if l_rate_details.rate_id = l_rate_tbl(1).rate_id then
5174 l_periodic_payment := lns_financials.calculatePayment(p_loan_amount => l_remaining_balance
5175 ,p_periodic_rate => l_rate_to_calculate
5176 ,p_num_intervals => l_amortization_intervals
5177 ,p_ending_balance=> l_balloon_amount
5178 ,p_pay_in_arrears=> l_pay_in_arrears);
5179 else
5180 l_periodic_payment := lns_financials.calculatePayment(p_loan_amount => l_remaining_balance
5181 ,p_periodic_rate => l_rate_to_calculate
5182 ,p_num_intervals => l_amortization_intervals
5183 ,p_ending_balance=> l_balloon_amount
5184 ,p_pay_in_arrears=> true);
5185 end if;
5186
5187 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic payment = ' || l_periodic_payment);
5188
5189 else
5190 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD periodic payment = ' || l_periodic_payment);
5191 end if;
5192
5193 l_previous_interest_only_flag := l_interest_only_flag;
5194 l_previous_rate_id := l_current_rate_id;
5195 l_previous_annualized := l_annualized_rate;
5196
5197 l_norm_interest := 0;
5198 l_add_prin_interest := 0;
5199 l_add_int_interest := 0;
5200 l_penal_prin_interest := 0;
5201 l_penal_int_interest := 0;
5202 l_penal_interest := 0;
5203
5204 -- now we will caculate the interest due for this period
5205 if p_based_on_terms = 'CURRENT' and
5206 l_last_installment_billed >= 0 and
5207 l_last_installment_billed + 1 = l_installment_number
5208 then
5209
5210 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
5211 l_norm_interest := LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
5212 p_calc_method => l_calc_method,
5213 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5214 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
5215 p_interest_rate => l_annualized_rate,
5216 p_day_count_method => l_day_count_method,
5217 p_payment_freq => l_payment_frequency,
5218 p_compound_freq => l_compound_freq);
5219
5220 l_norm_interest := round(l_norm_interest, l_precision);
5221
5222 if (l_installment_number-1) >= 0 then
5223
5224 -- get additional interest start date
5225 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
5226 fetch c_get_last_bill_date into l_add_start_date;
5227 close c_get_last_bill_date;
5228
5229 -- get additional interest end date
5230 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
5231 l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
5232 else
5233 l_add_end_date := sysdate;
5234 end if;
5235
5236 if (l_installment_number-1) > 0 then
5237 l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
5238 else
5239 l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
5240 end if;
5241
5242 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
5243 -- calculate additional interest on unpaid principal
5244 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
5245 p_calc_method => l_calc_method,
5246 p_period_start_date => l_add_start_date,
5247 p_period_end_date => l_add_end_date,
5248 p_interest_rate => l_annualized_rate,
5249 p_day_count_method => l_day_count_method,
5250 p_payment_freq => l_payment_frequency,
5251 p_compound_freq => l_compound_freq,
5252 p_prev_grace_end_date => l_prev_grace_end_date,
5253 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
5254 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5255 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
5256 p_target => 'UNPAID_PRIN',
5257 x_add_interest => l_add_prin_interest,
5258 x_penal_interest => l_penal_prin_interest);
5259 l_add_prin_interest := round(l_add_prin_interest, l_precision);
5260
5261 if (l_calc_method = 'COMPOUND') then
5262
5263 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
5264 -- calculate additional interest on unpaid interest
5265 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
5266 p_calc_method => l_calc_method,
5267 p_period_start_date => l_add_start_date,
5268 p_period_end_date => l_add_end_date,
5269 p_interest_rate => l_annualized_rate,
5270 p_day_count_method => l_day_count_method,
5271 p_payment_freq => l_payment_frequency,
5272 p_compound_freq => l_compound_freq,
5273 p_prev_grace_end_date => l_prev_grace_end_date,
5274 p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
5275 p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5276 p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
5277 p_target => 'UNPAID_INT',
5278 x_add_interest => l_add_int_interest,
5279 x_penal_interest => l_penal_int_interest);
5280 l_add_int_interest := round(l_add_int_interest, l_precision);
5281
5282 end if;
5283
5284 end if;
5285
5286 else
5287
5288 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_actual);
5289
5290 if (l_calc_method = 'SIMPLE') then
5291
5292 -- recalculate periodic rate for each period if day counting methodolgy varies
5293 l_periodic_rate := lns_financials.getPeriodicRate(
5294 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5295 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5296 ,p_annualized_rate => l_annualized_rate
5297 ,p_days_count_method => l_day_count_method);
5298
5299 elsif (l_calc_method = 'COMPOUND') then
5300
5301 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5302 ,p_payment_freq => l_payment_frequency
5303 ,p_annualized_rate => l_annualized_rate
5304 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5305 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5306 ,p_days_count_method => l_day_count_method);
5307
5308 end if;
5309
5310 l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_actual
5311 ,p_periodic_rate => l_periodic_rate
5312 ,p_compounding_period => null);
5313
5314 l_norm_interest := round(l_norm_interest, l_precision);
5315 end if;
5316
5317 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
5318 l_periodic_interest := round(l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest, l_precision);
5319
5320 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_payment = ' || l_periodic_payment);
5321 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
5322 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
5323 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_intervals_remaining = ' || l_intervals_remaining);
5324 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled_principal = ' || l_unbilled_principal);
5325
5326 -- check to see if we are in an interest only period
5327 -- if this is the case then the periodic_principal = 0
5328 -- there is a chance that the loan negatively amortizes
5329 if l_interest_only_flag <> 'Y' or l_intervals_remaining = 1 then
5330
5331 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculating principal due');
5332 l_periodic_principal := l_periodic_payment - l_periodic_interest;
5333 l_periodic_principal := round(l_periodic_principal, l_precision);
5334
5335 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal = ' || l_periodic_principal);
5336
5337 -- this is temporary according to not letting amortizations go negative
5338 if l_periodic_principal < 0 then
5339 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': DISALLOW NEGATIVE AMORTIZATION');
5340 l_periodic_principal := 0;
5341 end if;
5342
5343 -- if the loan is being pre-paid this will ensure that balance gets to zero
5344 -- make sure the final installment gets the remaining balance on the loan irregardless
5345 if l_remaining_balance_theory < l_periodic_principal then
5346 l_periodic_principal := l_remaining_balance_theory;
5347 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
5348 else
5349 if l_intervals_remaining = 1 then
5350 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
5351 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal is ' || l_unbilled_principal);
5352 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory is ' || l_remaining_balance_theory);
5353 if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
5354 l_periodic_principal := l_unbilled_principal;
5355 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
5356 else
5357 l_periodic_principal := l_remaining_balance_theory;
5358 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
5359 end if;
5360 end if;
5361 end if;
5362
5363 else
5364 -- we are in an interest only period
5365 l_periodic_principal := 0;
5366
5367 end if;
5368
5369 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory is ' || l_remaining_balance_theory);
5370 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': principal is ' || l_periodic_principal);
5371
5372 -- calculate balances and total payment
5373 l_begin_balance := l_remaining_balance_theory;
5374 l_end_balance := l_remaining_balance_theory - l_periodic_principal;
5375 -- l_amortized_amount := l_amortized_amount - l_periodic_principal;
5376
5377 -- check to see if this loan has been billed
5378 if l_unbilled_principal > 0 then
5379 l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
5380 end if;
5381
5382 -- build the amortization record
5383 -- this information is needed to calculate fees
5384 -- rest of the record can be built after fees are calculated
5385 l_amortization_rec.installment_number := l_installment_number; /* needed to calculate fees */
5386 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
5387 l_amortization_rec.PERIOD_START_DATE := l_payment_tbl(l_installment_number).period_begin_date;
5388 l_amortization_rec.PERIOD_END_DATE := l_payment_tbl(l_installment_number).period_end_date;
5389 l_amortization_rec.principal_amount := l_periodic_principal; /* needed to calculate fees */
5390 l_amortization_rec.interest_amount := l_periodic_interest;
5391 l_amortization_rec.begin_balance := l_begin_balance; /* needed to calculate fees */
5392 l_amortization_rec.end_balance := l_end_balance;
5393 l_amortization_rec.rate_id := l_current_rate_id;
5394 l_amortization_rec.rate_unadj := l_annualized_rate;
5395 l_amortization_rec.RATE_CHANGE_FREQ := p_loan_details.TERM_RATE_CHG_FREQ;
5396 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
5397 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
5398 l_amortization_rec.INTEREST_RATE := l_annualized_rate;
5399 l_amortization_rec.NORMAL_INT_AMOUNT := l_norm_interest;
5400 l_amortization_rec.ADD_PRIN_INT_AMOUNT := l_add_prin_interest;
5401 l_amortization_rec.ADD_INT_INT_AMOUNT := l_add_int_interest;
5402 l_amortization_rec.PENAL_INT_AMOUNT := l_penal_interest;
5403
5404 -- calculate fees here
5405 -- should be new routine to simply get the fees from the fee schedule
5406 l_fee_basis_tbl(1).fee_basis_name := 'TOTAL_BAL';
5407 l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance;
5408 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
5409 l_fee_basis_tbl(2).fee_basis_amount := l_original_loan_amount;
5410 l_fee_basis_tbl(3).fee_basis_name := 'IND_DISB_AMOUNT';
5411 l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
5412 --l_fee_basis_tbl(4).fee_basis_name := 'TOTAL_DISB_AMOUNT';
5413 --l_fee_basis_tbl(4).fee_basis_amount := l_original_loan_amount;
5414
5415 if l_installment_number = 1 then
5416 if l_orig_fee_structures.count > 0 then
5417
5418 open c_fees(l_loan_id, l_installment_number);
5419 fetch c_fees into l_fee_amount;
5420 close c_fees;
5421 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
5422
5423 /*
5424 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
5425 ,p_installment => l_installment_number
5426 ,p_fee_basis_tbl => l_fee_basis_tbl
5427 ,p_fee_structures => l_orig_fee_structures
5428 ,x_fees_tbl => l_orig_fees_tbl
5429 ,x_return_status => l_return_status
5430 ,x_msg_count => l_msg_count
5431 ,x_msg_data => l_msg_data);
5432 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated origination fees ' || l_orig_fee_structures.count);
5433 */
5434 end if;
5435 end if;
5436
5437 if l_memo_fee_structures.count > 0 then
5438 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
5439 ,p_installment => l_installment_number
5440 ,p_fee_basis_tbl => l_fee_basis_tbl
5441 ,p_fee_structures => l_memo_fee_structures
5442 ,x_fees_tbl => l_memo_fees_tbl
5443 ,x_return_status => l_return_status
5444 ,x_msg_count => l_msg_count
5445 ,x_msg_data => l_msg_data);
5446 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated memo fees ' || l_memo_fees_tbl.count);
5447 end if;
5448
5449
5450 if l_fee_structures.count > 0 then
5451 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
5452 ,p_installment => l_installment_number
5453 ,p_fee_basis_tbl => l_fee_basis_tbl
5454 ,p_fee_structures => l_fee_structures
5455 ,x_fees_tbl => l_fees_tbl
5456 ,x_return_status => l_return_status
5457 ,x_msg_count => l_msg_count
5458 ,x_msg_data => l_msg_data);
5459 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated fees ' || l_fees_tbl.count);
5460 end if;
5461 /*
5462 for i in 1..l_orig_fees_tbl.count loop
5463 l_fee_amount := l_fee_amount + l_orig_fees_tbl(i).FEE_AMOUNT;
5464 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig calculated fees ' || l_fee_amount);
5465 end loop;
5466 */
5467 for k in 1..l_fees_tbl.count loop
5468 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
5469 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': recurring calculated fees ' || l_fee_amount);
5470 end loop;
5471
5472 for j in 1..l_memo_fees_tbl.count loop
5473 l_other_amount := l_other_amount + l_memo_fees_tbl(j).FEE_AMOUNT;
5474 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': other calculated fees ' || l_other_amount);
5475 end loop;
5476
5477 l_total := l_fee_amount + l_periodic_principal + l_periodic_interest + l_other_amount;
5478 l_amortization_rec.total := l_total;
5479 l_amortization_rec.fee_amount := l_fee_amount;
5480 l_amortization_rec.other_amount := l_other_amount;
5481
5482 -- running totals calculated here
5483 l_principal_cumulative := l_principal_cumulative + l_periodic_principal;
5484 l_interest_cumulative := l_interest_cumulative + l_periodic_interest;
5485 l_fees_cumulative := l_fees_cumulative + l_fee_amount;
5486 l_other_cumulative := l_other_cumulative + l_other_amount;
5487
5488 l_amortization_rec.interest_cumulative := l_interest_cumulative;
5489 l_amortization_rec.principal_cumulative := l_principal_cumulative;
5490 l_amortization_rec.fees_cumulative := l_fees_cumulative;
5491 l_amortization_rec.other_cumulative := l_other_cumulative;
5492 l_amortization_rec.rate_id := l_current_rate_id;
5493 l_amortization_rec.SOURCE := 'PREDICTED';
5494
5495 -- add the record to the amortization table
5496 l_amortization_tbl(i) := l_amortization_rec;
5497
5498 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: due date ' || l_amortization_rec.due_date);
5499 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_principal ' || l_amortization_rec.principal_amount);
5500 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_interest ' || l_amortization_rec.interest_amount);
5501 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fee_amount is ' || l_amortization_rec.fee_amount);
5502 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: total is ' || l_amortization_rec.total);
5503 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: other_amount is ' || l_amortization_rec.other_amount);
5504 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: begin_balance is ' || l_amortization_rec.begin_balance);
5505 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: end_balance is ' || l_amortization_rec.end_balance);
5506 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: interest_cumulative is ' || l_amortization_rec.interest_cumulative);
5507 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: principal_cumulative is ' || l_amortization_rec.principal_cumulative);
5508 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fees_cumulative is ' || l_amortization_rec.fees_cumulative);
5509 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: other_cumulative is ' || l_amortization_rec.other_cumulative);
5510 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: current_rate_id is ' || l_amortization_rec.rate_id );
5511
5512 -- adjust new loan amount to reflect less periodic principal paid
5513 -- theoretically without over/underpayments l_loan_amount should = l_remaining_balance
5514 -- if they diverge then we will calculate interest based from l_remaining_balance
5515 -- rather than l_loan_amount
5516 l_remaining_balance_theory := l_end_balance;
5517
5518 if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number)
5519 and p_based_on_terms = 'CURRENT' then
5520 l_remaining_balance_actual := l_remaining_balance_theory;
5521 else
5522 l_remaining_balance_actual := l_remaining_balance_actual - l_periodic_principal;
5523 end if;
5524
5525 -- clean up
5526 l_orig_fees_tbl.delete;
5527 l_memo_fees_tbl.delete;
5528 l_fees_tbl.delete;
5529
5530 end loop;
5531
5532 --printAmortizationTable(p_amort_tbl => l_amortization_tbl);
5533
5534 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT IS ' || l_amortization_tbl.count);
5535 x_loan_amort_tbl := l_amortization_tbl;
5536
5537 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
5538
5539 Exception
5540 WHEN FND_API.G_EXC_ERROR THEN
5541 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
5542
5543 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
5544 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
5545
5546 WHEN OTHERS THEN
5547 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
5548
5549 end amortizeLoan;
5550
5551 /*=========================================================================
5552 || PUBLIC PROCEDURE amortizeLoan
5553 ||
5554 || DESCRIPTION
5555 ||
5556 || Overview: amortizes a loan
5557 || this api assumes the loan information is in the
5558 || Loans DataModel
5559 ||
5560 || Parameter: p_loan_id => Loan ID
5561 ||
5562 || Source Tables: NA
5563 ||
5564 || Target Tables: NA
5565 ||
5566 || Return value: x_loan_amort_tbl table of amortization_records
5567 ||
5568 || KNOWN ISSUES
5569 ||
5570 || NOTES
5571 ||
5572 || MODIFICATION HISTORY
5573 || Date Author Description of Changes
5574 || 12/09/2003 1:51PM raverma Created
5575 || 04/07/2004 raverma alter so we dont need to loop thru
5576 || whole amortization
5577 *=======================================================================*/
5578 procedure amortizeLoan (p_loan_Id in number
5579 ,p_based_on_terms in varchar2
5580 ,p_installment_number in number
5581 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
5582
5583 is
5584 l_loan_details LOAN_DETAILS_REC;
5585 l_amortization_tbl amortization_tbl;
5586 l_rate_tbl RATE_SCHEDULE_TBL;
5587 l_api_name varchar2(20);
5588 begin
5589
5590 l_api_name := 'amortizeLoan LOANID';
5591 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
5592 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
5593 ,p_based_on_terms => p_based_on_terms
5594 ,p_phase => 'TERM');
5595
5596 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
5597
5598 if (l_loan_details.PAYMENT_CALC_METHOD = 'EQUAL_PRINCIPAL') then
5599
5600 lns_financials.amortizeEPLoan(p_loan_details => l_loan_details
5601 ,p_rate_schedule => l_rate_tbl
5602 ,p_based_on_terms => p_based_on_terms
5603 ,p_installment_number => p_installment_number
5604 ,x_loan_amort_tbl => l_amortization_tbl);
5605
5606 elsif (l_loan_details.PAYMENT_CALC_METHOD = 'SEPARATE_SCHEDULES') then
5607
5608 lns_financials.amortizeSIPLoan(p_loan_details => l_loan_details
5609 ,p_rate_schedule => l_rate_tbl
5610 ,p_based_on_terms => p_based_on_terms
5611 ,p_installment_number => p_installment_number
5612 ,x_loan_amort_tbl => l_amortization_tbl);
5613
5614 elsif (l_loan_details.PAYMENT_CALC_METHOD = 'EQUAL_PAYMENT') then
5615
5616 lns_financials.amortizeLoan(p_loan_details => l_loan_details
5617 ,p_rate_schedule => l_rate_tbl
5618 ,p_based_on_terms => p_based_on_terms
5619 ,p_installment_number => p_installment_number
5620 ,x_loan_amort_tbl => l_amortization_tbl);
5621
5622 end if;
5623
5624 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' Tbl count is ' || l_amortization_tbl.count);
5625
5626 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
5627 x_loan_amort_tbl := l_amortization_tbl;
5628 Exception
5629 When others then
5630 null;
5631
5632 end amortizeLoan;
5633
5634 /*=========================================================================
5635 || PUBLIC PROCEDURE loanProjection
5636 ||
5637 || DESCRIPTION
5638 ||
5639 || Overview: procedure will project an open ended loan
5640 || 1. Amortization UI - when creating a loan
5641 || 2. Billing Engine - to generate bills
5642 ||
5643 || Parameter: p_loan_details = details of the loan
5644 || p_rate_schedule = rate schedule for the loan
5645 || x_loan_amort_tbl => table of loan records
5646 ||
5647 || Source Tables: NA
5648 ||
5649 || Target Tables:
5650 ||
5651 ||
5652 || KNOWN ISSUES
5653 || Currently only support single rate
5654 || NOTES
5655 ||
5656 || MODIFICATION HISTORY
5657 || Date Author Description of Changes
5658 || 07/20/2005 11:35AM raverma Created
5659 *=======================================================================*/
5660 procedure loanProjection(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
5661 ,p_rate_schedule in LNS_FINANCIALS.RATE_SCHEDULE_TBL
5662 ,x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
5663 is
5664 l_return_status varchar2(1);
5665 l_msg_count NUMBER;
5666 l_msg_data VARCHAR2(32767);
5667 -- loan_details
5668 l_loan_id number;
5669 l_original_loan_amount number; -- loan amount
5670 l_first_payment_date date;
5671 l_pay_in_arrears boolean;
5672 l_payment_frequency varchar2(30);
5673 l_day_count_method varchar2(30);
5674 l_intervals_original number;
5675 l_intervals number;
5676 l_intervals_remaining number;
5677 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
5678 l_precision number;
5679
5680 l_period_start_Date date;
5681 l_period_end_date date;
5682 l_periodic_rate number;
5683 l_maturity_date date;
5684
5685 l_amortization_rec LNS_FINANCIALS.AMORTIZATION_REC;
5686 l_amortization_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
5687 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
5688 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
5689 l_loan_start_date date;
5690 l_num_pay_dates number; -- number of dates on installment schedule
5691 l_periodic_payment number;
5692 l_periodic_principal number;
5693 l_periodic_interest number;
5694 l_total_principal number;
5695 l_payment_number number;
5696 l_fee_amount number;
5697 l_begin_balance number;
5698 l_end_balance number;
5699 l_unbilled_principal number;
5700 l_unpaid_principal number;
5701 --l_open_rate_type varchar2(30);
5702 l_open_rate_change_frequency varchar2(30);
5703 l_open_index_rate_id number;
5704 l_open_index_date date;
5705 l_open_ceiling_rate number;
5706 l_open_floor_rate number;
5707 l_unpaid_interest number;
5708
5709 l_wtd_balance number;
5710 l_total number;
5711 l_interest_cumulative number;
5712 l_principal_cumulative number;
5713 l_fees_cumulative number;
5714 i number; -- for installments
5715 k number; -- for disbursements
5716 l_installment_number number;
5717 l_api_name varchar2(20);
5718 l_last_installment_billed number;
5719 l_rate_to_calculate number;
5720 l_disb_header_id number;
5721 l_disb_amount number;
5722 l_total_disbursed number;
5723 l_calc_method varchar2(30);
5724 l_compound_freq varchar2(30);
5725
5726 -- for fees
5727 l_orig_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
5728 l_calc_fee_structures LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
5729 l_orig_fees_tbl LNS_FEE_ENGINE.FEE_CALC_TBL;
5730 l_fee_basis_tbl LNS_FEE_ENGINE.FEE_BASIS_TBL;
5731
5732 -- total fees on the schedule by installment
5733 cursor c_fees(p_loan_id number, p_installment number) is
5734 select nvl(sum(sched.fee_amount), 0)
5735 from lns_fee_schedules sched
5736 ,lns_fees struct
5737 where sched.loan_id = p_loan_id
5738 and sched.fee_id = struct.fee_id
5739 and fee_installment = p_installment
5740 and active_flag = 'Y';
5741
5742 cursor c_total_disbursed(p_loan_id number, p_from_date date, p_to_date date)
5743 is
5744 select nvl(sum(header_amount), 0)
5745 from lns_disb_headers
5746 where loan_id = p_loan_id
5747 and trunc(payment_request_date) >= p_from_date
5748 and trunc(payment_request_date) < p_to_date;
5749
5750 begin
5751
5752 -- initialize all variables
5753 l_original_loan_amount := 0; -- loan amount
5754 l_periodic_payment := 0;
5755 l_periodic_principal := 0;
5756 l_periodic_interest := 0;
5757 l_total_principal := 0;
5758 l_payment_number := 0;
5759 l_fee_amount := 0;
5760 l_begin_balance := 0;
5761 l_unbilled_principal := 0;
5762 l_unpaid_principal := 0;
5763 l_total := 0;
5764 l_interest_cumulative := 0;
5765 l_principal_cumulative := 0;
5766 l_fees_cumulative := 0;
5767 i := 0;
5768 l_installment_number := 1; -- begin from #1 installment, NOT #0 installment
5769 l_rate_to_calculate := 0;
5770 l_total_disbursed := 0;
5771 l_api_name := 'loanProjection';
5772
5773 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
5774
5775 l_payment_frequency := p_loan_details.payment_frequency;
5776 l_first_payment_date := p_loan_details.first_payment_date;
5777 l_original_loan_amount := p_loan_details.funded_amount;
5778 l_maturity_date := p_loan_details.maturity_date;
5779 l_intervals := p_loan_details.number_installments;
5780 l_last_installment_billed := p_loan_details.last_installment_billed;
5781 l_day_count_method := p_loan_details.day_count_method;
5782 l_loan_start_date := p_loan_details.loan_start_date;
5783 l_pay_in_arrears := p_loan_details.pay_in_arrears_boolean;
5784 l_precision := p_loan_details.currency_precision;
5785 l_loan_id := p_loan_details.loan_id;
5786 -- use the projected rate which should be the last calculated rate on the loan
5787 l_periodic_rate := p_loan_details.OPEN_PROJECTED_INTEREST_RATE;
5788 l_calc_method := p_loan_details.CALCULATION_METHOD;
5789 l_compound_freq := p_loan_details.INTEREST_COMPOUNDING_FREQ;
5790 l_unpaid_principal := p_loan_details.unpaid_principal;
5791 l_unpaid_interest := p_loan_details.UNPAID_INTEREST;
5792
5793 -- get the interest rate schedule
5794 l_rate_tbl := p_rate_schedule;
5795 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count: ' || l_rate_tbl.count);
5796
5797 -- get payment schedule
5798 -- this will return the acutal dates that payments will be due on
5799 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
5800 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => l_loan_start_date
5801 ,p_loan_maturity_date => l_maturity_date
5802 ,p_first_pay_date => l_first_payment_date
5803 ,p_num_intervals => l_intervals
5804 ,p_interval_type => l_payment_frequency
5805 ,p_pay_in_arrears => l_pay_in_arrears);
5806
5807 l_num_pay_dates := l_payment_tbl.count;
5808 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count: ' || l_num_pay_dates);
5809
5810 -- loop to build the amortization schedule
5811 for l_installment_number in 1..l_num_pay_dates
5812 loop
5813
5814 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' -----CALCULATING -----> installment #' || l_installment_number);
5815 i := i + 1;
5816 l_periodic_interest := 0;
5817 l_fee_amount := 0;
5818 l_intervals_remaining := l_num_pay_dates - l_installment_number + 1;
5819
5820 -- get the total funded amount
5821 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' getting total funded amount thru' || l_payment_tbl(l_installment_number).period_end_date);
5822
5823 open c_total_disbursed(l_loan_id , l_payment_tbl(1).period_begin_date , l_payment_tbl(l_installment_number).period_end_date);
5824 fetch c_total_disbursed into l_end_balance;
5825 close c_total_disbursed;
5826
5827 l_begin_balance := l_end_balance;
5828
5829 -- get the weighted balance for the period
5830 begin
5831 l_wtd_balance := lns_financials.getWeightedBalance(p_loan_id => l_loan_id
5832 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
5833 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
5834 ,p_calc_method => 'TARGET'
5835 ,p_phase => 'OPEN'
5836 ,p_day_count_method => l_day_count_method);
5837 exception
5838 when others then
5839 FND_MESSAGE.SET_NAME('LNS', 'LNS_COMPUTE_BALANCE_ERROR');
5840 FND_MSG_PUB.ADD;
5841 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - ERROR COMPUTING BALANCE');
5842 RAISE FND_API.G_EXC_ERROR;
5843 end;
5844
5845 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - l_wtd_balance is ' || l_wtd_balance);
5846
5847 -- now we will caculate the interest due for this period
5848 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_wtd_balance);
5849
5850 -- recalculate periodic rate for each period if day counting methodolgy varies
5851 if (l_calc_method = 'SIMPLE') then
5852 l_periodic_rate := lns_financials.getPeriodicRate(p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5853 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5854 ,p_annualized_rate => p_loan_details.OPEN_PROJECTED_INTEREST_RATE
5855 ,p_days_count_method => l_day_count_method);
5856 elsif (l_calc_method = 'COMPOUND') then
5857
5858 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5859 ,p_payment_freq => l_payment_frequency
5860 ,p_annualized_rate => p_loan_details.OPEN_PROJECTED_INTEREST_RATE
5861 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5862 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5863 ,p_days_count_method => l_day_count_method);
5864
5865 end if;
5866 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate rate is ' || l_periodic_rate);
5867
5868 -- if we are going to compound, then based on compounding the amount should be passed to calculateInterest call here.
5869 -- how do we determine what the amount to compound on
5870 -- for example: compound daily at .5% over 30 day period
5871 l_periodic_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
5872 ,p_periodic_rate => l_periodic_rate
5873 ,p_compounding_period => null);
5874
5875 l_periodic_interest := round(l_periodic_interest, l_precision);
5876 --mark
5877 if l_installment_number = p_loan_details.number_installments and
5878 (p_loan_details.OPEN_TO_TERM_FLAG = 'N' OR p_loan_details.SECONDARY_STATUS = 'REMAINING_DISB_CANCELLED') then
5879 l_periodic_principal := p_loan_details.funded_amount;
5880 else
5881 l_periodic_principal := 0;
5882 end if;
5883
5884 -- get the disbursement fees
5885 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting origination fee structures');
5886 l_orig_fee_structures := lns_fee_engine.getDisbursementFeeStructures(p_loan_id => l_loan_id
5887 ,p_fee_category => 'EVENT'
5888 ,p_fee_type => 'EVENT_ORIGINATION'
5889 ,p_from_date => l_payment_tbl(l_installment_number).period_begin_date
5890 ,p_to_date => l_payment_tbl(l_installment_number).period_end_date
5891 ,p_disb_header_id => null
5892 ,p_fee_id => null);
5893 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': orig structures count is ' || l_orig_fee_structures.count);
5894
5895 -- calculate the fees one by one
5896 for j in 1..l_orig_fee_structures.count
5897 loop
5898 -- get the fee basis
5899 -- get the total disbursed thru the target date of the fee
5900 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': IND_DISB_AMOUNT ' || l_orig_fee_structures(j).disbursement_date);
5901 l_fee_basis_tbl(1).fee_basis_name := 'IND_DISB_AMT';
5902 l_fee_basis_tbl(1).fee_basis_amount := l_orig_fee_structures(j).disbursement_amount;
5903 l_fee_basis_tbl(2).fee_basis_name := 'ORIG_LOAN';
5904 l_fee_basis_tbl(2).fee_basis_amount := l_original_loan_amount;
5905 l_calc_fee_structures(1) := l_orig_fee_structures(j);
5906 lns_fee_engine.calculateFees(p_loan_id => l_loan_id
5907 ,p_installment => 0
5908 ,p_fee_basis_tbl => l_fee_basis_tbl
5909 ,p_fee_structures => l_calc_fee_structures
5910 ,x_fees_tbl => l_orig_fees_tbl
5911 ,x_return_status => l_return_status
5912 ,x_msg_count => l_msg_count
5913 ,x_msg_data => l_msg_data);
5914 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculated origination fees ' || l_orig_fees_tbl.count);
5915 for m in 1..l_orig_fees_tbl.count
5916 loop
5917 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': m ' || l_orig_fees_tbl(m).FEE_AMOUNT);
5918 l_fee_amount := l_fee_amount + l_orig_fees_tbl(m).FEE_AMOUNT;
5919 end loop;
5920
5921 end loop;
5922
5923 -- rest of the record can be built after fees are calculated
5924 l_amortization_rec.installment_number := l_installment_number;
5925 l_amortization_rec.due_date := l_payment_tbl(l_installment_number).period_due_date;
5926 l_amortization_rec.principal_amount := l_periodic_principal;
5927 l_amortization_rec.interest_amount := l_periodic_interest;
5928 l_amortization_rec.begin_balance := l_begin_balance;
5929 l_amortization_rec.end_balance := l_end_balance;
5930 l_amortization_rec.other_amount := 0;
5931 l_amortization_rec.UNPAID_PRIN := l_unpaid_principal;
5932 l_amortization_rec.UNPAID_INT := l_unpaid_interest;
5933 l_amortization_rec.INTEREST_RATE := p_loan_details.OPEN_PROJECTED_INTEREST_RATE;
5934
5935 l_total := l_fee_amount + l_periodic_principal + l_periodic_interest;
5936 l_amortization_rec.total := l_total;
5937 l_amortization_rec.fee_amount := l_fee_amount;
5938
5939 -- running totals calculated here
5940 --l_principal_cumulative := l_principal_cumulative + l_periodic_principal;
5941 l_interest_cumulative := l_interest_cumulative + l_periodic_interest;
5942 l_fees_cumulative := l_fees_cumulative + l_fee_amount;
5943
5944 l_amortization_rec.interest_cumulative := l_interest_cumulative;
5945 l_amortization_rec.principal_cumulative := l_principal_cumulative;
5946 l_amortization_rec.fees_cumulative := l_fees_cumulative;
5947 l_amortization_rec.SOURCE := 'PREDICTED';
5948
5949 -- add the record to the amortization table
5950 l_amortization_tbl(i) := l_amortization_rec;
5951
5952 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: due date ' || l_amortization_rec.due_date);
5953 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_principal ' || l_amortization_rec.principal_amount);
5954 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_interest ' || l_amortization_rec.interest_amount);
5955 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fee_amount is ' || l_amortization_rec.fee_amount);
5956 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: total is ' || l_amortization_rec.fee_amount);
5957 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: begin_balance is ' || l_amortization_rec.begin_balance);
5958 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: end_balance is ' || l_amortization_rec.end_balance);
5959 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: interest_cumulative is ' || l_amortization_rec.interest_cumulative);
5960 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: principal_cumulative is ' || l_amortization_rec.principal_cumulative);
5961 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fees_cumulative is ' || l_amortization_rec.fees_cumulative);
5962
5963 end loop;
5964 --printAmortizationTable(p_amort_tbl => l_amortization_tbl);
5965
5966 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT IS ' || l_amortization_tbl.count);
5967 x_loan_amort_tbl := l_amortization_tbl;
5968
5969 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
5970
5971 Exception
5972 WHEN FND_API.G_EXC_ERROR THEN
5973 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
5974
5975 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
5976 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
5977
5978 WHEN OTHERS THEN
5979 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
5980
5981 end loanProjection;
5982
5983 /*=========================================================================
5984 || PUBLIC PROCEDURE runLoanProjection
5985 ||
5986 || DESCRIPTION
5987 ||
5988 || Overview: procedure will run a loan projection ||
5989 || Parameter: loan_id
5990 ||
5991 || Source Tables: LNS_LOAN_HEADERS, LNS_TERMS, LNS_RATE_SCHEDULES,
5992 || LNS_DISB_HEADERS, LNS_DISB_LINES
5993 ||
5994 || Target Tables: None
5995 ||
5996 || Return value: x_amort_tbl is table of amortization records
5997 ||
5998 || KNOWN ISSUES
5999 ||
6000 || NOTES
6001 ||
6002 || MODIFICATION HISTORY
6003 || Date Author Description of Changes
6004 || 07/18/2005 11:35AM raverma Created
6005 || 08/29/2005 raverma throw error if invalid dates
6006 *=======================================================================*/
6007 procedure runOpenProjection(p_init_msg_list IN VARCHAR2
6008 ,p_loan_ID IN NUMBER
6009 ,p_based_on_terms IN VARCHAR2
6010 ,x_amort_tbl OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_TBL
6011 ,x_return_status OUT NOCOPY VARCHAR2
6012 ,x_msg_count OUT NOCOPY NUMBER
6013 ,x_msg_data OUT NOCOPY VARCHAR2)
6014 is
6015
6016 l_api_name varchar2(25);
6017 l_api_version_number number;
6018 l_return_status VARCHAR2(1);
6019 l_msg_count NUMBER;
6020 l_msg_data VARCHAR2(32767);
6021
6022 l_amort_tbl LNS_FINANCIALS.AMORTIZATION_TBL;
6023 l_amort_tbl2 LNS_FINANCIALS.AMORTIZATION_TBL;
6024 l_total_amortization LNS_FINANCIALS.AMORTIZATION_REC;
6025 b_showActual boolean := false;
6026 l_last_installment_billed number;
6027
6028 l_num_records number;
6029 i number;
6030 m number;
6031 l_records_to_copy number;
6032 l_num_installments number;
6033 l_num_rows number;
6034 l_manual_fee_amount number;
6035 l_records_to_destroy number;
6036 l_start_date number;
6037 l_funded_amount number;
6038 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
6039 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
6040 l_disb_amount number;
6041 l_invalid_disb number;
6042
6043 -- get the sum of fees for a given loan for a given installment
6044 cursor c_fees(p_loan_id number, p_installment number) is
6045 select nvl(sum(sched.fee_amount), 0)
6046 from lns_fee_schedules sched
6047 ,lns_fees struct
6048 where sched.loan_id = p_loan_id
6049 and sched.fee_id = struct.fee_id
6050 and fee_installment = p_installment
6051 and active_flag = 'Y';
6052
6053 -- bug # 4258345
6054 -- add late fees to
6055 cursor c_manual_fees(p_loan_id number, p_installment number) is
6056 select sum(nvl(fee_amount,0))
6057 from lns_fee_schedules sch,
6058 lns_fees fees
6059 where sch.active_flag = 'Y'
6060 and sch.billed_flag = 'N'
6061 and fees.fee_id = sch.fee_id
6062 and ((fees.fee_category = 'MANUAL')
6063 OR (fees.fee_category = 'EVENT' AND fees.fee_type = 'EVENT_LATE_CHARGE'))
6064 and sch.loan_id = p_loan_id
6065 and fee_installment = p_installment;
6066
6067 cursor c_disbursements(p_loan_id number) is
6068 select nvl(sum(header_amount), 0)
6069 from lns_disb_headers
6070 where loan_id = p_loan_id;
6071
6072 -- if there is a return count then some dates are invalid
6073 cursor c_invalid_disb(p_loan_id number) is
6074 select count(1)
6075 from lns_disb_headers dh
6076 ,lns_loan_headers h
6077 where h.loan_id = dh.loan_id
6078 and trunc(dh.payment_request_date) < trunc(h.open_loan_start_date)
6079 and h.loan_id = p_loan_id;
6080
6081 BEGIN
6082 -- Standard Start of API savepoint
6083 SAVEPOINT runLoanProjection_PVT;
6084 l_api_name := 'runLoanProjection';
6085 i := 0;
6086 l_manual_fee_amount := 0;
6087
6088 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6089
6090 -- Initialize message list IF p_init_msg_list is set to TRUE.
6091 IF FND_API.to_Boolean( p_init_msg_list ) THEN
6092 FND_MSG_PUB.initialize;
6093 END IF;
6094
6095 -- Initialize API return status to SUCCESS
6096 x_return_status := FND_API.G_RET_STS_SUCCESS;
6097
6098 --
6099 -- Api body
6100 -- ----------------------------------------------------------------
6101 -- validate loan_id
6102 lns_utility_pub.validate_any_id(p_api_version => 1.0
6103 ,p_init_msg_list => p_init_msg_list
6104 ,x_msg_count => l_msg_count
6105 ,x_msg_data => l_msg_data
6106 ,x_return_status => l_return_status
6107 ,p_col_id => p_loan_id
6108 ,p_col_name => 'LOAN_ID'
6109 ,p_table_name => 'LNS_LOAN_HEADERS_ALL');
6110
6111 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
6112 FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
6113 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
6114 FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
6115 FND_MSG_PUB.ADD;
6116 RAISE FND_API.G_EXC_ERROR;
6117 end if;
6118
6119 -- check if disbursements exist and is amount > 0 as per karthik instructions
6120 open c_disbursements(p_loan_id);
6121 fetch c_disbursements into l_disb_amount;
6122 close c_disbursements;
6123
6124 -- check if disbursement dates are valid
6125 open c_invalid_disb(p_loan_id);
6126 fetch c_invalid_disb into l_invalid_disb;
6127 close c_invalid_disb;
6128
6129 if l_invalid_disb > 0 then
6130 FND_MESSAGE.SET_NAME('LNS', 'LNS_DISB_REQ_DATE_ERR');
6131 FND_MSG_PUB.ADD;
6132 RAISE FND_API.G_EXC_ERROR;
6133 end if;
6134
6135 if l_disb_amount > 0 then
6136 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'OPEN');
6137 l_loan_details := lns_financials.getLoanDetails(p_loan_Id => p_loan_id
6138 ,p_based_on_terms => p_based_on_terms
6139 ,p_phase => 'OPEN');
6140
6141 -- call projection API
6142 lns_financials.loanProjection(p_loan_details => l_loan_details
6143 ,p_rate_schedule => l_rate_tbl
6144 ,x_loan_amort_tbl => l_amort_tbl);
6145
6146 -- delete predicted records based on ORIGINAL amortization
6147 if p_based_on_terms = 'CURRENT' then
6148
6149 l_num_records := l_amort_tbl.count;
6150 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - amortization returns # records '|| l_num_records);
6151 l_last_installment_billed := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER_EXT(p_loan_id);
6152 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - last installment billed '|| l_last_installment_billed);
6153
6154 -- copy the records not billed to a temp collection
6155 m := 0;
6156 for i in 1..l_num_records
6157 loop
6158 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - copying record ' || i);
6159 if l_amort_tbl(i).installment_number > l_last_installment_billed then
6160 m := m + 1;
6161 l_amort_tbl2(m) := l_amort_tbl(i);
6162 end if;
6163 end loop;
6164
6165 -- copy back to original table
6166 l_amort_tbl.delete;
6167 m := 0;
6168 for i in 1..l_amort_tbl2.count
6169 loop
6170 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - re-copying record ' || i);
6171 m := m + 1;
6172 l_amort_tbl(m) := l_amort_tbl2(i);
6173 end loop;
6174
6175 -- finally get the manual fees for the 1st record and add them to the total "other Amount"
6176 -- there has got to be a better way to do this
6177 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - late + manual fee amount is '|| l_manual_fee_amount);
6178 begin
6179 open c_manual_fees(p_loan_id, l_last_installment_billed + 1);
6180 fetch c_manual_fees into l_manual_fee_amount;
6181 close c_manual_fees;
6182 end;
6183
6184 if l_manual_fee_amount is null then
6185 l_manual_fee_amount := 0;
6186 end if;
6187 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - manual fee amount is '|| l_manual_fee_amount);
6188
6189 if l_amort_tbl.count > 0 then
6190 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': adding fees...');
6191 l_amort_tbl(1).fee_amount := l_amort_tbl(1).fee_amount + l_manual_fee_amount;
6192 l_amort_tbl(1).total := l_amort_tbl(1).total + l_manual_fee_amount;
6193 end if;
6194
6195 end if;
6196 end if; -- disb amount > 0
6197 x_amort_tbl := l_amort_tbl;
6198 --
6199 -- End of API body
6200 --
6201
6202 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
6203
6204 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6205
6206 EXCEPTION
6207 WHEN FND_API.G_EXC_ERROR THEN
6208 ROLLBACK TO runLoanProjection_PVT;
6209 x_return_status := FND_API.G_RET_STS_ERROR;
6210 x_msg_count := l_msg_count;
6211 x_msg_data := l_msg_data;
6212 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
6213 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6214
6215 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6216 ROLLBACK TO runLoanProjection_PVT;
6217 x_return_status := FND_API.G_RET_STS_ERROR;
6218 x_msg_count := l_msg_count;
6219 x_msg_data := l_msg_data;
6220 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
6221 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6222
6223 WHEN OTHERS THEN
6224 ROLLBACK TO runLoanProjection_PVT;
6225 x_return_status := FND_API.G_RET_STS_ERROR;
6226 x_msg_count := l_msg_count;
6227 x_msg_data := l_msg_data;
6228 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
6229 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6230
6231 END runOpenProjection;
6232
6233 ---------------------------------------------------------------------------
6234 --- rate routines
6235 ---------------------------------------------------------------------------
6236 /*=========================================================================
6237 || PUBLIC PROCEDURE getRateSchedule - R12
6238 ||
6239 || DESCRIPTION
6240 ||
6241 || Overview: this api is used to get the rate schedule for a loan
6242 ||
6243 || Parameter: loan_id,
6244 || p_phase 'OPEN' or 'TERM'
6245 ||
6246 || Source Tables: LNS_RATE_SCHEDULES, LNS_TERMS, LNS_LOAN_HEADER_ALL
6247 ||
6248 || Target Tables: NA
6249 ||
6250 || Return value: rate_schedule_tbl which is defined as
6251 || TYPE INTEREST_RATE_REC IS RECORD(
6252 || BEGIN_DATE DATE,
6253 || END_DATE DATE,
6254 || ANNUAL_RATE NUMBER);
6255 || TYPE RATE_SCHEDULE_TBL IS TABLE OF INTEREST_RATE_REC INDEX BY BINARY_INTEGER;
6256 ||
6257 || KNOWN ISSUES
6258 ||
6259 || NOTES
6260 || NOTE: INSTALLMENT_NUMBER WILL NOT GET YOU THE GIVEN INSTALLMENT
6261 || NUMBER CORRESPONDING ON THE LOAN AMORTIZATION SCHEDULE
6262 ||
6263 || MODIFICATION HISTORY
6264 || Date Author Description of Changes
6265 || 07/18/2005 6:42PM raverma Created
6266 *=======================================================================*/
6267 function getRateSchedule(p_loan_id in number
6268 ,p_phase in varchar2) return LNS_FINANCIALS.RATE_SCHEDULE_TBL
6269 is
6270
6271 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
6272 l_rate_id number;
6273 l_annual_rate number; -- can be null if floating
6274 l_spread number;
6275 l_start_date date;
6276 l_begin_installment number;
6277 l_end_installment number;
6278 l_interest_only_flag varchar2(1);
6279 l_floating_flag varchar2(1);
6280 l_end_date date;
6281 i number;
6282 l_api_name varchar2(20);
6283
6284 cursor c_rate_schedule (p_loan_id number, p_phase varchar2)
6285 is
6286 select rate_id
6287 ,current_interest_rate
6288 ,nvl(spread, 0)
6289 ,trunc(start_date_active)
6290 ,trunc(end_date_active)
6291 ,begin_installment_number
6292 ,end_installment_number
6293 ,nvl(interest_only_flag, 'N')
6294 ,nvl(floating_flag, 'N')
6295 from lns_loan_headers_all h,
6296 lns_terms t,
6297 lns_rate_schedules rs
6298 where h.loan_id = p_loan_id
6299 and h.loan_id = t.loan_id
6300 and t.term_id = rs.term_id
6301 and rs.end_date_active is null
6302 and nvl(phase, 'TERM') = p_phase
6303 order by begin_installment_number
6304 ,start_date_active;
6305
6306 begin
6307
6308 i := 0;
6309 l_api_name := 'getRateSchedule';
6310 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6311
6312 Begin
6313 OPEN c_rate_schedule(p_loan_id, p_phase);
6314 LOOP
6315 i := i + 1;
6316 FETCH c_rate_schedule INTO
6317 l_rate_id
6318 ,l_annual_rate
6319 ,l_spread
6320 ,l_start_date
6321 ,l_end_date
6322 ,l_begin_installment
6323 ,l_end_installment
6324 ,l_interest_only_flag
6325 ,l_floating_flag;
6326 EXIT WHEN c_rate_schedule%NOTFOUND;
6327 l_rate_tbl(i).rate_id := l_rate_id;
6328 l_rate_tbl(i).annual_rate := l_annual_rate;
6329 l_rate_tbl(i).spread := l_spread;
6330 l_rate_tbl(i).begin_date := l_start_date;
6331 l_rate_tbl(i).end_date := l_end_date;
6332 l_rate_tbl(i).begin_installment_number := l_begin_installment;
6333 l_rate_tbl(i).end_installment_number := l_end_installment;
6334 l_rate_tbl(i).interest_only_flag := l_interest_only_flag;
6335 l_rate_tbl(i).FLOATING_FLAG := l_floating_flag;
6336 END LOOP;
6337 Exception
6338 When No_Data_Found then
6339 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_RATES');
6340 FND_MSG_PUB.Add;
6341 RAISE FND_API.G_EXC_ERROR;
6342 End;
6343
6344 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6345
6346 return l_rate_tbl;
6347
6348 Exception
6349 WHEN FND_API.G_EXC_ERROR THEN
6350 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6351
6352 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6353 logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
6354
6355 WHEN OTHERS THEN
6356 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6357
6358 end getRateSchedule;
6359
6360 /*=========================================================================
6361 || PUBLIC PROCEDURE getWeightedRate
6362 ||
6363 || DESCRIPTION
6364 ||
6365 || Overview: Calculates the weighted average interest rate for a period
6366 || of time for a table of rates
6367 ||
6368 || Parameter: p_start_date => date to begin periodic rate (last interest accrual date for loan payoff)
6369 || p_end_date => date to end periodic rate
6370 || p_rate_tbl => table of rate schedules
6371 ||
6372 || Source Tables: NA
6373 ||
6374 || Target Tables: NA
6375 ||
6376 || Return value: Annualized Rate weighted by rates
6377 ||
6378 || KNOWN ISSUES
6379 || rounding? only works to the daily level
6380 || days count method is unclear? (see function intervalsInPeriod)
6381 || any dates left out will be assumed to be interest rate of 0
6382 ||
6383 || there are 9 scenarios possible:
6384 ||
6385 || P_Start_Date p_End_date
6386 || +------------------------------------+ (time line to get periodic rate)
6387 ||
6388 || Scen 1: (rate tbl matches exactly)
6389 || +------------------------------------+ (time line to get periodic rate)
6390 || +------------------------------------+ (rate table time line)
6391 ||
6392 || Scen 2: (rate tbl further than end date)
6393 || +------------------------------------+ (time line to get periodic rate)
6394 || +------------------------------------------+ (rate table time line)
6395 ||
6396 || Scen 3: (rate tbl shorter than end date)
6397 || +------------------------------------+ (time line to get periodic rate)
6398 || +-------------------------------+ (rate table time line)
6399 ||
6400 || Scen 4: (rate tbl before start date)
6401 || +------------------------------------+ (time line to get periodic rate)
6402 || +----------------------------------------+ (rate table time line)
6403 ||
6404 || Scen 5: (rate tbl before start date)
6405 || +------------------------------------+ (time line to get periodic rate)
6406 || +----------------------------------------+ (rate table time line)
6407 ||
6408 || Scen 6: (rate tbl after start date)
6409 || +------------------------------------+ (time line to get periodic rate)
6410 || +-------------------------------+ (rate table time line)
6411 ||
6412 || Scen 7: (rate tbl is shorter than period)
6413 || +------------------------------------+ (time line to get periodic rate)
6414 || +-------------------------+ (rate table time line)
6415 ||
6416 || Scen 8: (rate tbl is longer than period)
6417 || +------------------------------------+ (time line to get periodic rate)
6418 || +-------------------------------------------------------+ (rate table time line)
6419 ||
6420 || Scen 9: (rate tbl is not contiguous)
6421 || +------------------------------------+ (time line to get periodic rate)
6422 || +--+ +---+ +------+ +-----+ (rate table time line)
6423 ||
6424 ||
6425 || only scenarios 3, 6, 7, 9 do we have periods to assume that rate is = 0
6426 || in all other scenarios the rate table covers the period of time allotted
6427 ||
6428 || also, it is assumed that the rate table is a contiguous period of time
6429 ||
6430 || NOTES
6431 ||
6432 || there are implicit assumptions that CANNOT be made when calculating
6433 || wtd avg interest for a given period.
6434 || for example, you cannot simply put in a
6435 || [ (# days @ rate 1 X rate 1) +
6436 || (# days @ rate 2 X rate 2) +
6437 || (# days @ rate 3 X rate 3) + ]
6438 || / total # days in rate schedule
6439 || because we may have p_start_date > rate 1 start date and
6440 || p_end_date < rate 3 end date
6441 ||
6442 ||
6443 || MODIFICATION HISTORY
6444 || Date Author Description of Changes
6445 || 2/09/2003 1:51PM raverma Created
6446 ||
6447 *=======================================================================*/
6448 function getWeightedRate(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
6449 ,p_start_date in date
6450 ,p_end_date in date
6451 ,p_rate_tbl in LNS_FINANCIALS.RATE_SCHEDULE_TBL) return number
6452 is
6453 l_api_name varchar2(25);
6454 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
6455 l_pay_dates LNS_FINANCIALS.DATE_TBL;
6456 l_days_at_rate number;
6457 l_weighted_rate number;
6458 l_running_weight number;
6459 l_total_days number;
6460 l_num_pay_dates number;
6461 l_period_start_date date;
6462 l_period_end_date date;
6463 --l_pay_in_arrears boolean;
6464 l_payment_tbl LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
6465 l_exit_loop boolean;
6466
6467 begin
6468
6469 l_api_name := 'getWeightedRate';
6470 l_days_at_rate := 0;
6471 l_weighted_rate := 0;
6472 l_running_weight := 0;
6473 l_total_days := 0;
6474 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6475 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' start date ' || p_start_date);
6476 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' end date ' || p_end_date);
6477 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate table count ' || p_rate_tbl.count);
6478
6479 if p_loan_details.custom_schedule = 'N' then
6480
6481 if p_loan_details.PAYMENT_CALC_METHOD = 'SEPARATE_SCHEDULES' then
6482
6483 l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
6484 p_loan_start_date => p_loan_details.loan_start_date
6485 ,p_loan_maturity_date => p_loan_details.maturity_date
6486 ,p_int_first_pay_date => p_loan_details.first_payment_date
6487 ,p_int_num_intervals => p_loan_details.number_installments
6488 ,p_int_interval_type => p_loan_details.payment_frequency
6489 ,p_int_pay_in_arrears => p_loan_details.pay_in_arrears_boolean
6490 ,p_prin_first_pay_date => p_loan_details.PRIN_FIRST_PAY_DATE
6491 ,p_prin_num_intervals => p_loan_details.PRIN_NUMBER_INSTALLMENTS
6492 ,p_prin_interval_type => p_loan_details.PRIN_PAYMENT_FREQUENCY
6493 ,p_prin_pay_in_arrears => p_loan_details.PRIN_PAY_IN_ARREARS_BOOL);
6494
6495 else
6496
6497 l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date => p_loan_details.loan_start_date
6498 ,p_loan_maturity_date => p_loan_details.maturity_date
6499 ,p_first_pay_date => p_loan_details.first_payment_date
6500 ,p_num_intervals => p_loan_details.number_installments
6501 ,p_interval_type => p_loan_details.payment_frequency
6502 ,p_pay_in_arrears => p_loan_details.pay_in_arrears_boolean);
6503
6504
6505 end if;
6506
6507 else
6508
6509 -- build custom payment schedule
6510 l_payment_tbl := LNS_CUSTOM_PUB.buildCustomPaySchedule(p_loan_details.LOAN_ID);
6511
6512 end if;
6513
6514 l_num_pay_dates := l_payment_tbl.count;
6515 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' num pay dates is ' || l_num_pay_dates);
6516 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' num installments is ' || p_loan_details.number_installments);
6517
6518 -- for k in 1..p_loan_details.number_installments
6519 for k in 1..l_num_pay_dates
6520 loop
6521
6522 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Period: ' || k);
6523 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' period start is ' || l_payment_tbl(k).period_begin_date);
6524 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' period end is ' || l_payment_tbl(k).period_end_date);
6525 -- check to see if this period is covered in the time
6526
6527 l_exit_loop := false;
6528 l_period_start_date := null;
6529 if p_start_date >= l_payment_tbl(k).period_begin_date and
6530 p_start_date < l_payment_tbl(k).period_end_date then
6531 l_period_start_date := p_start_date;
6532 elsif p_start_date < l_payment_tbl(k).period_begin_date and
6533 p_start_date < l_payment_tbl(k).period_end_date then
6534 l_period_start_date := l_payment_tbl(k).period_begin_date;
6535 end if;
6536
6537 l_period_end_date := null;
6538 if p_end_date >= l_payment_tbl(k).period_begin_date and
6539 p_end_date < l_payment_tbl(k).period_end_date then
6540 l_period_end_date := p_end_date;
6541 l_exit_loop := true;
6542 elsif p_end_date >= l_payment_tbl(k).period_begin_date and
6543 p_end_date > l_payment_tbl(k).period_end_date then
6544 if k = l_num_pay_dates then
6545 l_period_end_date := p_end_date;
6546 l_exit_loop := true;
6547 else
6548 l_period_end_date := l_payment_tbl(k).period_end_date;
6549 end if;
6550 end if;
6551
6552 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_period_start_date: ' || l_period_start_date);
6553 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_period_end_date: ' || l_period_end_date);
6554
6555 if l_period_start_date is not null and l_period_end_date is not null then
6556
6557 l_days_at_rate := LNS_FIN_UTILS.getDayCount(p_start_date => l_period_start_date
6558 ,p_end_date => l_period_end_date
6559 ,p_day_count_method => p_loan_details.day_count_method);
6560 l_rate_details := getRateDetails(p_installment => k
6561 ,p_rate_tbl => p_rate_tbl);
6562
6563 l_total_days := l_total_days + l_days_at_rate;
6564 l_running_weight := l_running_weight + (l_rate_details.annual_rate * l_days_at_rate);
6565
6566 end if;
6567
6568 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_days_at_rate: ' || l_days_at_rate);
6569 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_rate: ' || l_rate_details.annual_rate);
6570 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_running_weight: ' || l_running_weight);
6571
6572 if l_exit_loop then
6573 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Exiting loop');
6574 exit;
6575 end if;
6576
6577 end loop;
6578
6579 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' total days is ' || l_total_days);
6580
6581 if l_total_days = 0 then
6582 l_total_days := 1;
6583 end if;
6584
6585 l_weighted_rate := l_running_weight / l_total_days;
6586 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_weighted_rate ' || l_weighted_rate);
6587
6588 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6589
6590 return l_weighted_rate;
6591
6592 end getWeightedRate;
6593
6594
6595 /*=========================================================================
6596 || PUBLIC PROCEDURE getRateDetails
6597 ||
6598 || DESCRIPTION
6599 ||
6600 || Overview: return a interest_rate_record for a given installment
6601 ||
6602 ||
6603 || Parameter: p_installment => installment to get rate details
6604 || p_rate_tbl => table of interest rates
6605 ||
6606 ||
6607 || Return value: NA
6608 ||
6609 || Source Tables: NA
6610 ||
6611 || Target Tables: NA
6612 ||
6613 || KNOWN ISSUES
6614 || if no rates can be found in set of give dates a rate of 0 is returned
6615 ||
6616 || NOTES
6617 ||
6618 || MODIFICATION HISTORY
6619 || Date Author Description of Changes
6620 || 2/24/2003 4:28PM raverma Created
6621 *=======================================================================*/
6622 function getRateDetails(p_installment IN NUMBER
6623 ,p_rate_tbl IN LNS_FINANCIALS.RATE_SCHEDULE_TBL) return LNS_FINANCIALS.INTEREST_RATE_REC
6624 is
6625 x number;
6626 l_rate number;
6627 l_rate_rec LNS_FINANCIALS.INTEREST_RATE_REC;
6628 l_api_name varchar2(25);
6629
6630 begin
6631
6632 l_rate := 0;
6633 l_api_name := 'getRateDetails2';
6634 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6635 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - installment ' || p_installment);
6636
6637 x := 1;
6638 Begin
6639 LOOP
6640 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - match row ' || x);
6641 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate ' || p_rate_tbl(x).annual_rate);
6642 l_rate := p_rate_tbl(x).annual_rate;
6643 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate 1');
6644 l_rate_rec := p_rate_tbl(x);
6645 EXIT WHEN p_installment >= p_rate_tbl(x).begin_installment_number and
6646 p_installment <= p_rate_tbl(x).end_installment_number;
6647 x := x + 1;
6648 END LOOP;
6649 Exception
6650 When No_Data_found then
6651 -- when there is not a rate for this period it is assumed to be zero (see scenarios 3, 6, 8 in comments on getWeightedRate)
6652 --l_rate := 0;
6653 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - no rate found for period');
6654 when others then
6655 l_rate := 0;
6656
6657 End;
6658
6659 if l_rate = 0 then
6660 l_rate_rec.annual_rate := 0;
6661 end if;
6662
6663 --logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6664 return l_rate_rec;
6665
6666 end getRateDetails;
6667
6668
6669 /*=========================================================================
6670 | PUBLIC PROCEDURE getRateDetails
6671 ||
6672 || DESCRIPTION
6673 ||
6674 || Overview: return a interest_rate_record for a given date
6675 ||
6676 ||
6677 || Parameter: p_date => to get rate details
6678 || p_rate_tbl => table of interest rates
6679 ||
6680 ||
6681 || Return value: NA
6682 ||
6683 || Source Tables: NA
6684 ||
6685 || Target Tables: NA
6686 ||
6687 || KNOWN ISSUES
6688 || if no rates can be found in set of give dates a rate of 0 is returned
6689 ||
6690 || NOTES
6691 ||
6692 || MODIFICATION HISTORY
6693 || Date Author Description of Changes
6694 || 2/24/2003 4:28PM raverma Created
6695 ||
6696 *=======================================================================*/
6697 function getRateDetails(p_date in date
6698 ,p_rate_tbl in LNS_FINANCIALS.RATE_SCHEDULE_TBL) return LNS_FINANCIALS.INTEREST_RATE_REC
6699 is
6700 x number;
6701 l_rate number;
6702 l_rate_rec LNS_FINANCIALS.INTEREST_RATE_REC;
6703 l_api_name varchar2(25);
6704
6705 begin
6706
6707 l_rate := 0;
6708 l_api_name := 'getRateDetails';
6709 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6710
6711 x := 1;
6712 Begin
6713 LOOP
6714 l_rate := p_rate_tbl(x).annual_rate;
6715 l_rate_rec := p_rate_tbl(x);
6716 EXIT WHEN p_date >= p_rate_tbl(x).begin_date and p_date <= p_rate_tbl(x).end_date;
6717
6718 x := x + 1;
6719 END LOOP;
6720 Exception
6721 When No_Data_found then
6722 -- when there is not a rate for this period it is assumed to be zero (see scenarios 3, 6, 8 in comments on getWeightedRate)
6723 l_rate := 0;
6724 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - no rate found for period');
6725 when others then
6726 l_rate := 0;
6727
6728 End;
6729
6730 if l_rate = 0 then
6731 l_rate_rec.annual_rate := 0;
6732 end if;
6733
6734 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6735
6736 return l_rate_rec;
6737
6738 end getRateDetails;
6739
6740 /*=========================================================================
6741 || PUBLIC PROCEDURE getLoanDetails
6742 ||
6743 || DESCRIPTION
6744 ||
6745 || Overview: return a rec_type of loan details
6746 ||
6747 || Parameter: loan_id
6748 ||
6749 || Return value: table of dates
6750 ||
6751 || Source Tables: LNS_LOAN_HEADER, LNS_TERMS, LNS_AMORTIZATION_SCHEDS
6752 ||
6753 || Target Tables: NA
6754 ||
6755 || KNOWN ISSUES
6756 ||
6757 || NOTES
6758 ||
6759 || MODIFICATION HISTORY
6760 || Date Author Description of Changes
6761 || 1/15/2004 4:28PM raverma Created
6762 || 2/26/2004 raverma add loan_maturity_Date
6763 || 3/12/2004 raverma added reamortization information
6764 || 4/15/2004 raverma added loan_status
6765 || 8/02/2004 raverma added logic to calculate num_amortization_intervals based on
6766 || theoretical amortization_maturity_date
6767 || 01/19/2007 scherkas Fixed bug 5842639
6768 *=======================================================================*/
6769 function getLoanDetails(p_loan_id in number
6770 ,p_based_on_terms in varchar2
6771 ,p_phase in varchar2) return LNS_FINANCIALS.LOAN_DETAILS_REC
6772
6773 is
6774
6775
6776 -- get the loan details assumes there is only ONE ROW in terms (TERM PHASE)
6777 CURSOR c_loan_details(p_Loan_id NUMBER, p_based_on_terms varchar2, p_phase varchar2) IS
6778 SELECT h.loan_id
6779 ,decode(p_phase, 'TERM', h.loan_term, 'OPEN', h.open_loan_term, h.loan_term) TERM
6780 ,decode(p_phase, 'TERM', h.loan_term_period, 'OPEN', h.open_loan_term_period, h.loan_term_period) TERM_PERIOD
6781 ,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
6782 ,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
6783 ,decode(h.balloon_payment_type, 'TERM', 0, 'AMOUNT', h.balloon_payment_amount, 0) BALLOON_PAYMENT_AMT
6784 ,decode(p_phase, 'TERM', t.amortization_frequency, 'OPEN', t.loan_payment_frequency) AMORT_FREQ
6785 ,decode(p_phase, 'TERM', t.loan_payment_frequency, 'OPEN', t.open_payment_frequency, t.loan_payment_frequency) PAY_FREQ
6786 ,decode(p_phase, 'TERM', trunc(h.loan_start_date), 'OPEN' , trunc(h.open_loan_start_date), trunc(h.loan_start_date)) START_DATE
6787 ,decode(p_phase, 'TERM', trunc(t.first_payment_date), 'OPEN' , trunc(t.open_first_payment_date), trunc(t.first_payment_date)) FIRST_PAY_DATE
6788 ,h.requested_amount REQUEST_AMOUNT
6789 ,h.funded_amount FUNDED_AMOUNT
6790 ,lns_financials.getRemainingBalance(p_loan_id) BALANCE
6791 --,decode(p_based_on_terms, 'CURRENT', lns_financials.getRemainingBalance(p_loan_id), 'ORIGINAL', h.requested_amount) BALANCE -- see bug #3881401
6792 ,decode(p_phase, 'TERM', trunc(h.loan_maturity_date), 'OPEN', trunc(h.open_maturity_date), trunc(h.loan_maturity_date)) MATURITY_DATE
6793 ,NVL(t.reamortize_over_payment, 'N')
6794 ,NVL(t.reamortize_under_payment, 'N')
6795 ,NVL(t.reamortize_with_interest, 'N')
6796 ,LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id) LAST_PAY_NUM
6797 --,decode(p_based_on_terms, 'CURRENT', LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id),'ORIGINAL', 1) LAST_PAY_NUM
6798 ,decode(nvl(t.day_count_method, 'PERIODIC30_360'), 'PERIODIC30_360', '30/360', t.day_count_method) DAY_COUNT
6799 ,decode(p_phase, 'TERM', decode(trunc(t.first_payment_date) - trunc(h.loan_start_date), 0, 'N', 'Y')
6800 , 'OPEN', decode(trunc(t.open_first_payment_date) - trunc(h.open_loan_start_date), 0, 'N', 'Y')
6801 , decode(trunc(t.first_payment_date) - trunc(h.loan_start_date), 0, 'N', 'Y')) ARREARS
6802 ,nvl(h.custom_payments_flag, 'N') CUSTOM
6803 ,h.loan_status LOAN_STATUS
6804 ,h.loan_currency CURRENCY
6805 ,curr.precision PRECISION
6806 ,h.OPEN_TO_TERM_FLAG OPEN_TO_TERM_FLAG
6807 ,h.OPEN_TO_TERM_EVENT OPEN_TO_TERM_EVENT
6808 ,h.MULTIPLE_FUNDING_FLAG MULTIPLE_FUNDING_FLAG
6809 ,h.SECONDARY_STATUS SECONDARY_STATUS
6810 ,t.RATE_TYPE RATE_TYPE
6811 ,t.CEILING_RATE TERM_CEILING_RATE
6812 ,t.FLOOR_RATE TERM_FLOOR_RATE
6813 ,t.PERCENT_INCREASE TERM_PERCENT_INCREASE
6814 ,t.PERCENT_INCREASE_LIFE TERM_PERCENT_INCREASE_LIFE
6815 ,t.FIRST_PERCENT_INCREASE TERM_FIRST_PERCENT_INCREASE
6816 ,t.OPEN_PERCENT_INCREASE OPEN_PERCENT_INCREASE
6817 ,t.OPEN_PERCENT_INCREASE_LIFE OPEN_PERCENT_INCREASE_LIFE
6818 ,t.OPEN_FIRST_PERCENT_INCREASE OPEN_FIRST_PERCENT_INCREASE
6819 ,t.OPEN_CEILING_RATE OPEN_CEILING_RATE
6820 ,t.OPEN_FLOOR_RATE OPEN_FLOOR_RATE
6821 ,t.OPEN_PROJECTED_RATE OPEN_PROJECTED_RATE
6822 ,t.TERM_PROJECTED_RATE TERM_PROJECTED_RATE
6823 ,t.rate_change_frequency TERM_RATE_CHG_FREQ
6824 ,t.rate_change_frequency OPEN_RATE_CHG_FREQ
6825 ,t.INDEX_RATE_ID OPEN_INDEX_RATE_ID
6826 ,t.INDEX_RATE_ID TERM_INDEX_RATE_ID
6827 ,t.OPEN_INDEX_DATE OPEN_INDEX_DATE
6828 ,t.TERM_INDEX_DATE TERM_INDEX_DATE
6829 ,decode(p_phase, 'TERM', t.TERM_PROJECTED_RATE, t.OPEN_PROJECTED_RATE) INITIAL_INTEREST_RATE
6830 ,nvl(lns_fin_utils.getActiveRate(h.loan_id), decode(p_phase, 'TERM', t.TERM_PROJECTED_RATE, t.OPEN_PROJECTED_RATE)) LAST_INTEREST_RATE
6831 ,nvl(t.FIRST_RATE_CHANGE_DATE, t.NEXT_RATE_CHANGE_DATE) FIRST_RATE_CHANGE_DATE
6832 ,t.NEXT_RATE_CHANGE_DATE NEXT_RATE_CHANGE_DATE
6833 ,t.CALCULATION_METHOD
6834 ,t.INTEREST_COMPOUNDING_FREQ
6835 ,decode(p_phase, 'TERM', decode(p_based_on_terms,
6836 'CURRENT', decode(nvl(h.custom_payments_flag, 'N'), 'Y', nvl(t.PAYMENT_CALC_METHOD, 'CUSTOM'),
6837 'N', nvl(t.PAYMENT_CALC_METHOD, 'EQUAL_PAYMENT')),
6838 decode(nvl(h.custom_payments_flag, 'N'), 'Y', nvl(t.ORIG_PAY_CALC_METHOD, 'CUSTOM'),
6839 'N', nvl(t.PAYMENT_CALC_METHOD, 'EQUAL_PAYMENT'))
6840 ), null)
6841 ,t.ORIG_PAY_CALC_METHOD
6842 ,trunc(nvl(t.prin_first_pay_date, t.first_payment_date))
6843 ,nvl(t.prin_payment_frequency, t.loan_payment_frequency)
6844 ,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
6845 ,nvl(t.PENAL_INT_RATE, 0)
6846 ,nvl(t.PENAL_INT_GRACE_DAYS, 0)
6847 FROM lns_loan_headers_all h
6848 ,lns_terms t
6849 ,fnd_currencies curr
6850 WHERE h.loan_id = p_loan_id
6851 AND t.loan_id = h.loan_id
6852 AND curr.currency_code = h.loan_currency;
6853
6854 /*
6855 -- this is appropriate for OPEN + TERM phase
6856 cursor c_rate_information(p_loan_id number, p_phase varchar) is
6857 select t.rate_type -- term_phase
6858 ,t.rate_change_frequency -- term_phase
6859 ,t.index_rate_id -- term_phase
6860 ,rs.index_date -- term_phase
6861 ,nvl(t.ceiling_rate, 100) -- term_phase
6862 ,nvl(t.floor_rate, 0) -- term_phase
6863 from lns_rate_schedules rs
6864 ,lns_terms t
6865 where t.loan_id = p_loan_id
6866 AND t.term_id = rs.term_id
6867 AND rs.phase = p_phase
6868 AND rs.begin_installment_number = 1
6869 AND rs.end_date_active is null;
6870 */
6871
6872 -- get reamortization information
6873 -- this is temporary place on LNS_AMORTIZATION_SCHEDS
6874 -- we should move this to LNS_TERMS when we have terms realignment
6875 -- bug# 5664316 - we only store ONE reamortization row
6876 CURSOR c_reamortization(p_Loan_id NUMBER) IS
6877 SELECT nvl(reamortization_amount, 0)
6878 ,nvl(reamortize_from_installment, 0)
6879 ,nvl(reamortize_to_installment, 0)
6880 FROM lns_loan_headers_all lnh,
6881 lns_amortization_scheds amort1
6882 WHERE lnh.loan_id = amort1.loan_id(+)
6883 AND lnh.loan_id = p_loan_id
6884 AND amort1.reamortization_amount > 0;
6885
6886 -- cursor to get the balance information for the loan
6887 -- changes as per scherkas 11-16-2005
6888 cursor c_balanceInfo(p_loan_id NUMBER, p_phase varchar2) IS
6889 select nvl(sum(amort.PRINCIPAL_AMOUNT),0) -- billed principal
6890 ,nvl(sum(amort.PRINCIPAL_REMAINING),0) -- unpaid principal
6891 ,nvl(sum(amort.INTEREST_REMAINING),0) -- unpaid interest
6892 from LNS_AM_SCHEDS_V amort
6893 where amort.Loan_id = p_loan_id
6894 and amort.REVERSED_CODE = 'N'
6895 and amort.phase = p_phase;
6896
6897 -- this cursor will get the last time the loan interest was accrued
6898 -- fix for bug 7423644: removed condition interest_trx_id is not null
6899 cursor c_last_interest_accrual(p_loan_id NUMBER) is
6900 select decode(LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(lnh.loan_id),
6901 0,
6902 decode(lnh.current_phase, 'TERM', lnh.loan_start_date, 'OPEN', lnh.open_loan_start_date),
6903 (select max(due_date)
6904 from lns_amortization_scheds
6905 where reversed_flag = 'N'
6906 and loan_id = lnh.loan_id
6907 and phase = lnh.current_phase))
6908 from lns_loan_headers lnh
6909 where lnh.loan_id = p_loan_id;
6910
6911 -- this cursor is to get the last activity date on the loan
6912 -- payoff processing will use this date
6913 cursor c_last_loan_activity(p_loan_id number) is
6914 select max(activity_date)
6915 from LNS_REC_ACT_CASH_CM_V
6916 where activity_code = 'PMT'
6917 and loan_id = p_loan_id;
6918
6919 -- begin fix for bug 6724561
6920 -- cursor to get latest extended from installment - last billed installment from the last approved loan extension
6921 cursor c_ext_from_install(p_loan_id NUMBER) IS
6922 select LAST_BILLED_INSTALLMENT
6923 from LNS_LOAN_EXTENSIONS
6924 where loan_id = p_loan_id
6925 and STATUS = 'APPROVED'
6926 order by LOAN_EXT_ID desc;
6927 -- end fix for bug 6724561
6928
6929 -- begin fix for bug 6724522
6930 -- cursor to get original loan term if loan has been extended
6931 cursor c_orig_loan_term(p_loan_id NUMBER) IS
6932 select OLD_TERM,
6933 OLD_TERM_PERIOD,
6934 OLD_BALLOON_TYPE,
6935 OLD_BALLOON_AMOUNT,
6936 OLD_AMORT_TERM,
6937 OLD_MATURITY_DATE,
6938 OLD_INSTALLMENTS
6939 from LNS_LOAN_EXTENSIONS
6940 where loan_id = p_loan_id
6941 and STATUS = 'APPROVED'
6942 order by LOAN_EXT_ID;
6943
6944 l_orig_loan_term number;
6945 l_orig_loan_period varchar2(30);
6946 l_orig_balloon_type varchar2(30);
6947 l_orig_balloon_amount number;
6948 l_orig_amort_term number;
6949 l_orig_maturity_date date;
6950 l_orig_num_install number;
6951 -- end fix for bug 6724522
6952
6953 l_billed_principal number;
6954 l_amortized_to_Date date;
6955 --l_pay_in_arrears boolean;
6956 l_loan_Details LNS_FINANCIALS.LOAN_DETAILS_REC;
6957 l_amortize_dates LNS_FIN_UTILS.DATE_TBL;
6958 l_loan_id number;
6959 l_api_name varchar2(25);
6960
6961 begin
6962
6963 l_api_name := 'getLoanDetails';
6964 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6965
6966 --l_loan_id := p_loan_id;
6967 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_loan_id: ' || p_loan_id);
6968 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_based_on_terms: ' || p_based_on_terms);
6969 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_phase: ' || p_phase);
6970
6971 OPEN c_loan_details(p_loan_id, p_based_on_terms, p_phase);
6972 FETCH c_loan_details INTO
6973 l_loan_details.loan_id
6974 ,l_loan_Details.loan_term
6975 ,l_loan_Details.loan_term_period
6976 ,l_loan_Details.amortized_term
6977 ,l_loan_Details.amortized_term_period
6978 ,l_loan_details.balloon_payment_amount
6979 ,l_loan_Details.amortization_frequency
6980 ,l_loan_Details.payment_frequency
6981 ,l_loan_Details.loan_start_date
6982 ,l_loan_Details.first_payment_date
6983 ,l_loan_Details.requested_amount
6984 ,l_loan_details.funded_amount
6985 ,l_loan_details.remaining_balance
6986 ,l_loan_details.maturity_Date
6987 ,l_loan_details.reamortize_overpay
6988 ,l_loan_details.reamortize_underpay
6989 ,l_loan_details.reamortize_with_interest
6990 ,l_loan_details.last_installment_billed
6991 ,l_loan_details.day_count_method
6992 ,l_loan_details.pay_in_arrears
6993 ,l_loan_details.custom_schedule
6994 ,l_loan_details.loan_status
6995 ,l_loan_details.loan_currency
6996 ,l_loan_details.currency_precision
6997 ,l_loan_details.OPEN_TO_TERM_FLAG
6998 ,l_loan_details.OPEN_TO_TERM_EVENT
6999 ,l_loan_details.MULTIPLE_FUNDING_FLAG
7000 ,l_loan_details.SECONDARY_STATUS
7001 ,l_loan_details.RATE_TYPE -- fixed or variable
7002 ,l_loan_details.TERM_CEILING_RATE -- term ceiling rate
7003 ,l_loan_details.TERM_FLOOR_RATE -- term floor rate
7004 ,l_loan_details.TERM_ADJ_PERCENT_INCREASE -- term percentage increase btwn adjustments
7005 ,l_loan_details.TERM_LIFE_PERCENT_INCREASE -- term lifetime max adjustment for interest
7006 ,l_loan_details.TERM_FIRST_PERCENT_INCREASE -- term first percentage increase
7007 ,l_loan_details.OPEN_ADJ_PERCENT_INCREASE -- open percentage increase btwn adjustments
7008 ,l_loan_details.OPEN_LIFE_PERCENT_INCREASE -- open lifetime max adjustment for interest
7009 ,l_loan_details.OPEN_FIRST_PERCENT_INCREASE -- open first percentage increase
7010 ,l_loan_details.OPEN_CEILING_RATE -- open ceiling rate
7011 ,l_loan_details.OPEN_FLOOR_RATE -- open floor rate
7012 ,l_loan_details.OPEN_PROJECTED_INTEREST_RATE -- open projected interest rate
7013 ,l_loan_details.TERM_PROJECTED_INTEREST_RATE -- term projected interest rate
7014 ,l_loan_details.OPEN_RATE_CHG_FREQ
7015 ,l_loan_details.TERM_RATE_CHG_FREQ
7016 ,l_loan_details.OPEN_INDEX_RATE_ID
7017 ,l_loan_details.TERM_INDEX_RATE_ID
7018 ,l_loan_details.OPEN_INDEX_DATE
7019 ,l_loan_details.TERM_INDEX_DATE
7020 ,l_loan_details.INITIAL_INTEREST_RATE -- current phase only
7021 ,l_loan_details.LAST_INTEREST_RATE -- current phase only
7022 ,l_loan_details.FIRST_RATE_CHANGE_DATE -- current phase only
7023 ,l_loan_details.NEXT_RATE_CHANGE_DATE -- current phase only
7024 ,l_loan_details.CALCULATION_METHOD
7025 ,l_loan_details.INTEREST_COMPOUNDING_FREQ
7026 ,l_loan_details.PAYMENT_CALC_METHOD
7027 ,l_loan_details.ORIG_PAY_CALC_METHOD
7028 ,l_loan_details.prin_first_pay_date
7029 ,l_loan_details.prin_payment_frequency
7030 ,l_loan_details.PRIN_PAY_IN_ARREARS
7031 ,l_loan_details.PENAL_INT_RATE
7032 ,l_loan_details.PENAL_INT_GRACE_DAYS
7033 ;
7034 close c_loan_details;
7035
7036 /* open c_rate_information(p_loan_id, p_phase) ;
7037 fetch c_rate_information into
7038 l_loan_details.open_rate_type
7039 ,l_loan_details.open_rate_chg_freq
7040 ,l_loan_details.open_index_rate_id
7041 ,l_loan_details.open_index_date
7042 ,l_loan_details.open_ceiling_rate
7043 ,l_loan_details.open_floor_rate;
7044 close c_rate_information;
7045 */
7046
7047 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate_type ' || l_loan_details.rate_type);
7048 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_rate_chg_freq ' || l_loan_details.open_rate_chg_freq);
7049 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_index_rate_id ' || l_loan_details.open_index_rate_id);
7050 --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_index_date ' || l_loan_details.open_index_date);
7051 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_ceiling_rate ' || l_loan_details.open_ceiling_rate);
7052 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_floor_rate ' || l_loan_details.open_floor_rate);
7053
7054 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': balloon_payment_amount' || l_loan_details.balloon_payment_amount);
7055
7056 -- begin fix for bug 6724522
7057 -- replacing loan terms with original data for p_based_on_terms <> 'CURRENT'
7058 if p_based_on_terms <> 'CURRENT' then
7059 open c_orig_loan_term(p_loan_id);
7060 fetch c_orig_loan_term into
7061 l_orig_loan_term,
7062 l_orig_loan_period,
7063 l_orig_balloon_type,
7064 l_orig_balloon_amount,
7065 l_orig_amort_term,
7066 l_orig_maturity_date,
7067 l_orig_num_install;
7068 close c_orig_loan_term;
7069
7070 if l_orig_loan_term is not null and
7071 l_orig_loan_period is not null and
7072 l_orig_balloon_type is not null and
7073 l_orig_balloon_amount is not null and
7074 l_orig_amort_term is not null and
7075 l_orig_maturity_date is not null and
7076 l_orig_num_install is not null
7077 then
7078 l_loan_Details.loan_term := l_orig_loan_term;
7079 l_loan_Details.loan_term_period := l_orig_loan_period;
7080 l_loan_Details.amortized_term_period := l_orig_loan_period;
7081 l_loan_Details.maturity_Date := l_orig_maturity_date;
7082 l_loan_Details.ORIG_NUMBER_INSTALLMENTS := l_orig_num_install;
7083
7084 if l_orig_balloon_type = 'TERM' then
7085 l_loan_details.balloon_payment_amount := 0;
7086 l_loan_Details.amortized_term := l_orig_amort_term;
7087 elsif l_orig_balloon_type = 'AMOUNT' then
7088 l_loan_details.balloon_payment_amount := l_orig_balloon_amount;
7089 l_loan_Details.amortized_term := l_orig_loan_term;
7090 end if;
7091 end if;
7092 end if;
7093 -- end fix for bug 6724522
7094
7095 -- begin fix for bug 6724561
7096 -- get latest extended from installment
7097 if p_based_on_terms = 'CURRENT' then
7098 open c_ext_from_install(p_loan_id);
7099 fetch c_ext_from_install into l_loan_Details.extend_from_installment;
7100 close c_ext_from_install;
7101 end if;
7102 -- end fix for bug 6724561
7103
7104 -- adding balloon amount
7105 l_loan_details.amortized_amount := l_loan_details.requested_amount - l_loan_details.balloon_payment_amount;
7106
7107 open c_last_interest_accrual(p_loan_id);
7108 fetch c_last_interest_accrual into l_loan_details.last_interest_accrual;
7109 close c_last_interest_accrual;
7110
7111 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting number of intervals');
7112 -- get the number of installments on a loan
7113 -- this represents the number of payments on the loan
7114 /*
7115 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting number of payment intervals');
7116 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_loan_Details.first_payment_date' || l_loan_Details.first_payment_date);
7117 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_amortized_to_Date' || l_amortized_to_Date);
7118 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_loan_details.num_amortization_intervals' || l_loan_details.num_amortization_intervals);
7119 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_loan_Details.amortization_frequency' || l_loan_Details.amortization_frequency);
7120 */
7121
7122 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting number of payment intervals');
7123 l_loan_details.number_installments := lns_fin_utils.intervalsInPeriod(l_loan_Details.loan_term
7124 ,l_loan_Details.loan_term_period
7125 ,l_loan_Details.payment_frequency);
7126
7127 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting number of principal payment intervals');
7128 l_loan_details.PRIN_NUMBER_INSTALLMENTS := lns_fin_utils.intervalsInPeriod(l_loan_Details.loan_term
7129 ,l_loan_Details.loan_term_period
7130 ,l_loan_Details.prin_payment_frequency);
7131
7132 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting number of principal amortized payment intervals');
7133 l_loan_details.PRIN_AMORT_INSTALLMENTS := lns_fin_utils.intervalsInPeriod(l_loan_Details.amortized_term
7134 ,l_loan_Details.amortized_term_period
7135 ,l_loan_Details.prin_payment_frequency);
7136
7137 -- get the number of amortization intervals on a loan
7138 -- the number of amortization intervals is counted from the first payment date
7139 -- this number will be used in the amortization equation
7140 if l_loan_details.pay_in_arrears = 'Y' then
7141 l_loan_details.pay_in_arrears_boolean := true;
7142 else
7143 l_loan_details.pay_in_arrears_boolean := false;
7144 end if;
7145
7146 if l_loan_details.PRIN_PAY_IN_ARREARS = 'Y' then
7147 l_loan_details.PRIN_PAY_IN_ARREARS_BOOL := true;
7148 else
7149 l_loan_details.PRIN_PAY_IN_ARREARS_BOOL := false;
7150 end if;
7151
7152 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting number of amortization intervals');
7153 l_loan_details.num_amortization_intervals := lns_fin_utils.intervalsInPeriod(l_loan_Details.amortized_term
7154 ,l_loan_Details.amortized_term_period
7155 ,l_loan_Details.amortization_frequency);
7156 if l_loan_details.balloon_payment_amount > 0 then
7157 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - reducing number of amortization intervals');
7158 l_loan_details.num_amortization_intervals := l_loan_details.num_amortization_intervals - 1;
7159 end if;
7160
7161 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting amortized to date');
7162 l_amortized_to_Date := LNS_FIN_UTILS.getMaturityDate(p_term => l_loan_Details.amortized_term
7163 ,p_term_period => l_loan_Details.amortized_term_period
7164 ,p_frequency => l_loan_Details.amortization_frequency
7165 ,p_start_date => l_loan_Details.loan_start_date);
7166
7167 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting payment schedule');
7168 -- fix for bug 5842639: added p_loan_start_date parameter to LNS_FIN_UTILS.getPaymentSchedule
7169 l_amortize_dates := LNS_FIN_UTILS.getPaymentSchedule(p_loan_start_date => l_loan_Details.loan_start_date
7170 ,p_first_pay_date => l_loan_Details.first_payment_date
7171 ,p_maturity_Date => l_amortized_to_Date
7172 ,p_pay_in_arrears => l_loan_details.pay_in_arrears_boolean
7173 ,p_num_intervals => l_loan_details.num_amortization_intervals
7174 ,p_interval_type => l_loan_Details.amortization_frequency);
7175
7176 -- we amortize over the actual number of installments on the payment schedule
7177 l_loan_details.num_amortization_intervals := l_amortize_dates.count;
7178
7179 -- use this part of the procedure to differentiate between
7180 -- elements that are calculated differently for current and original
7181 -- amortization
7182
7183 if p_based_on_terms = 'CURRENT' then
7184 -- get reamortization information
7185 Begin
7186 -- bug# 5664316 make sure we catch no data found on EACH cursor: reamortization, activity, balanceInfo
7187 open c_reamortization(p_loan_id);
7188 fetch c_reamortization into
7189 l_loan_details.reamortize_amount
7190 ,l_loan_details.reamortize_from_installment
7191 ,l_loan_details.reamortize_to_installment;
7192 close c_reamortization;
7193 Exception
7194 when no_data_found then
7195 l_loan_details.reamortize_amount := 0;
7196 l_loan_details.reamortize_from_installment := null;
7197 l_loan_details.reamortize_to_installment := 0;
7198 End;
7199
7200 Begin
7201
7202 open c_last_loan_activity(p_loan_id);
7203 fetch c_last_loan_activity into
7204 l_loan_details.last_activity_date;
7205 close c_last_loan_activity;
7206 Exception
7207 when no_data_found then
7208 l_loan_details.last_activity_date := null;
7209 End;
7210
7211 Begin
7212
7213 -- get balance information
7214 open c_balanceInfo(p_loan_id, p_phase);
7215 fetch c_balanceInfo into
7216 l_billed_principal
7217 ,l_loan_details.unpaid_principal
7218 ,l_loan_details.UNPAID_INTEREST;
7219 close c_balanceInfo;
7220
7221 l_loan_details.unbilled_principal := l_loan_details.funded_amount - l_billed_principal;
7222 Exception
7223 when no_data_found then
7224 -- l_loan_details.reamortize_amount := 0;
7225 -- l_loan_details.reamortize_from_installment := 0;
7226 -- l_loan_details.reamortize_to_installment := 0;
7227 -- l_loan_details.last_activity_date := null;
7228 l_loan_details.unpaid_principal := 0;
7229 l_loan_details.unbilled_principal := l_loan_details.funded_amount;
7230 l_loan_details.UNPAID_INTEREST := 0;
7231 End;
7232
7233 else
7234 l_loan_details.reamortize_amount := 0;
7235 l_loan_details.reamortize_from_installment := null;
7236 l_loan_details.reamortize_to_installment := 0;
7237 l_loan_details.last_activity_date := null;
7238 l_loan_details.unpaid_principal := 0;
7239 l_loan_details.unbilled_principal := l_loan_details.funded_amount;
7240 l_loan_details.UNPAID_INTEREST := 0;
7241 end if;
7242
7243 --open c_last_interest_accrual(p_loan_id);
7244 --fetch c_last_interest_accrual into l_loan_details.last_interest_accrual;
7245 --close c_last_interest_accrual;
7246 /*
7247 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting number of intervals');
7248 -- get the number of installments on a loan
7249 -- this represents the number of payments on the loan
7250 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting number of payment intervals');
7251 l_loan_details.number_installments := lns_fin_utils.intervalsInPeriod(l_loan_Details.loan_term
7252 ,l_loan_Details.loan_term_period
7253 ,l_loan_Details.payment_frequency);
7254
7255 -- get the number of amortization intervals on a loan
7256 -- the number of amortization intervals is counted from the first payment date
7257 -- this number will be used in the amortization equation
7258 if l_loan_details.pay_in_arrears = 'Y' then
7259 l_loan_details.pay_in_arrears_boolean := true;
7260 else
7261 l_loan_details.pay_in_arrears_boolean := false;
7262 end if;
7263 */
7264 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '<---------- BEGIN LOAN DETAILS ------------->');
7265
7266 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortized_term: ' || l_loan_details.amortized_term);
7267 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortized_term_period: ' || l_loan_details.amortized_term_period);
7268 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization_frequency: ' || l_loan_details.amortization_frequency);
7269 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': first_payment_date: ' || l_loan_details.first_payment_date);
7270 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_start_date: ' || l_loan_details.loan_start_date);
7271 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': funded_amount: ' || l_loan_details.funded_amount);
7272 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': remaining_balance: ' || l_loan_details.remaining_balance);
7273 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number_installments: ' || l_loan_details.number_installments);
7274 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': num_amortization_intervals: ' || l_loan_details.num_amortization_intervals);
7275 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': reamortize_amount: ' || l_loan_details.reamortize_amount);
7276 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': reamortize_from_installment: ' || l_loan_details.reamortize_from_installment);
7277 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': day_count_method: ' || l_loan_details.day_count_method);
7278 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': last_installment_billed: ' || l_loan_details.last_installment_billed);
7279 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': PAYMENT_CALC_METHOD: ' || l_loan_details.PAYMENT_CALC_METHOD);
7280 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATION_METHOD: ' || l_loan_details.CALCULATION_METHOD);
7281 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': INTEREST_COMPOUNDING_FREQ: ' || l_loan_details.INTEREST_COMPOUNDING_FREQ);
7282 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prin_first_pay_date: ' || l_loan_details.prin_first_pay_date);
7283 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prin_payment_frequency: ' || l_loan_details.prin_payment_frequency);
7284 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': unbilled_principal ' || l_loan_details.unbilled_principal);
7285 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': unpaid_principal ' || l_loan_details.unpaid_principal);
7286 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': UNPAID_INTEREST ' || l_loan_details.UNPAID_INTEREST);
7287 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': extend_from_installment ' || l_loan_Details.extend_from_installment);
7288 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ORIG_PAY_CALC_METHOD ' || l_loan_Details.ORIG_PAY_CALC_METHOD);
7289
7290 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '<---------- END LOAN DETAILS --------------->');
7291 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7292
7293 return l_loan_details;
7294
7295 Exception
7296 When No_Data_Found then
7297 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - LOAN ID: ' || l_loan_id || ' not found');
7298 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_LOAN_ID');
7299 FND_MSG_PUB.Add;
7300 RAISE FND_API.G_EXC_ERROR;
7301
7302 When Others then
7303 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || 'Err: ' || sqlerrm);
7304 RAISE FND_API.G_EXC_ERROR;
7305
7306 end getLoanDetails;
7307
7308
7309 /*=========================================================================
7310 || PUBLIC PROCEDURE shiftLoan
7311 ||
7312 || DESCRIPTION
7313 ||
7314 || Overview: will shift a loans OPEN phase and/or TERM phase
7315 || where appropriate
7316 || 1. determine if any disbursements are past the open maturity date
7317 || 2. if so, get the next available maturity date,
7318 || -- this should increment by amortization frequency
7319 || 3. update the term/term period - in terms of payment frequency,
7320 || -- the term will change to X MONTHS if TERM was > MONTHS
7321 ||
7322 || Parameter: p_loan_id = loan_id
7323 ||
7324 || Source Tables: LNS_LOAN_HEADERS_ALL, LNS_DISB_HEADERS
7325 || LNS_TERMS
7326 ||
7327 || Target Tables: LNS_LOAN_HEADERS_ALL, LNS_TERMS
7328 ||
7329 || Return value: Standard Oracle API
7330 ||
7331 || MODIFICATION HISTORY
7332 || Date Author Description of Changes
7333 || 02/14/2005 11:35AM raverma Created
7334 *=======================================================================*/
7335 procedure shiftLoan(p_loan_id in number
7336 ,p_init_msg_list IN VARCHAR2
7337 ,p_commit IN VARCHAR2
7338 ,x_return_status OUT NOCOPY VARCHAR2
7339 ,x_msg_count OUT NOCOPY NUMBER
7340 ,x_msg_data OUT NOCOPY VARCHAR2)
7341
7342 is
7343
7344 l_api_name varchar2(25);
7345 l_move_maturity_date number;
7346 i number;
7347 l_old_maturity_date date;
7348 l_new_maturity_date date;
7349 l_max_pay_request_date date;
7350 l_payment_frequency varchar2(30);
7351 l_new_frequency varchar2(30);
7352 l_custom_payments_flag varchar2(1);
7353 l_current_phase varchar2(30);
7354 l_term number;
7355 l_term_period varchar2(30);
7356 l_temp varchar2(30);
7357 l_term_phase_exists varchar2(1);
7358 l_term_id number;
7359 l_initial_months number;
7360
7361 l_return_status VARCHAR2(1);
7362 l_msg_count NUMBER;
7363 l_msg_data VARCHAR2(32767);
7364 l_loan_details LOAN_DETAILS_REC;
7365 l_loan_header_rec LNS_LOAN_HEADER_PUB.loan_header_rec_type;
7366 l_term_rec LNS_TERMS_PUB.loan_term_rec_type;
7367 l_version_number number;
7368 l_terms_version_number number;
7369 l_dates_shifted_flag varchar2(1) := 'N';
7370
7371
7372 CURSOR move_maturity_date_cur(P_LOAN_ID number) IS
7373 select
7374 CASE
7375 WHEN (nvl(loan.CURRENT_PHASE, 'TERM') = 'OPEN') THEN
7376 sign(trunc(loan.OPEN_MATURITY_DATE) - (select trunc(max(PAYMENT_REQUEST_DATE)) from LNS_DISB_HEADERS where LOAN_ID = loan.LOAN_ID))
7377 WHEN (nvl(loan.CURRENT_PHASE, 'TERM') = 'TERM' and loan.MULTIPLE_FUNDING_FLAG = 'N') THEN
7378 sign(trunc(loan.LOAN_MATURITY_DATE) - (select trunc(max(PAYMENT_REQUEST_DATE)) from LNS_DISB_HEADERS where LOAN_ID = loan.LOAN_ID))
7379 ELSE
7380 1
7381 END
7382 from lns_loan_headers loan
7383 where loan.LOAN_ID = p_loan_id;
7384
7385
7386 cursor c_loan_info (p_loan_id number) is
7387 select t.open_payment_frequency
7388 ,decode(h.current_phase, 'OPEN', h.open_maturity_date, h.loan_maturity_date)
7389 ,nvl(h.custom_payments_flag, 'N')
7390 ,h.open_to_term_flag
7391 ,decode(h.current_phase, 'OPEN', h.open_loan_term, h.loan_term)
7392 ,decode(h.current_phase, 'OPEN', h.open_loan_term_period, h.loan_term_period)
7393 ,h.OBJECT_VERSION_NUMBER
7394 ,t.object_VERSION_NUMBER
7395 ,t.term_id
7396 ,h.current_phase
7397 from lns_terms t
7398 ,lns_loan_headers h
7399 where h.loan_id = p_loan_id
7400 and h.loan_id = t.loan_id;
7401
7402 cursor c_max_pay_req_date(p_loan_id number) is
7403 select max(payment_request_date)
7404 from lns_disb_headers
7405 where loan_id = p_loan_id;
7406
7407 begin
7408 -- Standard Start of API savepoint
7409 SAVEPOINT shiftLoan;
7410 l_api_name := 'shiftLoan';
7411 i := 0;
7412
7413 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7414 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
7415
7416 -- Initialize API return status to SUCCESS
7417 x_return_status := FND_API.G_RET_STS_SUCCESS;
7418
7419 --
7420 -- Api body
7421 -- -----------------------------------------------------------------
7422 open move_maturity_date_cur(P_LOAN_ID);
7423 fetch move_maturity_date_cur into l_move_maturity_date;
7424 close move_maturity_date_cur;
7425
7426 if l_move_maturity_date = -1 then
7427
7428 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - we need to move the loan');
7429
7430 -- get the final payment request date
7431 open c_max_pay_req_date(p_loan_id);
7432 fetch c_max_pay_req_date into l_max_pay_request_date;
7433 close c_max_pay_req_date;
7434 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_max_pay_request_date' || l_max_pay_request_date);
7435
7436 -- get loan info
7437 open c_loan_info(p_loan_id);
7438 fetch c_loan_info into
7439 l_payment_frequency
7440 ,l_old_maturity_date
7441 ,l_custom_payments_flag
7442 ,l_term_phase_exists
7443 ,l_term
7444 ,l_term_period
7445 ,l_version_number
7446 ,l_terms_version_number
7447 ,l_term_id
7448 ,l_current_phase;
7449 close c_loan_info;
7450
7451 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_payment_frequency ' || l_payment_frequency);
7452 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_old_maturity_date ' || l_old_maturity_date );
7453 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_custom_payments_flag ' || l_custom_payments_flag);
7454 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_phase_exists ' || l_term_phase_exists );
7455 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term ' || l_term);
7456 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_period ' || l_term_period );
7457 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_version_number ' || l_version_number );
7458 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_terms_version_number ' || l_terms_version_number );
7459 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_id ' || l_term_id );
7460
7461 if l_custom_payments_flag <> 'Y' then
7462 -- we will be converting the term of the loan if frequency > MONTHLY
7463 if l_payment_frequency <> 'SEMI-MONTHLY' AND l_payment_frequency <> 'WEEKLY' then
7464 l_new_frequency := 'MONTHS';
7465 l_initial_months := lns_fin_utils.convertPeriod(p_term => l_term
7466 ,p_term_period => l_term_period);
7467 else
7468 --weeks or semi-months
7469 if substr(l_payment_frequency, length(l_payment_frequency) - 1, 2) = 'LY' then
7470 l_temp := substr(l_payment_frequency, 1, length(l_payment_frequency) - 2) || 'S';
7471 else
7472 l_temp := l_payment_frequency;
7473 end if;
7474 l_new_frequency := l_temp;
7475 l_initial_months := l_term;
7476 end if;
7477 l_new_maturity_Date := l_old_maturity_date;
7478
7479 loop
7480 -- i will be the number of "TERMS" to add the LNS_LOAN_HEADERS.TERM
7481 i := i + 1;
7482 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - i ' || l_new_maturity_date);
7483 l_new_maturity_date := lns_fin_utils.getNextDate(p_date => l_new_maturity_date
7484 ,p_interval_type => l_new_frequency
7485 ,p_direction => 1);
7486 exit when l_new_maturity_date >= l_max_pay_request_date;
7487 end loop;
7488
7489 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NEW MATURITY DATE' || l_new_maturity_date );
7490
7491 --now we move the loan dates
7492 if (l_current_phase = 'OPEN' and l_term_phase_exists = 'Y') then
7493 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting new term dates');
7494
7495 -- Bug#6169438, Added new parameter l_dates_shifted_flag
7496 shiftLoanDates(p_loan_id => p_loan_id
7497 ,p_new_start_date => l_new_maturity_date
7498 ,p_phase => 'TERM'
7499 ,x_loan_details => l_loan_details
7500 ,x_dates_shifted_flag => l_dates_shifted_flag
7501 ,x_return_status => l_return_status
7502 ,x_msg_count => l_msg_count
7503 ,x_msg_data => l_msg_data);
7504 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM start date is ' || l_loan_details.loan_start_date);
7505 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM first payment date is ' || l_loan_details.first_payment_Date);
7506 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM maturity date is ' || l_loan_details.maturity_date);
7507
7508 -- items to update for term phase
7509 l_term_rec.term_id := l_term_id;
7510 l_term_rec.FIRST_PAYMENT_DATE := l_loan_details.first_payment_Date;
7511 l_term_rec.NEXT_PAYMENT_DUE_DATE := l_loan_details.first_payment_Date;
7512 l_loan_header_rec.loan_maturity_date := l_loan_details.maturity_date;
7513 l_loan_header_rec.loan_start_date := l_loan_details.loan_start_date;
7514 lns_terms_pub.update_term(p_object_version_number => l_terms_version_number
7515 ,p_init_msg_list => fnd_api.g_false
7516 ,p_loan_term_rec => l_term_rec
7517 ,x_return_status => l_return_status
7518 ,x_msg_count => l_msg_count
7519 ,x_msg_data => l_msg_data);
7520 end if;
7521
7522 if l_current_phase = 'OPEN' then
7523 -- update items for loan header table
7524 l_loan_header_rec.loan_id := p_loan_id;
7525 l_loan_header_rec.open_maturity_date := l_new_maturity_date;
7526 l_loan_header_rec.open_loan_term := l_initial_months + i;
7527 l_loan_header_rec.open_loan_term_period := l_new_frequency;
7528
7529 lns_loan_header_pub.update_loan(p_object_version_number => l_version_number
7530 ,p_loan_header_rec => l_loan_header_rec
7531 ,p_init_msg_list => fnd_api.g_false
7532 ,x_return_status => l_return_status
7533 ,x_msg_count => l_msg_count
7534 ,x_msg_data => l_msg_data);
7535 elsif l_current_phase = 'TERM' then
7536
7537 l_loan_header_rec.loan_id := p_loan_id;
7538 l_loan_header_rec.loan_maturity_date := l_new_maturity_date;
7539 l_loan_header_rec.loan_term := l_initial_months + i;
7540 l_loan_header_rec.loan_term_period := l_new_frequency;
7541
7542 lns_loan_header_pub.update_loan(p_object_version_number => l_version_number
7543 ,p_loan_header_rec => l_loan_header_rec
7544 ,p_init_msg_list => fnd_api.g_false
7545 ,x_return_status => l_return_status
7546 ,x_msg_count => l_msg_count
7547 ,x_msg_data => l_msg_data);
7548
7549 end if; -- open phase
7550 end if; -- custom payments
7551
7552 else
7553 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NOTHING TO MOVE');
7554 end if;
7555
7556 --
7557 -- End of API body
7558 -- ----------------------------------------------------------------
7559 --
7560 -- Standard check for p_commit
7561 IF FND_API.to_Boolean(p_commit) THEN
7562 COMMIT WORK;
7563 END IF;
7564
7565
7566 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7567
7568 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7569
7570 EXCEPTION
7571 WHEN FND_API.G_EXC_ERROR THEN
7572 ROLLBACK TO shiftLoan;
7573 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7574 x_return_status := FND_API.G_RET_STS_ERROR;
7575 x_msg_count := l_msg_count;
7576 x_msg_data := l_msg_data;
7577 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7578
7579 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
7580 ROLLBACK TO shiftLoan;
7581 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7582 x_return_status := FND_API.G_RET_STS_ERROR;
7583 x_msg_count := l_msg_count;
7584 x_msg_data := l_msg_data;
7585 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7586
7587 WHEN OTHERS THEN
7588 ROLLBACK TO shiftLoan;
7589 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7590 x_return_status := FND_API.G_RET_STS_ERROR;
7591 x_msg_count := l_msg_count;
7592 x_msg_data := l_msg_data;
7593 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7594
7595 end shiftLoan;
7596
7597 /*=========================================================================
7598 || PUBLIC PROCEDURE shiftLoanDates
7599 ||
7600 || DESCRIPTION
7601 ||
7602 || Overview: procedure will return a new loan details record with
7603 || shifted dates
7604 ||
7605 || Parameter: p_loan_id = loan_id
7606 || p_new_start_Date = new start date of loan
7607 ||
7608 || Source Tables: NA
7609 ||
7610 || Target Tables:
7611 ||
7612 || Return value: x_loan_Details
7613 || detail record of the loan with the new dates
7614 ||
7615 || KNOWN ISSUES
7616 ||
7617 || NOTES
7618 ||
7619 || MODIFICATION HISTORY
7620 || Date Author Description of Changes
7621 || 11/29/2004 11:35AM raverma Created
7622 || 7/29/2005 raverma added p_phase
7623 || 14-JUL-2007 mbolli Bug#6169438 - Added new OUT parameter x_dates_shifted_flag
7624 *====================================================================================================*/
7625 procedure shiftLoanDates(p_loan_id in number
7626 ,p_new_start_date in date
7627 ,p_phase in varchar2
7628 ,x_loan_details out NOCOPY lns_financials.loan_details_rec
7629 ,x_dates_shifted_flag OUT NOCOPY VARCHAR2
7630 ,x_return_status OUT NOCOPY VARCHAR2
7631 ,x_msg_count OUT NOCOPY NUMBER
7632 ,x_msg_data OUT NOCOPY VARCHAR2)
7633 is
7634 l_return_status VARCHAR2(1);
7635 l_msg_count NUMBER;
7636 l_msg_data VARCHAR2(32767);
7637 l_api_name varchar2(25);
7638 l_loan_details lns_financials.loan_Details_rec;
7639 l_day_difference number;
7640 l_new_maturity_date date;
7641 l_new_first_payment_date date;
7642 x number;
7643
7644 begin
7645
7646 -- Standard Start of API savepoint
7647 SAVEPOINT shiftLoanDates;
7648 l_api_name := 'shiftLoanDates';
7649 x := 0;
7650
7651 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7652 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
7653 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_new_start_date ' || p_new_start_date);
7654 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
7655
7656 -- Initialize API return status to SUCCESS
7657 x_return_status := FND_API.G_RET_STS_SUCCESS;
7658 x_dates_shifted_flag := 'N';
7659
7660 --
7661 -- Api body
7662 -- ----------------------------------------------------------------
7663 lns_utility_pub.validate_any_id(p_api_version => 1.0
7664 ,p_init_msg_list => 'T'
7665 ,x_msg_count => l_msg_count
7666 ,x_msg_data => l_msg_data
7667 ,x_return_status => l_return_status
7668 ,p_col_id => p_loan_id
7669 ,p_col_name => 'LOAN_ID'
7670 ,p_table_name => 'LNS_LOAN_HEADERS_ALL');
7671
7672 if l_return_status <> FND_API.G_RET_STS_SUCCESS then
7673 FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
7674 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
7675 FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
7676 FND_MSG_PUB.ADD;
7677 RAISE FND_API.G_EXC_ERROR;
7678 end if;
7679
7680 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
7681 ,p_based_on_terms => 'ORIGINAL'
7682 ,p_phase => p_phase);
7683
7684 if p_new_start_date > l_loan_details.first_payment_Date then
7685 l_new_first_payment_date := p_new_start_date;
7686 else
7687 l_new_first_payment_date := l_loan_details.first_payment_Date;
7688 end if;
7689
7690 -- figure out difference between the old start and old first payment date
7691 -- if this lands on the same date as add_months then use add_months, else it is not moved from original first_payment_date
7692 -- it is then up to the user to move the first payment date on UI
7693 for i in 1..l_loan_details.number_installments Loop
7694 x := x + 1;
7695 if l_loan_details.first_payment_date = add_months(l_loan_details.loan_start_date, x) then
7696 l_new_first_payment_date := add_months(p_new_start_date, x);
7697 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - matched date at ' || x);
7698 exit;
7699 end if;
7700 end loop;
7701
7702 /* see bug #4178486
7703 -- count the difference between the old start date and old first payment date
7704 -- this is according to the day count method
7705 l_day_difference := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_details.loan_start_Date
7706 ,p_end_date => l_loan_details.first_payment_Date
7707 ,p_day_count_method => l_loan_details.day_count_method);
7708 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_day_difference ' || l_day_difference);
7709
7710 -- tack on the same number of days to the new loan start date
7711 l_new_first_payment_date := p_new_start_Date + l_day_difference;
7712 */
7713 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_first_payment_date ' || l_new_first_payment_date);
7714
7715 -- get the new maturity date
7716 l_new_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term => l_loan_Details.loan_term
7717 ,p_term_period => l_loan_Details.loan_term_period
7718 ,p_frequency => l_loan_Details.amortization_frequency
7719 ,p_start_date => p_new_start_date);
7720
7721 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_maturity_date ' || l_new_maturity_date);
7722
7723 --Bug#6169438 - Check whether the loan dates are changed or not.
7724 IF ((l_loan_Details.loan_start_date <> p_new_start_date) OR (l_loan_details.first_payment_Date <> l_new_first_payment_date) OR (l_loan_Details.maturity_Date <> l_new_maturity_Date)) THEN
7725 x_dates_shifted_flag := 'Y';
7726 END IF;
7727
7728 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_dates_shifted_flag ' || x_dates_shifted_flag);
7729
7730
7731 -- assign the new dates to the loan details record
7732 l_loan_Details.loan_start_date := p_new_start_date;
7733 l_loan_details.first_payment_Date := l_new_first_payment_date;
7734 l_loan_Details.maturity_Date := l_new_maturity_Date;
7735
7736 x_loan_details := l_loan_details;
7737 --
7738 -- End of API body
7739 --
7740 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7741
7742 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7743
7744 EXCEPTION
7745 WHEN FND_API.G_EXC_ERROR THEN
7746 ROLLBACK TO shiftLoanDates;
7747 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7748 x_return_status := FND_API.G_RET_STS_ERROR;
7749 x_msg_count := l_msg_count;
7750 x_msg_data := l_msg_data;
7751 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7752
7753 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
7754 ROLLBACK TO shiftLoanDates;
7755 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7756 x_return_status := FND_API.G_RET_STS_ERROR;
7757 x_msg_count := l_msg_count;
7758 x_msg_data := l_msg_data;
7759 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7760
7761 WHEN OTHERS THEN
7762 ROLLBACK TO shiftLoanDates;
7763 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7764 x_return_status := FND_API.G_RET_STS_ERROR;
7765 x_msg_count := l_msg_count;
7766 x_msg_data := l_msg_data;
7767 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7768 end shiftLoanDates;
7769
7770
7771 /*=========================================================================
7772 || PUBLIC PROCEDURE calculateEPPayment
7773 ||
7774 || DESCRIPTION
7775 ||
7776 || Overview: returns a termly equal principal payment amount for a loan
7777 ||
7778 || PSEUDO CODE/LOGIC
7779 ||
7780 || PARAMETERS
7781 ||
7782 || Parameter: p_loan_amount => amount of loan
7783 || p_num_intervals => number of installments for loan
7784 || p_ending_balance => future or residual value of the loan (most loans will pass 0)
7785 || p_pay_in_arrears => true if payments are at end of period
7786 || false otherwise
7787 ||
7788 || payment = (p_loan_amount - p_ending_balance) / p_num_intervals;
7789 ||
7790 || Return value: principal amount to pay per installment
7791 ||
7792 || Source Tables: NA
7793 ||
7794 || Target Tables: NA
7795 ||
7796 || KNOWN ISSUES
7797 ||
7798 || NOTES
7799 ||
7800 || MODIFICATION HISTORY
7801 || Date Author Description of Changes
7802 || 09/13/2007 scherkas Created
7803 *=======================================================================*/
7804 function calculateEPPayment(p_loan_amount in number
7805 ,p_num_intervals in number
7806 ,p_ending_balance in number
7807 ,p_pay_in_arrears in boolean) return number
7808
7809 is
7810 l_periodic_amount number;
7811 l_api_name varchar2(25);
7812
7813 begin
7814
7815 l_api_name := 'calculateEPPayment';
7816 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7817
7818 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ': loan amount is ' || p_loan_amount);
7819 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ending balance is ' || p_ending_balance);
7820 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number of intervals is ' || p_num_intervals);
7821
7822 l_periodic_amount := (p_loan_amount - p_ending_balance) / p_num_intervals;
7823
7824 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic_prin_amount: ' || l_periodic_amount);
7825 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7826
7827 return l_periodic_amount;
7828
7829 Exception
7830 When others then
7831 null;
7832
7833 end calculateEPPayment;
7834
7835
7836
7837 /*=========================================================================
7838 || PUBLIC PROCEDURE calculatePayment
7839 ||
7840 || DESCRIPTION
7841 ||
7842 || Overview: returns a termly payment amount for a loan
7843 ||
7844 || PSEUDO CODE/LOGIC
7845 ||
7846 || PARAMETERS
7847 ||
7848 || Parameter: p_annualized_rate => annual rate of the loan
7849 || p_loan_amount => amount of loan
7850 || p_num_intervals => number of installments for loan
7851 || p_ending_balance => future or residual value of the loan (most loans will pass 0)
7852 || p_pay_in_arrears => true if payments are at end of period
7853 || false otherwise
7854 ||
7855 || payment =
7856 || loan_amount x periodic_rate /
7857 || (1 - (1 / (1 + periodic_rate)^p_num_intervals )) -
7858 || p_ending_balance x periodic_rate /
7859 || ((1 + periodic_rate)^p_num_intervals -1)
7860 ||
7861 || Return value: amount to pay per installment
7862 ||
7863 || Source Tables: NA
7864 ||
7865 || Target Tables: NA
7866 ||
7867 || KNOWN ISSUES
7868 ||
7869 || NOTES
7870 ||
7871 || MODIFICATION HISTORY
7872 || Date Author Description of Changes
7873 || 12/11/2003 12:40PM raverma Created
7874 || 7/22/2003 raverma enable pay in arrears = false
7875 *=======================================================================*/
7876 function calculatePayment(p_loan_amount in number
7877 ,p_periodic_rate in number
7878 ,p_num_intervals in number
7879 ,p_ending_balance in number
7880 ,p_pay_in_arrears in boolean) return number
7881
7882 is
7883 l_periodic_amount number;
7884 l_numerator number;
7885 l_denominator number;
7886 l_api_name varchar2(25);
7887 l_num_intervals number;
7888
7889 begin
7890
7891 l_api_name := 'calculatePayment';
7892 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7893
7894 if p_pay_in_arrears then
7895 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' pay in arrears');
7896 else
7897 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' pay in advance');
7898 end if;
7899 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number of intervals is ' || p_num_intervals);
7900 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate is ' || p_periodic_rate);
7901 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ending balance is ' || p_ending_balance);
7902 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ': loan amount is ' || p_loan_amount);
7903
7904 l_num_intervals := p_num_intervals;
7905 if l_num_intervals = 0 then
7906 l_num_intervals := 1;
7907 end if;
7908 -- check for 0 percent interest
7909 -- this is the pay in arrears formula
7910
7911 if p_ending_balance = 0 then
7912
7913 if p_pay_in_arrears then
7914 if p_periodic_rate <> 0 then
7915 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 1');
7916 l_numerator := p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount;
7917 l_denominator := Power ((1 + p_periodic_rate), l_num_intervals) - 1;
7918 else
7919 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 2');
7920 l_numerator := Power (1, l_num_intervals) * p_loan_amount;
7921 l_denominator := l_num_intervals;
7922 end if;
7923 else
7924 if p_periodic_rate <> 0 then
7925 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 3');
7926 l_numerator := p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount;
7927 l_denominator := Power ((1 + p_periodic_rate), l_num_intervals) - 1;
7928 else
7929 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 4');
7930 l_numerator := Power (1, l_num_intervals - 1) * p_loan_amount;
7931 l_denominator := l_num_intervals;
7932 end if;
7933
7934 end if;
7935
7936 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': numerator:' || l_numerator);
7937 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': denominator:' || l_denominator);
7938
7939 l_periodic_amount := l_numerator / l_denominator;
7940
7941 else -- for case of balloon payment
7942
7943 if p_pay_in_arrears then
7944 if p_periodic_rate <> 0 then
7945
7946 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 5');
7947 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) ) +
7948 ( (p_periodic_rate * p_ending_balance) / ((1 + p_periodic_rate) - Power ((1 + p_periodic_rate), l_num_intervals + 1)) );
7949
7950 else
7951 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 6');
7952 l_periodic_amount := ( (Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount) / l_num_intervals ) -
7953 ( p_ending_balance / l_num_intervals );
7954 end if;
7955
7956 else
7957 if p_periodic_rate <> 0 then
7958 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 7');
7959 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) ) +
7960 ( (p_periodic_rate * p_ending_balance) / ((1 + p_periodic_rate) - Power ((1 + p_periodic_rate), l_num_intervals + 1)) );
7961 else
7962 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 8');
7963 l_periodic_amount := ( (Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount) / l_num_intervals ) -
7964 ( p_ending_balance / l_num_intervals );
7965 end if;
7966
7967 end if;
7968
7969 end if;
7970
7971 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic_amount: ' || l_periodic_amount);
7972 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7973
7974 return l_periodic_amount;
7975
7976 Exception
7977 When others then
7978 null;
7979
7980 end calculatePayment;
7981
7982 /*=========================================================================
7983 || PUBLIC PROCEDURE calculateInterest
7984 ||
7985 || DESCRIPTION
7986 ||
7987 || Overview: returns an interest due on a loan
7988 || we will use the formula:
7989 || FV = P*r^n
7990 || where FV = future value at a given point in time
7991 || PV = Present value of loan / capital
7992 || r = rate annualized
7993 || n = period of payment
7994 || to compound interest continually we use the formula:
7995 || FV = Pe^(Yr)
7996 || where Y = years and
7997 || e = 2.71828....
7998 ||
7999 || PSEUDO CODE/LOGIC
8000 ||
8001 || PARAMETERS
8002 ||
8003 || Parameter: p_amount = amount of loan
8004 || p_annual_rate = interest rate for loan expressed as a whole number
8005 || p_start_date = date at which interest is calculated
8006 || p_end_date = date at which interest in ended
8007 || p_compounding_period = for future use
8008 ||
8009 || Return value: amount interest due
8010 ||
8011 || Source Tables: NA
8012 ||
8013 || Target Tables: NA
8014 ||
8015 || KNOWN ISSUES
8016 ||
8017 || NOTES
8018 ||
8019 || MODIFICATION HISTORY
8020 || Date Author Description of Changes
8021 || 12/08/2003 10:56AM raverma Created
8022 || 03/17/2004 raverma don't allow negative interest for now
8023 *=======================================================================*/
8024 function calculateInterest(p_amount in number
8025 ,p_periodic_rate in number
8026 ,p_compounding_period in varchar2) return number
8027 is
8028 l_periodic_rate number;
8029 l_amount number;
8030 l_api_name varchar2(25);
8031
8032 begin
8033
8034 l_api_name := 'calculateInterest';
8035 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8036 if p_amount > 0 then
8037 l_amount := p_amount;
8038 else
8039 l_amount := 0;
8040 end if;
8041
8042 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8043
8044 return l_amount * p_periodic_rate;
8045
8046 end calculateInterest;
8047
8048 /*=========================================================================
8049 || PUBLIC FUNCTION validatePayoff
8050 ||
8051 || DESCRIPTION
8052 || contains validation rules on dates and statuses for a payoff
8053 ||
8054 || PSEUDO CODE/LOGIC
8055 ||
8056 || PARAMETERS
8057 ||
8058 || Return value:
8059 ||
8060 || Source Tables: NA
8061 ||
8062 || Target Tables: NA
8063 ||
8064 || KNOWN ISSUES
8065 ||
8066 || NOTES
8067 ||
8068 ||
8069 || MODIFICATION HISTORY
8070 || Date Author Description of Changes
8071 || 10/26/2004 12:55PM raverma Created
8072 *=======================================================================*/
8073 procedure validatePayoff(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
8074 ,p_payoff_date in date
8075 ,x_return_status OUT NOCOPY VARCHAR2
8076 ,x_msg_count OUT NOCOPY NUMBER
8077 ,x_msg_data OUT NOCOPY VARCHAR2)
8078
8079 is
8080 l_api_name varchar2(25);
8081 l_api_version_number number;
8082 l_return_status VARCHAR2(1);
8083 l_msg_count NUMBER;
8084 l_msg_data VARCHAR2(32767);
8085
8086 begin
8087
8088 -- Initialize API return status to SUCCESS
8089 x_return_status := FND_API.G_RET_STS_SUCCESS;
8090 l_api_name := 'validatePayoff';
8091 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8092 --
8093 -- Api body
8094 -- --------------------------------------------------------------------
8095
8096
8097 -- these dates should be further restricted
8098 if p_loan_details.loan_status = 'PAIDOFF' then
8099 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_ALREADY');
8100 FND_MSG_PUB.Add;
8101 RAISE FND_API.G_EXC_ERROR;
8102
8103 --karamach --Bug5295446 --Need to prevent payoff for loans in Approved status as well
8104 --elsif p_loan_details.loan_status = 'INCOMPLETE' or p_loan_details.loan_status = 'DELETED' or
8105 -- p_loan_details.loan_status = 'REJECTED' or p_loan_details.loan_status = 'PENDING' then
8106 elsif p_loan_details.loan_status IN ('INCOMPLETE','DELETED','REJECTED','PENDING','APPROVED') then
8107 FND_MESSAGE.Set_Name('LNS', 'LNS_INVOICE_SUMMARY_ERROR');
8108 FND_MSG_PUB.Add;
8109 RAISE FND_API.G_EXC_ERROR;
8110 end if;
8111
8112 if p_payoff_date < p_loan_details.last_interest_accrual then
8113 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff too early');
8114 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_TOO_EARLY');
8115 FND_MESSAGE.SET_TOKEN('PAYOFF_DATE', fnd_date.date_to_displaydate(p_loan_details.last_interest_accrual));
8116 FND_MSG_PUB.Add;
8117 RAISE FND_API.G_EXC_ERROR;
8118 end if;
8119
8120 if p_payoff_date < p_loan_details.last_activity_date then
8121 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff too early');
8122 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_TOO_EARLY2');
8123 FND_MESSAGE.SET_TOKEN('PARAMETER', 'LAST_ACTIVITY_DATE');
8124 FND_MESSAGE.SET_TOKEN('VALUE', fnd_date.date_to_displaydate(p_loan_details.last_activity_date));
8125 FND_MSG_PUB.Add;
8126 RAISE FND_API.G_EXC_ERROR;
8127 end if;
8128
8129 /* raverma added 12-08-05 */
8130 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling LNS_FUNDING_PUB.validate_disb_for_payoff returns ');
8131 LNS_FUNDING_PUB.VALIDATE_DISB_FOR_PAYOFF(P_API_VERSION => 1.0
8132 ,P_INIT_MSG_LIST => FND_API.G_FALSE
8133 ,P_COMMIT => FND_API.G_FALSE
8134 ,P_VALIDATION_LEVEL => 100
8135 ,P_LOAN_ID => p_loan_details.loan_id
8136 ,x_return_status => l_return_status
8137 ,x_msg_count => l_msg_count
8138 ,x_msg_data => l_msg_data);
8139 if l_return_Status <> FND_API.G_RET_STS_SUCCESS then
8140 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - validate_disb_for_payoff returns ' || l_return_Status);
8141 RAISE FND_API.G_EXC_ERROR;
8142 end if;
8143
8144 x_return_status := l_return_Status;
8145 -- --------------------------------------------------------------------
8146 -- End of API body
8147 --
8148
8149 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8150
8151 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8152
8153 exception
8154
8155 WHEN FND_API.G_EXC_ERROR THEN
8156 x_return_status := FND_API.G_RET_STS_ERROR;
8157 x_msg_count := l_msg_count;
8158 x_msg_data := l_msg_data;
8159 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8160 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8161
8162 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8163 x_return_status := FND_API.G_RET_STS_ERROR;
8164 x_msg_count := l_msg_count;
8165 x_msg_data := l_msg_data;
8166 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8167 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8168
8169 WHEN OTHERS THEN
8170 x_return_status := FND_API.G_RET_STS_ERROR;
8171 x_msg_count := l_msg_count;
8172 x_msg_data := l_msg_data;
8173 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8174 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8175
8176 end validatePayoff;
8177
8178 /*=========================================================================
8179 || PUBLIC FUNCTION calculatePayoff
8180 ||
8181 || DESCRIPTION
8182 || calculate any additional interest due on loan, etc fees, to
8183 || pay off
8184 ||
8185 || PSEUDO CODE/LOGIC
8186 || 1. get number of interest rates running over remaining period
8187 || 2. get weighted average of those rates
8188 || 3. calculate interest due on remaining principal
8189 || from payoff_date
8190 ||
8191 || PARAMETERS
8192 || p_loan_id => loan_id to payoff
8193 || p_payoff_date => date at which to payoff the loan
8194 ||
8195 || Return value:
8196 ||
8197 || Source Tables: NA
8198 ||
8199 || Target Tables: NA
8200 ||
8201 || KNOWN ISSUES
8202 ||
8203 || NOTES
8204 ||
8205 ||
8206 || MODIFICATION HISTORY
8207 || Date Author Description of Changes
8208 || 03/24/2004 12:55PM raverma Created
8209 || 04/15/2004 raverma check to see if loan is PAIDOFF
8210 *=======================================================================*/
8211 procedure calculatePayoff(p_api_version IN NUMBER
8212 ,p_init_msg_list IN VARCHAR2
8213 ,p_loan_id in number
8214 ,p_payoff_date in date
8215 ,x_payoff_tbl OUT NOCOPY LNS_FINANCIALS.PAYOFF_TBL2
8216 ,x_return_status OUT NOCOPY VARCHAR2
8217 ,x_msg_count OUT NOCOPY NUMBER
8218 ,x_msg_data OUT NOCOPY VARCHAR2)
8219 IS
8220
8221 l_api_name varchar2(25);
8222 l_api_version_number number;
8223 l_return_status VARCHAR2(1);
8224 l_msg_count NUMBER;
8225 l_msg_data VARCHAR2(32767);
8226
8227 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
8228 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
8229 l_annualized_rate number;
8230 l_periodic_rate number;
8231 l_additional_interest number;
8232 l_additional_fees number;
8233 l_payoff_tbl LNS_FINANCIALS.PAYOFF_TBL2;
8234 l_principal_unpaid number;
8235 l_interest_unpaid number;
8236 l_fees_unpaid number;
8237 l_payoff_date date;
8238 l_from_date date;
8239 l_to_date date;
8240 l_multipler number;
8241 l_balance number;
8242 l_current_phase varchar2(30);
8243 l_rate_type varchar2(30);
8244 l_index_rate_id number;
8245 l_rate_for_date number;
8246 l_norm_interest number;
8247 l_add_prin_interest number;
8248 l_add_int_interest number;
8249 l_penal_prin_interest number;
8250 l_penal_int_interest number;
8251 l_penal_interest number;
8252 l_add_start_date date;
8253 l_add_end_date date;
8254
8255 cursor c_additional_fees(p_loan_id number) is
8256 select nvl(sum(fee_amount), 0)
8257 from lns_fee_schedules
8258 where loan_id = p_loan_id
8259 and billed_flag = 'N'
8260 and active_flag = 'Y';
8261
8262 cursor c_loan_info(p_loan_id number) is
8263 select nvl(h.current_phase, 'TERM')
8264 ,t.rate_type
8265 ,t.index_rate_id
8266 from lns_loan_headers h
8267 ,lns_terms t
8268 where h.loan_id = p_loan_id
8269 and t.loan_id = h.loan_id;
8270
8271 cursor c_get_last_bill_date(p_loan_id number, p_installment_number number) is
8272 select ACTIVITY_DATE
8273 from LNS_PRIN_TRX_ACTIVITIES_V
8274 where loan_id = p_loan_id
8275 and PAYMENT_NUMBER = p_installment_number
8276 and PARENT_AMORTIZATION_ID is null
8277 and ACTIVITY_CODE in ('BILLING', 'START');
8278
8279 begin
8280
8281 l_api_name := 'calculatePayoff';
8282 l_api_version_number := 1;
8283 l_additional_interest := 0;
8284 l_additional_fees := 0;
8285 l_principal_unpaid := 0;
8286 l_interest_unpaid := 0;
8287 l_fees_unpaid := 0;
8288 l_balance := 0;
8289 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8290 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
8291 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_payoff_date ' || p_payoff_date);
8292
8293 -- Standard Start of API savepoint
8294 SAVEPOINT calculatePayoff;
8295
8296 -- Standard call to check for call compatibility.
8297 IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
8298 l_api_name, G_PKG_NAME)
8299 THEN
8300 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
8301 END IF;
8302
8303 -- Initialize message list IF p_init_msg_list is set to TRUE.
8304 IF FND_API.to_Boolean(p_init_msg_list) THEN
8305 FND_MSG_PUB.initialize;
8306 END IF;
8307
8308 -- Initialize API return status to SUCCESS
8309 x_return_status := FND_API.G_RET_STS_SUCCESS;
8310
8311 --
8312 -- Api body
8313 -- --------------------------------------------------------------------
8314
8315 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting current phase');
8316 open c_loan_info(p_loan_id);
8317 fetch c_loan_info into l_current_phase, l_rate_type, l_index_rate_id;
8318 close c_loan_info;
8319 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - current phase ' || l_current_phase);
8320 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_type ' || l_rate_type);
8321 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_index_rate_id ' || l_index_rate_id);
8322
8323 -- bug #4865575
8324 if l_rate_type = 'VARIABLE' then
8325
8326 l_rate_for_date := lns_fin_utils.getRateForDate(p_index_rate_id => l_index_rate_id
8327 ,p_rate_date => p_payoff_date);
8328
8329 if l_rate_for_date is null then
8330 LogMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
8331 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_PAYOFF_DATE');
8332 FND_MSG_PUB.Add;
8333 RAISE FND_API.G_EXC_ERROR;
8334 end if;
8335
8336 end if;
8337
8338 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
8339 ,p_based_on_terms => 'CURRENT'
8340 ,p_phase => l_current_phase);
8341 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, l_current_phase);
8342 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - got loan details and rate info');
8343
8344 lns_financials.validatePayoff(p_loan_details => l_loan_details
8345 ,p_payoff_date => p_payoff_date
8346 ,x_return_status => l_return_status
8347 ,x_msg_count => l_msg_count
8348 ,x_msg_data => l_msg_data);
8349 IF l_return_status <> FND_API.G_RET_STS_SUCCESS THEN
8350 LogMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
8351 RAISE FND_API.G_EXC_ERROR;
8352 END IF;
8353
8354 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing late fees');
8355 lns_fee_engine.processLateFees(p_loan_id => p_loan_id
8356 ,p_init_msg_list => p_init_msg_list
8357 ,p_commit => 'F'
8358 ,x_return_status => l_return_status
8359 ,x_msg_count => l_msg_count
8360 ,x_msg_data => l_msg_data);
8361
8362 if p_payoff_date < l_loan_details.last_interest_accrual then
8363 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff prior to last interest accrual');
8364 -- we will have a interest credit
8365 l_from_date := p_payoff_date;
8366 l_to_date := l_loan_details.last_interest_accrual;
8367 l_multipler := -1;
8368 /*
8369 l_balance := lns_financials.getAverageDailyBalance(p_loan_id => p_loan_id
8370 ,p_term_id => null
8371 ,p_from_date => p_payoff_date
8372 ,p_to_date => l_loan_details.last_interest_accrual
8373 ,p_calc_method => null);
8374 */
8375 else
8376 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff after lastinterest accrual');
8377 l_from_date := l_loan_details.last_interest_accrual;
8378 l_to_date := p_payoff_date;
8379 l_multipler := 1;
8380 -- l_balance := l_loan_details.remaining_balance;
8381 end if;
8382 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - computed principal balance: ' || l_balance);
8383 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - from date: ' || l_from_date);
8384 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - to date: ' || l_to_date);
8385 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_muliplier: ' || l_multipler);
8386
8387 BEGIN
8388 -- changes as per scherkas 11-16-2005
8389 select
8390 nvl(sum(SCHED.PRINCIPAL_REMAINING),0)
8391 ,nvl(sum(SCHED.INTEREST_REMAINING),0)
8392 ,nvl(sum(SCHED.FEE_REMAINING),0)
8393 into l_principal_unpaid
8394 ,l_interest_unpaid
8395 ,l_fees_unpaid
8396 from LNS_AM_SCHEDS_V SCHED
8397 ,LNS_LOAN_HEADERS H
8398 where H.loan_id = p_loan_id and
8399 H.loan_id = Sched.loan_id and
8400 SCHED.reversed_code = 'N' and
8401 nvl(sched.phase, 'TERM') = nvl(h.current_phase, 'TERM');
8402 Exception
8403 when no_data_found then
8404 null;
8405 END;
8406 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_principal_unpaid: ' || l_principal_unpaid);
8407 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_interest_unpaid: ' || l_interest_unpaid);
8408 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_fees_unpaid: ' || l_fees_unpaid);
8409 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - status: ' || l_loan_details.loan_status);
8410
8411 -- get the wtd rate if necessary
8412 -- need to address floating rates here
8413 if l_rate_tbl.count = 1 then
8414 l_annualized_rate := l_rate_tbl(1).annual_rate;
8415 else
8416 l_annualized_rate := lns_financials.getWeightedRate(p_loan_details => l_loan_details
8417 ,p_start_date => l_from_date
8418 ,p_end_date => l_to_date
8419 ,p_rate_tbl => l_rate_tbl);
8420 end if;
8421 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_annualized_rate: ' || l_annualized_rate);
8422
8423 l_norm_interest := 0;
8424 l_add_prin_interest := 0;
8425 l_add_int_interest := 0;
8426 l_penal_prin_interest := 0;
8427 l_penal_int_interest := 0;
8428 l_penal_interest := 0;
8429
8430 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
8431 l_norm_interest := LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => p_loan_id,
8432 p_calc_method => l_loan_details.CALCULATION_METHOD,
8433 p_period_start_date => l_from_date,
8434 p_period_end_date => l_to_date,
8435 p_interest_rate => l_annualized_rate,
8436 p_day_count_method => l_loan_details.day_count_method,
8437 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
8438 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ);
8439
8440 l_norm_interest := round(l_norm_interest, l_loan_details.currency_precision);
8441
8442 -- get additional interest start date
8443 open c_get_last_bill_date(p_loan_id, l_loan_details.last_installment_billed);
8444 fetch c_get_last_bill_date into l_add_start_date;
8445 close c_get_last_bill_date;
8446
8447 -- get additional interest end date
8448 if trunc(l_add_start_date) > trunc(l_from_date) then
8449 l_add_start_date := l_from_date;
8450 end if;
8451 l_add_end_date := l_to_date;
8452
8453 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
8454 -- calculate additional interest on unpaid principal
8455 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => p_loan_id,
8456 p_calc_method => l_loan_details.CALCULATION_METHOD,
8457 p_period_start_date => l_add_start_date,
8458 p_period_end_date => l_add_end_date,
8459 p_interest_rate => l_annualized_rate,
8460 p_day_count_method => l_loan_details.day_count_method,
8461 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
8462 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
8463 p_penal_int_rate => l_loan_details.PENAL_INT_RATE,
8464 p_prev_grace_end_date => l_from_date,
8465 p_grace_start_date => l_from_date,
8466 p_grace_end_date => (l_from_date + l_loan_details.PENAL_INT_GRACE_DAYS),
8467 p_target => 'UNPAID_PRIN',
8468 x_add_interest => l_add_prin_interest,
8469 x_penal_interest => l_penal_prin_interest);
8470 l_add_prin_interest := round(l_add_prin_interest, l_loan_details.currency_precision);
8471
8472 if (l_loan_details.CALCULATION_METHOD = 'COMPOUND') then
8473
8474 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
8475 -- calculate additional interest on unpaid interest
8476
8477 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => p_loan_id,
8478 p_calc_method => l_loan_details.CALCULATION_METHOD,
8479 p_period_start_date => l_add_start_date,
8480 p_period_end_date => l_add_end_date,
8481 p_interest_rate => l_annualized_rate,
8482 p_day_count_method => l_loan_details.day_count_method,
8483 p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
8484 p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
8485 p_penal_int_rate => l_loan_details.PENAL_INT_RATE,
8486 p_prev_grace_end_date => l_from_date,
8487 p_grace_start_date => l_from_date,
8488 p_grace_end_date => (l_from_date + l_loan_details.PENAL_INT_GRACE_DAYS),
8489 p_target => 'UNPAID_INT',
8490 x_add_interest => l_add_int_interest,
8491 x_penal_interest => l_penal_int_interest);
8492 l_add_int_interest := round(l_add_int_interest, l_loan_details.currency_precision);
8493
8494 end if;
8495
8496 l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_loan_details.currency_precision);
8497 l_additional_interest := (l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest) * l_multipler;
8498 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_additional_interest: ' || l_additional_interest);
8499
8500 begin
8501 open c_additional_fees(p_loan_id);
8502 fetch c_additional_fees into l_additional_fees;
8503 close c_additional_fees;
8504 exception when no_data_found then
8505 null;
8506 end;
8507
8508 l_payoff_tbl(1).PAYOFF_PURPOSE := 'PRIN';
8509 l_payoff_tbl(1).BILLED_AMOUNT := l_principal_unpaid;
8510 l_payoff_tbl(1).UNBILLED_AMOUNT := l_loan_details.remaining_balance - l_principal_unpaid;
8511 l_payoff_tbl(1).TOTAL_AMOUNT := l_loan_details.remaining_balance;
8512
8513 l_payoff_tbl(2).PAYOFF_PURPOSE := 'INT';
8514 l_payoff_tbl(2).BILLED_AMOUNT := l_interest_unpaid;
8515 l_payoff_tbl(2).UNBILLED_AMOUNT := l_additional_interest;
8516 l_payoff_tbl(2).TOTAL_AMOUNT := l_additional_interest + l_interest_unpaid;
8517
8518 l_payoff_tbl(3).PAYOFF_PURPOSE := 'FEE';
8519 l_payoff_tbl(3).BILLED_AMOUNT := l_fees_unpaid;
8520 l_payoff_tbl(3).UNBILLED_AMOUNT := l_additional_fees;
8521 l_payoff_tbl(3).TOTAL_AMOUNT := l_fees_unpaid + l_additional_fees;
8522
8523 x_payoff_tbl := l_payoff_tbl;
8524
8525 -- --------------------------------------------------------------------
8526 -- End of API body
8527 --
8528
8529 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8530
8531 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8532
8533 EXCEPTION
8534 WHEN FND_API.G_EXC_ERROR THEN
8535 ROLLBACK TO calculatePayoff;
8536 x_return_status := FND_API.G_RET_STS_ERROR;
8537 x_msg_count := l_msg_count;
8538 x_msg_data := l_msg_data;
8539 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8540 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8541
8542 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8543 ROLLBACK TO calculatePayoff;
8544 x_return_status := FND_API.G_RET_STS_ERROR;
8545 x_msg_count := l_msg_count;
8546 x_msg_data := l_msg_data;
8547 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8548 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8549
8550 WHEN OTHERS THEN
8551 ROLLBACK TO calculatePayoff;
8552 x_return_status := FND_API.G_RET_STS_ERROR;
8553 x_msg_count := l_msg_count;
8554 x_msg_data := l_msg_data;
8555 FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8556 logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8557
8558 end calculatePayoff;
8559
8560 function frequency2ppy(p_frequency in varchar2) return number
8561 is
8562 l_ppy number;
8563 begin
8564 l_ppy := 1;
8565 if p_frequency = 'WEEKLY' then
8566 l_ppy := 52;
8567 elsif p_frequency = 'BIWEEKLY' then
8568 l_ppy := 26;
8569 elsif p_frequency = 'SEMI-MONTHLY' then
8570 l_ppy := 24;
8571 elsif p_frequency = 'MONTHLY' then
8572 l_ppy := 12;
8573 elsif p_frequency = 'BI-MONTHLY' then
8574 l_ppy := 6;
8575 elsif p_frequency = 'QUARTERLY' then
8576 l_ppy := 4;
8577 elsif p_frequency = 'SEMI-ANNUALLY' then
8578 l_ppy := 2;
8579 elsif p_frequency = 'YEARLY' then
8580 l_ppy := 1;
8581 else
8582 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_INTERVAL');
8583 FND_MESSAGE.SET_TOKEN('INTERVAL',p_frequency);
8584 FND_MSG_PUB.Add;
8585 RAISE FND_API.G_EXC_ERROR;
8586 end if;
8587
8588 return l_ppy;
8589 end;
8590
8591
8592 /*=========================================================================
8593 || PUBLIC PROCEDURE getCompoundPeriodicRate
8594 ||
8595 || DESCRIPTION
8596 ||
8597 || Overview: this function will return the compound interest rate
8598 ||
8599 || Parameters:
8600 || p_compound_freq - mandatory; compounding frequency
8601 || p_payment_freq - mandatory; payment frequency
8602 || p_start_date - optional; start date of rate
8603 || p_end_date - optional; end date of rate
8604 || p_annualized rate - mandatory; interest rate expressed as a WHOLE number
8605 || p_days_count_method - mandatory; day count method
8606 ||
8607 || Source Tables: NA
8608 ||
8609 || Target Tables: NA
8610 ||
8611 || Return value: compound periodic interest rate on the loan
8612 ||
8613 | KNOWN ISSUES
8614 |
8615 | NOTES
8616 ||
8617 || MODIFICATION HISTORY
8618 || Date Author Description of Changes
8619 || 09/21/2007 scherkas Created
8620 || 4/08/2008 scherkas Fix logic to work with any number of years between period_start_date and period_end_date
8621 *=======================================================================*/
8622 function getCompoundPeriodicRate(p_compound_freq in varchar2
8623 ,p_payment_freq in varchar2
8624 ,p_annualized_rate in number
8625 ,p_period_start_date in date
8626 ,p_period_end_date in date
8627 ,p_days_count_method in varchar2) return number
8628 is
8629 l_periodic_rate number;
8630 l_day_count number;
8631 l_days_in_year number;
8632 l_api_name varchar2(25);
8633 l_year1 number;
8634 l_year2 number;
8635 l_rate1 number;
8636 --l_rate2 number;
8637 l_days_ratio number;
8638 l_payments_per_year number;
8639 l_compounds_per_year number;
8640 l_start_date date;
8641 l_end_date date;
8642
8643 begin
8644
8645 l_api_name := 'getCompoundPeriodicRate';
8646 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8647 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
8648 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
8649 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': annualized rate: ' || p_annualized_rate);
8650 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_days_count_method);
8651 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
8652 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
8653
8654 l_periodic_rate := 0;
8655
8656 l_payments_per_year := frequency2ppy(p_payment_freq);
8657 l_compounds_per_year := frequency2ppy(p_compound_freq);
8658 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payments per year: ' || l_payments_per_year);
8659 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compounds per year: ' || l_compounds_per_year);
8660
8661 if (p_period_start_date is not null and p_period_end_date is not null) then
8662
8663 select to_number(to_char(p_period_start_date, 'YYYY')) into l_year1 from dual;
8664 select to_number(to_char(p_period_end_date, 'YYYY')) into l_year2 from dual;
8665
8666 l_days_ratio := 0;
8667
8668 for k in l_year1..l_year2 loop
8669
8670 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ------ calculating for year ' || k);
8671 l_rate1 := 0;
8672 --l_rate2 := 0;
8673 l_day_count := 0;
8674 l_days_in_year := 0;
8675
8676 if k = l_year1 then
8677 l_start_date := p_period_start_date;
8678 else
8679 l_start_date := l_end_date;
8680 end if;
8681
8682 if k = l_year2 then
8683 l_end_date := p_period_end_date;
8684 else
8685 l_end_date := to_date('01/01/' || to_char(k+1),'DD/MM/YYYY');
8686 end if;
8687
8688 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_start_date ' || l_start_date);
8689 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_date ' || l_end_date);
8690
8691 l_day_count := LNS_FIN_UTILS.getDayCount(p_start_date => l_start_date
8692 ,p_end_date => l_end_date
8693 ,p_day_count_method => p_days_count_method);
8694
8695 l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year => k
8696 ,p_year_count_method => p_days_count_method);
8697
8698 l_rate1 := l_day_count / (l_days_in_year/l_payments_per_year);
8699 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days ratio ' || l_rate1);
8700
8701 l_days_ratio := l_days_ratio + l_rate1;
8702 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total days ratio ' || l_days_ratio);
8703
8704 end loop;
8705
8706 else
8707 l_days_ratio := 1;
8708 end if;
8709
8710 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-------------');
8711 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Final days ratio ' || l_days_ratio);
8712
8713 l_periodic_rate := l_days_ratio * (Power((1+((p_annualized_rate)/(100*l_compounds_per_year))),(l_compounds_per_year/l_payments_per_year))-1);
8714
8715 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate: ' || l_periodic_rate);
8716 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8717
8718 return l_periodic_rate;
8719
8720 end getCompoundPeriodicRate;
8721
8722
8723 /*=========================================================================
8724 || PUBLIC PROCEDURE getPeriodicRate
8725 ||
8726 || DESCRIPTION
8727 ||
8728 || Overview: this function will return the interest rate for a given
8729 || period of time so the interest in a give month at
8730 || 12% interest per year will return a 1% monthly rate
8731 || (30 /360 methodology)
8732 ||
8733 || Parameter: p_start_date optional start date of rate
8734 || p_end_date optional end date of rate
8735 || p_annualized rate = interest rate expressed as a WHOLE number
8736 || p_days_count_method = for future use
8737 ||
8738 || Source Tables: NA
8739 ||
8740 || Target Tables: NA
8741 ||
8742 || Return value: periodic interest rate on the loan
8743 ||
8744 | KNOWN ISSUES
8745 |
8746 | NOTES
8747 ||
8748 || MODIFICATION HISTORY
8749 || Date Author Description of Changes
8750 || 12/09/2003 1:51PM raverma Created
8751 || 2/26/2004 raverma added more robust day / year counting methodolgy
8752 || 7/22/2004 raverma handle situation where start date = end date
8753 || 3/22/2006 karamach Fix date format issue for bug5112031
8754 || 4/08/2008 scherkas Fix logic to work with any number of years between period_start_date and period_end_date
8755 *=======================================================================*/
8756 function getPeriodicRate(p_period_start_date in date
8757 ,p_period_end_date in date
8758 ,p_annualized_rate in number
8759 ,p_days_count_method in varchar2) return number
8760 is
8761 l_annual_rate number;
8762 l_periodic_rate number;
8763 l_day_count number;
8764 l_days_in_year number;
8765 l_api_name varchar2(25);
8766 l_year1 number;
8767 l_year2 number;
8768 l_periodic_factor number;
8769 l_rate1 number;
8770 l_rate2 number;
8771 l_start_date date;
8772 l_end_date date;
8773
8774 begin
8775
8776 l_api_name := 'getPeriodicRate';
8777 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8778 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_days_count_method);
8779 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': annualized rate: ' || p_annualized_rate);
8780 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
8781 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
8782
8783 l_annual_rate := p_annualized_rate / 100;
8784 l_periodic_rate := 0;
8785
8786 select to_number(to_char(p_period_start_date, 'YYYY')) into l_year1 from dual;
8787 select to_number(to_char(p_period_end_date, 'YYYY')) into l_year2 from dual;
8788
8789 for k in l_year1..l_year2 loop
8790
8791 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ------ calculating for year ' || k);
8792 l_rate1 := 0;
8793 l_day_count := 0;
8794 l_days_in_year := 0;
8795
8796 if k = l_year1 then
8797 l_start_date := p_period_start_date;
8798 else
8799 l_start_date := l_end_date;
8800 end if;
8801
8802 if k = l_year2 then
8803 l_end_date := p_period_end_date;
8804 else
8805 l_end_date := to_date('01/01/' || to_char(k+1),'DD/MM/YYYY');
8806 end if;
8807
8808 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_start_date ' || l_start_date);
8809 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_date ' || l_end_date);
8810
8811 l_day_count := LNS_FIN_UTILS.getDayCount(p_start_date => l_start_date
8812 ,p_end_date => l_end_date
8813 ,p_day_count_method => p_days_count_method);
8814
8815 l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year => k
8816 ,p_year_count_method => p_days_count_method);
8817
8818 l_rate1 := (l_day_count / l_days_in_year) * l_annual_rate;
8819 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate1 ' || l_rate1);
8820
8821 l_periodic_rate := l_periodic_rate + l_rate1;
8822 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic rate ' || l_periodic_rate);
8823
8824 end loop;
8825
8826 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-------------');
8827 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Final Periodic rate ' || l_periodic_rate);
8828 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8829
8830 return l_periodic_rate;
8831
8832 end getPeriodicRate;
8833
8834 /*
8835 ||
8836 || Parameter: p_rate = annualized interest rate
8837 || p_period_value = time factor like '2'
8838 || p_period_type = 'DAILY', 'WEEKLY', 'BI-WEEKLY', 'MONTHLY'
8839 || 'BI-MONTHLY',
8840 || Return value:
8841 ||
8842 || Source Tables:
8843 ||
8844 || Target Tables:
8845 ||
8846 || Creation date: 12/08/2003 3:33PM
8847 ||
8848 || Major Modifications: when who what
8849 ||
8850 */
8851 function compoundInterest(p_rate in number
8852 ,p_period_value in number
8853 ,p_period_type in varchar2) return number
8854 is
8855 begin
8856 null;
8857 end compoundInterest;
8858
8859 /*=========================================================================
8860 || PUBLIC PROCEDURE getAnnualRate
8861 ||
8862 || DESCRIPTION
8863 ||
8864 || Overview: gets the current interest rate for the loan
8865 ||
8866 || Parameter: loan_id
8867 ||
8868 || Return value: current annual rate for the loan
8869 ||
8870 || Source Tables: LNS_RATE_SCHEDULES
8871 ||
8872 || Target Tables: NA
8873 ||
8874 || KNOWN ISSUES
8875 ||
8876 || NOTES
8877 ||
8878 || MODIFICATION HISTORY
8879 || Date Author Description of Changes
8880 || 12/15/2003 4:28PM raverma Created
8881 ||
8882 *=======================================================================*/
8883 function getAnnualRate(p_loan_Id in number) return number
8884 is
8885 l_rate number;
8886 l_api_name varchar2(20);
8887
8888 begin
8889
8890 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8891
8892 select rs.current_interest_rate into l_rate
8893 from lns_rate_schedules rs,
8894 lns_terms t,
8895 lns_loan_headers_all h
8896 where h.loan_id = p_loan_id
8897 and h.loan_id = t.loan_id
8898 and rs.term_id = t.term_id
8899 and rs.start_date_active <= sysdate
8900 and rs.end_date_active >= sysdate;
8901
8902 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8903
8904 return l_rate;
8905
8906 Exception
8907
8908 When Others then
8909 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Error: ' || sqlerrm);
8910 --seed this message
8911 -- FND_MESSAGE.Set_Name('LNS', 'LNS_UNABLE_TO_COMPUTE_BALANCE');
8912 -- FND_MSG_PUB.Add;
8913 -- RAISE FND_API.G_EXC_ERROR;
8914
8915 end getAnnualRate;
8916
8917 /*=========================================================================
8918 || PUBLIC PROCEDURE getActiveRate
8919 ||
8920 || DESCRIPTION
8921 ||
8922 || Overview: gets the current interest rate for the loan
8923 || we will look at the last installment billed (not reversed)
8924 || to get the rate on the loan
8925 || Parameter: loan_id
8926 ||
8927 || Return value: current annual rate for the loan
8928 ||
8929 || Source Tables: LNS_RATE_SCHEDULES,
8930 ||
8931 || Target Tables: NA
8932 ||
8933 || KNOWN ISSUES
8934 ||
8935 || NOTES
8936 ||
8937 || MODIFICATION HISTORY
8938 || Date Author Description of Changes
8939 || 3/8/2004 4:28PM raverma Created
8940 ||
8941 *=======================================================================*/
8942 function getActiveRate(p_loan_id in number) return number
8943 is
8944 l_rate_details LNS_FINANCIALS.INTEREST_RATE_REC;
8945 l_last_installment number;
8946 l_active_rate number;
8947 l_rate_tbl LNS_FINANCIALS.RATE_SCHEDULE_TBL;
8948
8949
8950 begin
8951
8952 l_active_rate := -1;
8953 l_rate_tbl := getRateSchedule(p_loan_id, 'TERM');
8954
8955 if l_rate_tbl.count = 1 then
8956 l_active_rate := l_rate_tbl(1).annual_rate;
8957
8958 else
8959
8960 begin
8961
8962 l_last_installment := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id);
8963
8964 if l_last_installment = 0
8965 then l_last_installment := 1;
8966 end if;
8967
8968 exception when others then
8969 l_last_installment := 1;
8970 end;
8971 l_rate_details := getRateDetails(p_installment => l_last_installment
8972 ,p_rate_tbl => l_rate_tbl);
8973 l_active_rate := l_rate_Details.annual_rate;
8974
8975 end if;
8976
8977 return l_active_rate;
8978
8979 end getActiveRate;
8980
8981
8982 /*=========================================================================
8983 || PUBLIC PROCEDURE calculateInterestRate
8984 ||
8985 || DESCRIPTION
8986 ||
8987 || Overview: function to calcualte interest for a variableRate Loan
8988 ||
8989 || Parameter:
8990 || p_initial_rate in number => initial interest rate for loan
8991 || p_last_period_rate in number => last periodic rate
8992 || p_max_period_adjustment in number => maximum rate diff between adjustments
8993 || p_max_lifetime_adjustment in number => maximum lifetime rate difference
8994 || p_ceiling in number => maximum rate
8995 || p_floor in number => minimum rate
8996 || p_rate_to_compare in number => index rate plus spread
8997 ||
8998 || Return value: variable interest rate
8999 ||
9000 || Source Tables: NA
9001 ||
9002 || Target Tables: NA
9003 ||
9004 || KNOWN ISSUES
9005 ||
9006 || NOTES
9007 ||
9008 || Creation date: 12/08/2003 6:31PM
9009 ||
9010 || Major Modifications: when who what
9011 || 11/20/2005 raverma created
9012 *=======================================================================*/
9013 function calculateInterestRate(p_initial_rate in number
9014 ,p_rate_to_compare in number
9015 ,p_last_period_rate in number
9016 ,p_max_first_adjustment in number
9017 ,p_max_period_adjustment in number
9018 ,p_max_lifetime_adjustment in number
9019 ,p_ceiling_rate in number
9020 ,p_floor_rate in number
9021 ,p_installment_number in number) return number
9022
9023 is
9024 l_new_rate number;
9025 l_rate_diff number;
9026 l_life_rate_diff number;
9027 l_sign1 number;
9028 l_sign2 number;
9029 l_api_name varchar2(30);
9030
9031 begin
9032
9033 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9034 -- need to check for NULLs
9035 l_rate_diff := ABS(p_rate_to_compare - p_last_period_rate);
9036 l_life_rate_diff := ABS(p_rate_to_compare - p_initial_rate);
9037 l_sign1 := 1;
9038 l_sign2 := 1;
9039 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_diff ' || l_rate_diff);
9040 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_life_rate_diff ' || l_life_rate_diff);
9041
9042 -- rate differentials go both ways
9043 if p_rate_to_compare < p_last_period_rate then
9044 l_sign1 := -1;
9045 end if;
9046
9047 -- rate differentials go both ways
9048 if p_rate_to_compare < p_initial_rate then
9049 l_sign2 := -1;
9050 end if;
9051
9052 l_new_rate := p_rate_to_compare;
9053
9054 if l_new_rate > p_ceiling_rate and p_ceiling_rate is not null then
9055 l_new_rate := p_ceiling_rate;
9056 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was above CEILING of: ' || p_ceiling_rate);
9057 end if;
9058
9059 l_life_rate_diff := ABS(l_new_rate - p_initial_rate);
9060 if l_life_rate_diff > p_max_lifetime_adjustment and p_max_lifetime_adjustment is not null then
9061 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was above life differential of: ' || l_life_rate_diff );
9062 l_new_rate := p_last_period_rate + (p_max_lifetime_adjustment * l_sign2);
9063 end if;
9064 l_rate_diff := ABS(l_new_rate - p_last_period_rate);
9065
9066 if l_rate_diff > p_max_period_adjustment and p_max_period_adjustment is not null then
9067 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New rate was above adjustment differential of: ' || l_rate_diff);
9068 l_new_rate := p_last_period_rate + (p_max_period_adjustment * l_sign1);
9069 end if;
9070
9071 if l_new_rate < p_floor_rate and p_floor_rate is not null then
9072 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was below floor of ' || p_floor_rate );
9073 l_new_rate := p_floor_rate;
9074 end if;
9075 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_rate ' || l_new_rate);
9076
9077 return l_new_rate;
9078
9079 end calculateInterestRate;
9080
9081 /*=========================================================================
9082 || PUBLIC PROCEDURE getRemainingBalance
9083 ||
9084 || DESCRIPTION
9085 ||
9086 || Overview: function to get the remaining balance on the loan
9087 ||
9088 || Parameter: loan_id
9089 ||
9090 || Return value: Amount Or BALANCE on loan
9091 ||
9092 || Source Tables: LNS_TERMS, LNS_LOAN_HEADER, LNS_AMORTIZATION_SCHEDS
9093 ||
9094 || Target Tables: NA
9095 ||
9096 || KNOWN ISSUES
9097 ||
9098 || NOTES
9099 ||
9100 || Creation date: 12/08/2003 6:31PM
9101 ||
9102 || Major Modifications: when who what
9103 || 12/26/2003 raverma base the remaining balance from
9104 || loan status
9105 || 2/03/2004 balance if ACTIVE is based on PRINCIPAL_BALANCE
9106 || 7/29/2004 balance if DEFAULT or DELINQUENT = ACTIVE
9107 *=======================================================================*/
9108 function getRemainingBalance(p_loan_id in number) return number
9109 is
9110 l_balance number;
9111 l_initial_amount number;
9112 l_billed_amount number;
9113 l_loan_status varchar2(30);
9114 l_column varchar2(30);
9115 l_table varchar2(30);
9116 l_api_name varchar2(30);
9117
9118 begin
9119 l_balance := -1;
9120 l_initial_amount := 0;
9121 l_billed_amount := 0;
9122 l_api_name := 'getRemainingBalance';
9123 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9124
9125 Execute Immediate
9126 ' Select Loan_Status ' ||
9127 ' From lns_loan_headers_all ' ||
9128 ' where loan_id = :p_loan_id'
9129 into l_loan_status
9130 using p_loan_id;
9131
9132 if l_loan_status = 'APPROVED' then
9133 l_column := 'REQUESTED_AMOUNT';
9134 l_table := 'LNS_LOAN_HEADERS_ALL';
9135
9136 elsif l_loan_Status = 'ACTIVE' then
9137 l_column := 'TOTAL_PRINCIPAL_BALANCE';
9138 l_table := 'LNS_PAY_SUM_V';
9139
9140 elsif l_loan_Status = 'DELINQUENT' then
9141 l_column := 'TOTAL_PRINCIPAL_BALANCE';
9142 l_table := 'LNS_PAY_SUM_V';
9143
9144 elsif l_loan_Status = 'DEFAULT' then
9145 l_column := 'TOTAL_PRINCIPAL_BALANCE';
9146 l_table := 'LNS_PAY_SUM_V';
9147
9148 elsif l_loan_Status = 'PAIDOFF' then
9149 l_column := 'TOTAL_PRINCIPAL_BALANCE';
9150 l_table := 'LNS_PAY_SUM_V';
9151 -- l_column := 'REQUESTED_AMOUNT';
9152 -- l_table := 'LNS_LOAN_HEADERS_ALL';
9153
9154 elsif l_loan_status = 'PENDING' then
9155 l_column := 'REQUESTED_AMOUNT';
9156 l_table := 'LNS_LOAN_HEADERS_ALL';
9157
9158 elsif l_loan_status = 'INCOMPLETE' then
9159 l_column := 'REQUESTED_AMOUNT';
9160 l_table := 'LNS_LOAN_HEADERS_ALL';
9161
9162 elsif l_loan_status = 'IN_FUNDING' then
9163 l_column := 'REQUESTED_AMOUNT';
9164 l_table := 'LNS_LOAN_HEADERS_ALL';
9165
9166 elsif l_loan_status = 'FUNDING_ERROR' then
9167 l_column := 'REQUESTED_AMOUNT';
9168 l_table := 'LNS_LOAN_HEADERS_ALL';
9169
9170 else -- catch any new statuses
9171 l_column := 'REQUESTED_AMOUNT';
9172 l_table := 'LNS_LOAN_HEADERS_ALL';
9173
9174 end if;
9175
9176 Execute Immediate
9177 ' Select ' || l_column ||
9178 ' From ' || l_table ||
9179 ' where loan_id = :p_loan_id'
9180 into l_balance
9181 using p_loan_id;
9182
9183 -- logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': remainingBalance: ' || l_balance);
9184 -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9185
9186 return l_balance;
9187 /*
9188 Exception
9189 When Others then
9190 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Error: ' || sqlerrm);
9191 --seed this message
9192 FND_MESSAGE.Set_Name('LNS', 'LNS_UNABLE_TO_COMPUTE_BALANCE');
9193 FND_MSG_PUB.Add;
9194 RAISE FND_API.G_EXC_ERROR;
9195 */
9196 end getRemainingBalance;
9197
9198 /*========================================================================
9199 | PUBLIC FUNCTION weightBalance
9200 |
9201 | DESCRIPTION
9202 | takes a table of loan_activities, sorts them and weights the balance
9203 || by the from/to dates
9204 |
9205 | PSEUDO CODE/LOGIC
9206 || - calculate the wtd average daily balance for the loan (construction)
9207 || - day counting method is accoring to the terms of the loan
9208 ||
9209 || within the given from/to date range
9210 || ADB =[(# of days X Balance 1 ) +
9211 || (# of days X Balance 2 ) +
9212 || (# of days X Balance 3 ) +
9213 || .
9214 || .
9215 || .
9216 || (# of days X Balance N ) ]
9217 || /
9218 || Total Number of Days (from <-> to dates)
9219 |
9220 | PARAMETERS
9221 |
9222 | Return value:
9223 |
9224 | Source Tables: NA
9225 |
9226 | Target Tables: NA
9227 |
9228 | KNOWN ISSUES
9229 |
9230 | MODIFICATION HISTORY
9231 | Date Author Description of Changes
9232 | 07/19/05 4:13:PM raverma Created
9233 *=======================================================================*/
9234 function weightBalance(p_loan_activities IN LNS_FINANCIALS.LOAN_ACTIVITY_TBL
9235 ,p_from_date in date
9236 ,p_to_date in date
9237 ,p_day_count_method in varchar2) return number
9238 is
9239 l_balance_days number;
9240 l_total_days number;
9241 l_num_days number;
9242 l_weighted_balance number;
9243 k number;
9244 m number;
9245 l_api_name varchar2(25);
9246 l_begin_balance number;
9247 l_end_balance number;
9248 l_total_activity_amount number;
9249 l_loan_activities LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
9250
9251
9252 begin
9253 l_api_name := 'weightBalance';
9254 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9255 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - number of activities: ' || p_loan_activities.count);
9256 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
9257 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
9258 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_day_count_method: ' || p_day_count_method);
9259
9260 -- sort activities by activity date
9261
9262 -- # of days @ balance 1
9263 -- # of days @ balance 2
9264 -- # of days @ balance N
9265 -- find balance on from date
9266 -- find balance on to date
9267 -- find number of balance changes between the 2
9268 -- loop thru each balance change and calc # of days at balance
9269 -- now calculate ADB using dates from and to
9270 l_balance_days := 0;
9271 l_total_days := 0;
9272 l_num_days := 0;
9273 l_weighted_balance := 0;
9274 l_total_activity_amount := 0;
9275 l_loan_activities := p_loan_activities;
9276 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - sorting the activities');
9277 sortRows(l_loan_activities);
9278 /*
9279 for j in 1..p_loan_activities.count
9280 loop
9281 dbms_output.put_line(p_loan_activities(j).activity_date );
9282 dbms_output.put_line(p_loan_activities(j).ending_balance );
9283 end loop;
9284 */
9285 m := l_loan_activities.count;
9286 if m = 1 then
9287 l_weighted_balance := l_loan_activities(1).ending_balance;
9288 else
9289
9290 for p in 1..m loop
9291 --dbms_output.put_line('p is ' || p);
9292 if l_loan_activities(p).activity_amount > 0 then
9293 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p ' || p);
9294 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity date: ' || l_loan_activities(p).activity_date);
9295 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity amount: ' || l_loan_activities(p).activity_amount);
9296 if p = 1 then
9297 -- this is for the previous balance
9298 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
9299 ,p_end_date => p_to_date
9300 ,p_day_count_method => p_day_count_method);
9301 elsif p < m then
9302 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
9303 ,p_end_date => l_loan_activities(p+1).activity_date
9304 ,p_day_count_method => p_day_count_method);
9305
9306 elsif p = m then
9307 --dbms_output.put_line('2');
9308 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
9309 ,p_end_date => p_to_date
9310 ,p_day_count_method => p_day_count_method);
9311
9312 end if;
9313 if l_num_days > 0 then
9314 l_total_activity_amount := l_total_activity_amount + l_loan_activities(p).activity_amount;
9315 end if;
9316 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - total activity amount: ' || l_total_activity_amount);
9317 --dbms_output.put_line('day count is ' || l_num_days);
9318 --dbms_output.put_line('balance is ' || p_loan_activities(p).ending_balance);
9319 l_balance_days := l_balance_days + (l_num_days * l_loan_activities(p).activity_amount);
9320 end if;
9321
9322 end loop;
9323 -- this is the total days (denominator)
9324 l_total_Days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
9325 ,p_end_date => p_to_date
9326 ,p_day_count_method => p_day_count_method);
9327 -- dbms_output.put_line('total days is ' || l_total_Days );
9328 l_weighted_balance := l_balance_days / l_total_days;
9329
9330 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
9331 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_total_days: ' || l_total_days);
9332 --dbms_output.put_line('adb is ' || l_weighted_balance);
9333 end if;
9334
9335 return l_weighted_balance;
9336
9337 end weightBalance;
9338
9339 /*=========================================================================
9340 || PUBLIC FUNCTION getWeightedBalance
9341 ||
9342 || DESCRIPTION
9343 ||
9344 || PARAMETERS
9345 || p_loan_id loan_id
9346 || p_term_id term_id (for future use)
9347 || p_from_date date from which to calculate ADB
9348 || p_to_date date to which to calculate ADB
9349 || p_calc_method 'ACTUAL' or 'TARGET'
9350 ||
9351 || Return value: wtd average daily balance for the loan
9352 ||
9353 || Source Tables: LNS_DISB_HEADERS, LNS_DISB_LINES
9354 ||
9355 || Target Tables: NA
9356 ||
9357 || KNOWN ISSUES
9358 ||
9359 || NOTES
9360 ||
9361 || MODIFICATION HISTORY
9362 || Date Author Description of Changes
9363 || 07/17/05 1:51:PM raverma Created
9364 *=======================================================================*/
9365 function getWeightedBalance(p_loan_id number
9366 ,p_from_date date
9367 ,p_to_date date
9368 ,p_calc_method varchar2
9369 ,p_phase varchar2
9370 ,p_day_count_method varchar2) return number
9371
9372 is
9373 l_api_name varchar2(25);
9374 l_wtd_balance number;
9375 l_loan_activities LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
9376 i number;
9377 l_activity_date date;
9378 l_activity_amount number;
9379 l_loan_start_date date;
9380
9381 cursor c_actual_balance(p_loan_id number, p_from_date date, p_to_date date) IS
9382 select p_from_date - 1
9383 ,nvl(sum(line_amount), 0)
9384 from lns_disb_lines lines
9385 where disb_header_id in (select disb_header_id from lns_disb_headers where loan_id = p_loan_id)
9386 and trunc(disbursement_date) < p_from_date
9387 UNION
9388 select trunc(inv.creation_date)
9389 ,nvl(sum(amount), 0)
9390 from AP_INVOICE_PAYMENTS_ALL inv
9391 ,lns_disb_headers head
9392 ,lns_disb_lines line
9393 where head.loan_id = p_loan_id
9394 and line.disb_header_id = head.disb_header_id
9395 and line.invoice_id is not null
9396 and line.invoice_id = inv.invoice_id
9397 and line.status IN ('PARTIALLY_FUNDED', 'FULLY_FUNDED')
9398 and trunc(inv.creation_date) >= p_from_date
9399 and trunc(inv.creation_date) < p_to_date
9400 group by trunc(inv.creation_date);
9401 /* raverma 12-13-05 removed
9402 select disbursement_date
9403 ,sum(line_amount)
9404 from lns_disb_lines
9405 where disb_header_id in (select disb_header_id from lns_disb_headers where loan_id = p_loan_id)
9406 and disbursement_date is not null
9407 and trunc(disbursement_date) >= p_from_date
9408 and trunc(disbursement_date) < p_to_date
9409 group by disbursement_date;
9410 */
9411 cursor c_theoretical_balance(p_loan_id number, p_from_date date, p_to_date date) IS
9412 select p_from_date - 1
9413 ,nvl(sum(header_amount),0)
9414 from lns_disb_headers
9415 where loan_id = p_loan_id
9416 and trunc(payment_request_date) < p_from_date
9417 UNION
9418 select payment_request_date
9419 ,nvl(sum(header_amount),0)
9420 from lns_disb_headers
9421 where loan_id = p_loan_id
9422 and trunc(payment_request_date) >= p_from_date
9423 and trunc(payment_request_date) < p_to_date
9424 group by payment_request_date;
9425
9426 cursor c_loan_boundaries(p_loan_id number)
9427 is
9428 select open_loan_start_date
9429 from lns_loan_headers
9430 where loan_id = p_loan_id;
9431
9432 begin
9433
9434 l_api_name := 'getWeightedBalance';
9435 i := 0;
9436 l_wtd_balance := 0;
9437 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Begin');
9438 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
9439 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
9440 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id: ' || p_loan_id);
9441 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_calc_method: ' || p_calc_method);
9442
9443 -- validate the from and to Dates
9444 if p_from_date > p_to_date then
9445 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_ACTIVE_DATE');
9446 FND_MSG_PUB.Add;
9447 RAISE FND_API.G_EXC_ERROR;
9448 end if;
9449 /*
9450 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
9451 ,p_based_on_terms => 'CURRENT'
9452 ,p_phase => 'OPEN');
9453
9454 -- validate if dates are within the boundaries of loan_start and maturity_dates
9455 if p_to_date > l_loan_details.maturity_date then
9456 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR1');
9457 FND_MSG_PUB.Add;
9458 RAISE FND_API.G_EXC_ERROR;
9459 end if;
9460
9461 if p_from_date < l_loan_details.loan_start_date then
9462 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR2');
9463 FND_MSG_PUB.Add;
9464 RAISE FND_API.G_EXC_ERROR;
9465 end if;
9466 */
9467 l_loan_activities(1).ending_balance := 0;
9468
9469 if p_calc_method = 'ACTUAL' then
9470
9471 -- get all the balance activities on the loan
9472 OPEN c_actual_balance(p_loan_id, p_from_date, p_to_date);
9473 LOOP
9474 i := i + 1;
9475 FETCH c_actual_balance INTO
9476 l_activity_date
9477 ,l_activity_amount;
9478 EXIT WHEN c_actual_balance%NOTFOUND;
9479
9480 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
9481 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date: ' || l_activity_date);
9482 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount: ' || l_activity_amount);
9483 l_loan_activities(i).activity_date := l_activity_date;
9484 l_loan_activities(i).activity_amount := l_activity_amount;
9485 if i = 1 then
9486 l_loan_activities(i).ending_balance := l_activity_amount;
9487 else
9488 l_loan_activities(i).ending_balance := l_activity_amount + l_loan_activities(i-1).ending_balance;
9489 end if;
9490 l_activity_date := null;
9491 l_activity_amount := null;
9492 END LOOP;
9493 close c_actual_balance;
9494
9495 elsif p_calc_method = 'TARGET' then
9496
9497 OPEN c_theoretical_balance(p_loan_id, p_from_date, p_to_date);
9498 LOOP
9499 i := i + 1;
9500 FETCH c_theoretical_balance INTO
9501 l_activity_date
9502 ,l_activity_amount;
9503 EXIT WHEN c_theoretical_balance%NOTFOUND;
9504
9505 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
9506 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date: ' || l_activity_date);
9507 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount: ' || l_activity_amount);
9508 l_loan_activities(i).activity_date := l_activity_date;
9509 l_loan_activities(i).activity_amount := l_activity_amount;
9510
9511 if i = 1 then
9512 l_loan_activities(i).ending_balance := l_activity_amount;
9513 else
9514 l_loan_activities(i).ending_balance := l_activity_amount + l_loan_activities(i-1).ending_balance;
9515 end if;
9516
9517 l_activity_date := null;
9518 l_activity_amount := null;
9519 END LOOP;
9520 close c_theoretical_balance;
9521
9522 end if;
9523
9524 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting wtd balance');
9525 l_wtd_balance := weightBalance(p_loan_activities => l_loan_activities
9526 ,p_from_date => p_from_date
9527 ,p_to_date => p_to_date
9528 ,p_day_count_method => p_day_count_method);
9529 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_wtd_balance' || l_wtd_balance);
9530
9531 return l_wtd_balance;
9532
9533 end getWeightedBalance;
9534
9535
9536
9537 /*=========================================================================
9538 || PUBLIC FUNCTION getAverageDailyBalance
9539 ||
9540 || DESCRIPTION
9541 || - calculate average daily balance for the loan (term)
9542 || - day counting method is accoring to the terms of the loan
9543 ||
9544 || only one method supported right now:
9545 || within the given from/to date range
9546 || ADB =[(# of days X Balance 1 ) +
9547 || (# of days X Balance 2 ) +
9548 || (# of days X Balance 3 ) +
9549 || .
9550 || .
9551 || .
9552 || (# of days X Balance N ) ]
9553 || /
9554 || Total Number of Days (from <-> to dates)
9555 ||
9556 || PARAMETERS
9557 || p_loan_id loan_id
9558 || p_term_id term_id (for future use)
9559 || p_from_date date from which to calculate ADB
9560 || p_to_date date to which to calculate ADB
9561 || p_calc_method for future use
9562 ||
9563 || Return value: average daily balance for the loan
9564 ||
9565 || Source Tables: LNS_RECEIVABLE_ACTIVITIES_V, LNS_LOAN_HEADERS
9566 ||
9567 || Target Tables: NA
9568 ||
9569 || KNOWN ISSUES
9570 ||
9571 || NOTES
9572 ||
9573 ||
9574 || MODIFICATION HISTORY
9575 || Date Author Description of Changes
9576 || 05/31/06 1:51:PM karamach Added cursor c_loan_phase and passed current_phase to getLoanDetails api to fix bug5237022
9577 || 09/30/04 1:51:PM raverma Created
9578 ||
9579 *=======================================================================*/
9580 function getAverageDailyBalance(p_loan_id number
9581 ,p_term_id number
9582 ,p_from_date date
9583 ,p_to_date date
9584 ,p_calc_method number) return number
9585 is
9586
9587 -- this cursor will get balance by activity date
9588 -- the markers ensure that funding and maturity are the 1st and last rows
9589 cursor c_balance_history(p_loan_id number) is
9590 select trunc(loan_start_date) activity_date,
9591 funded_amount activity_amount,
9592 funded_amount ending_balance
9593 from lns_loan_headers
9594 where loan_id = p_loan_id
9595 union all
9596 select trunc(activity_date) activity_date,
9597 sum(activity_amount) activity_amount,
9598 LNS_BILLING_UTIL_PUB.LOAN_BALANCE_BY_DATE(P_LOAN_ID, activity_date) --min(balance_by_activity_date) ending_balance
9599 from LNS_REC_ACT_CASH_CM_V rav
9600 where rav.loan_id = p_loan_id and
9601 line_type_code = 'PRIN' and
9602 (activity_code in ('PMT', 'ADJ') or (activity_code = 'CM' and activity_number like 'NET%'))
9603 group by activity_date
9604 union all
9605 select trunc(loan_maturity_date) activity_date
9606 ,null
9607 ,lns_financials.getRemainingBalance(p_loan_id)
9608 from lns_loan_headers
9609 where loan_id = p_loan_id
9610 order by activity_date asc;
9611
9612 -- this cursor will get the current phase of the loan
9613 cursor c_loan_phase(p_loan_id number) is
9614 select nvl(current_phase,'TERM') current_phase
9615 from lns_loan_headers
9616 where loan_id = p_loan_id;
9617
9618 l_activity_date date;
9619 l_activity_amount number;
9620 l_balance_days number;
9621 l_num_days number;
9622 l_total_days number;
9623 l_loan_details LNS_FINANCIALS.LOAN_DETAILS_REC;
9624 l_loan_activities LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
9625 l_average_daily_balance number;
9626 k number;
9627 m number;
9628 l_num_balance_changes number;
9629 l_api_name varchar2(25);
9630 l_begin_balance number;
9631 l_end_balance number;
9632 i number;
9633 -- l_marker number;
9634 l_loan_phase varchar2(30);
9635
9636 begin
9637
9638 --LNS_BILLING_UTIL_PUB.LOAN_BALANCE_BY_DATE(P_LOAN_ID IN NUMBER, P_DATE IN DATE) function
9639 l_api_name := 'getAverageDailyBalance';
9640 l_balance_days := 0;
9641 l_num_days := 0;
9642 l_total_days := 0;
9643 l_average_daily_balance:= 0;
9644 i := 0;
9645 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Begin');
9646 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
9647 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
9648
9649 -- validate the from and to Dates
9650 if p_from_date > p_to_date then
9651 FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_ACTIVE_DATE');
9652 FND_MSG_PUB.Add;
9653 RAISE FND_API.G_EXC_ERROR;
9654 end if;
9655
9656 OPEN c_loan_phase(p_loan_id);
9657 FETCH c_loan_phase INTO l_loan_phase;
9658 CLOSE c_loan_phase;
9659
9660 l_loan_details := lns_financials.getLoanDetails(p_loan_id => p_loan_id
9661 ,p_based_on_terms => 'CURRENT'
9662 --karamach bug5237022
9663 --,p_phase => 'TERM');
9664 ,p_phase => l_loan_phase);
9665
9666 -- validate if dates are within the boundaries of loan_start and maturity_dates
9667 if p_to_date > l_loan_details.maturity_date then
9668 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR1');
9669 FND_MSG_PUB.Add;
9670 RAISE FND_API.G_EXC_ERROR;
9671 end if;
9672
9673 if p_from_date < l_loan_details.loan_start_date then
9674 FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR2');
9675 FND_MSG_PUB.Add;
9676 RAISE FND_API.G_EXC_ERROR;
9677 end if;
9678
9679 -- get all the balance activities on the loan
9680 OPEN c_balance_history(p_loan_id);
9681 LOOP
9682 i := i + 1;
9683 FETCH c_balance_history INTO
9684 l_activity_date
9685 ,l_activity_amount
9686 ,l_end_balance;
9687 -- ,l_marker;
9688 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
9689 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date: ' || l_activity_date);
9690 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount: ' || l_activity_amount);
9691 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_end_balance: ' || l_end_balance);
9692 EXIT WHEN c_balance_history%NOTFOUND;
9693
9694 l_loan_activities(i).activity_date := l_activity_date;
9695 l_loan_activities(i).activity_amount := l_activity_amount;
9696 l_loan_activities(i).ending_balance := l_end_balance;
9697
9698 END LOOP;
9699 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - number of activities: ' || l_loan_activities.count);
9700
9701 -- # of balance changes = l_loan_activities.count - 2
9702 -- # of days @ balance 1
9703 -- # of days @ balance 2
9704 -- # of days @ balance N
9705 -- find balance on from date
9706 -- find balance on to date
9707 -- find number of balance changes between the 2
9708 -- loop thru each balance change and calc # of days at balance
9709 -- now calculate ADB using dates from and to
9710 k := 1;
9711 WHILE p_from_date >= l_loan_activities(k).activity_date loop
9712 l_begin_balance := l_loan_activities(k).ending_balance;
9713 k := k + 1;
9714 end loop;
9715 k := k - 1;
9716
9717 m := 1;
9718 WHILE p_to_date >= l_loan_activities(m).activity_date loop
9719 l_end_balance := l_loan_activities(m).ending_balance;
9720 m := m + 1;
9721 end loop;
9722 m := m - 1;
9723
9724 --dbms_output.put_line('output k' || k);
9725 --dbms_output.put_line('output m' || m);
9726
9727 if k = m then
9728 l_average_daily_balance := l_loan_activities(k).ending_balance;
9729 else
9730 for p in k..m loop
9731 --dbms_output.put_line('p is ' || p);
9732 if p = k then -- first record
9733 --dbms_output.put_line('1');
9734 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
9735 ,p_end_date => l_loan_activities(p + 1).activity_date
9736 ,p_day_count_method => l_loan_details.day_count_method);
9737
9738 elsif p = m then
9739 -- dbms_output.put_line('3');
9740 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
9741 ,p_end_date => p_to_date
9742 ,p_day_count_method => l_loan_details.day_count_method);
9743
9744 else
9745 -- dbms_output.put_line('2');
9746 l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date => l_loan_activities(p).activity_date
9747 ,p_end_date => l_loan_activities(p + 1).activity_date
9748 ,p_day_count_method => l_loan_details.day_count_method);
9749
9750 end if;
9751 --dbms_output.put_line('day count is ' || l_num_days);
9752 --dbms_output.put_line('balance is ' || l_loan_activities(p).ending_balance);
9753 l_balance_days := l_balance_days + l_num_days * l_loan_activities(p).ending_balance;
9754
9755 end loop;
9756 -- this is the total days (denominator)
9757 l_total_Days := LNS_FIN_UTILS.getDayCount(p_start_date => p_from_date
9758 ,p_end_date => p_to_date
9759 ,p_day_count_method => l_loan_details.day_count_method);
9760
9761 --dbms_output.put_line('total days is ' || l_total_Days );
9762 l_average_daily_balance := l_balance_days / l_total_days;
9763 end if;
9764
9765 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
9766 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_total_balance: ' || l_total_days);
9767 --dbms_output.put_line('adb is ' || l_average_daily_balance);
9768 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_end_balance: ' || l_end_balance);
9769 return round(l_average_daily_balance, l_loan_details.currency_precision);
9770
9771 EXCEPTION
9772
9773 When others Then
9774 return -1;
9775 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - ' || sqlerrm);
9776
9777
9778 end getAverageDailyBalance;
9779
9780
9781 function getAPR(p_loan_id in number
9782 ,p_term_id in number
9783 ,p_actual_flag in varchar2) return number
9784 is
9785
9786 begin
9787 null;
9788 /*
9789 public static double RATE(double d, double d1, double d2)
9790 {
9791 double d3 = 1.0D;
9792 double d4 = 0.5D;
9793 double d5 = d1;
9794 if(d * d1 <= d2)
9795 {
9796 return 0.0D;
9797 }
9798 for(int i = 1; i < 50; i++)
9799 {
9800 double d6 = PMT(d3, d, d2);
9801 if(d6 == d1)
9802 {
9803 return d3;
9804 }
9805 if(d6 < d1)
9806 {
9807 d3 += d4;
9808 } else
9809 {
9810 d3 -= d4;
9811 }
9812 d4 /= 2D;
9813 }
9814
9815 return d3;
9816 }
9817 */
9818 end;
9819
9820
9821 -- This function calculates normal interest
9822 function CALC_NORM_INTEREST(p_loan_id in number,
9823 p_calc_method in varchar2,
9824 p_period_start_date in date,
9825 p_period_end_date in date,
9826 p_interest_rate in number,
9827 p_day_count_method in varchar2,
9828 p_payment_freq in varchar2,
9829 p_compound_freq in varchar2) return number
9830 is
9831 l_api_name varchar2(25);
9832 l_activity_date date;
9833 l_activity_code varchar2(30);
9834 l_activity_amount number;
9835 l_theory_balance number;
9836 l_actual_balance number;
9837 l_days_late number;
9838 l_display_order number;
9839 l_rate number;
9840 l_day_count number;
9841 i number;
9842 l_norm_prev_amount number;
9843 l_norm_interest number;
9844 l_norm_prev_act_date date;
9845 l_cum_norm_interest number;
9846 l_periodic_rate number;
9847
9848 cursor c_trx_activities(p_loan_id number, p_start_date date, p_end_date date) is
9849 select
9850 trunc(ACTIVITY_DATE),
9851 ACTIVITY_CODE,
9852 ACTIVITY_AMOUNT,
9853 THEORETICAL_BALANCE,
9854 ACTUAL_BALANCE,
9855 DAYS_LATE,
9856 display_order
9857 from LNS_PRIN_TRX_ACTIVITIES_V
9858 where loan_id = p_loan_id and
9859 trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
9860 trunc(ACTIVITY_DATE) < trunc(p_end_date) and
9861 ACTIVITY_CODE in ('START', 'DUE')
9862 order by activity_date, display_order, LOAN_AMORTIZATION_ID;
9863
9864 begin
9865
9866 l_api_name := 'CALC_NORM_INTEREST';
9867 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
9868 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9869 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
9870 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
9871 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
9872 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
9873 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
9874 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
9875 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
9876 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
9877 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
9878
9879 -- calculating normal and additional interest
9880 i := 1;
9881 l_norm_interest := 0;
9882 l_cum_norm_interest := 0;
9883 l_norm_prev_amount := 0;
9884 l_norm_prev_act_date := p_period_start_date;
9885
9886 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
9887
9888 OPEN c_trx_activities(p_loan_id, p_period_start_date, p_period_end_date);
9889 LOOP
9890
9891 FETCH c_trx_activities INTO
9892 l_activity_date
9893 ,l_activity_code
9894 ,l_activity_amount
9895 ,l_theory_balance
9896 ,l_actual_balance
9897 ,l_days_late
9898 ,l_display_order;
9899
9900 EXIT WHEN c_trx_activities%NOTFOUND;
9901
9902 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
9903 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Theory_Bal Actual_Bal Days_Late');
9904 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);
9905
9906 -- normal interest
9907 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating normal interest...');
9908 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_norm_prev_act_date || ' - ' || l_activity_date);
9909 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_norm_prev_amount);
9910 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
9911
9912 if (p_calc_method = 'SIMPLE') then
9913
9914 -- recalculate periodic rate for each period if day counting methodolgy varies
9915 l_periodic_rate := getPeriodicRate(
9916 p_period_start_date => l_norm_prev_act_date
9917 ,p_period_end_date => l_activity_date
9918 ,p_annualized_rate => p_interest_rate
9919 ,p_days_count_method => p_day_count_method);
9920
9921 elsif (p_calc_method = 'COMPOUND') then
9922
9923 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
9924 ,p_payment_freq => p_payment_freq
9925 ,p_annualized_rate => p_interest_rate
9926 ,p_period_start_date => l_norm_prev_act_date
9927 ,p_period_end_date => l_activity_date
9928 ,p_days_count_method => p_day_count_method);
9929
9930 end if;
9931 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
9932
9933 l_norm_interest := lns_financials.calculateInterest(p_amount => l_norm_prev_amount
9934 ,p_periodic_rate => l_periodic_rate
9935 ,p_compounding_period => null);
9936 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'normal interest = ' || l_norm_interest);
9937
9938 l_cum_norm_interest := l_cum_norm_interest + l_norm_interest;
9939 l_norm_prev_amount := l_theory_balance;
9940 l_norm_prev_act_date := l_activity_date;
9941 i := i + 1;
9942 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative normal interest = ' || l_cum_norm_interest);
9943
9944 END LOOP;
9945 close c_trx_activities;
9946
9947 -- manually adding last record for p_period_end_date date
9948 l_activity_date := p_period_end_date;
9949 l_activity_code := 'DUE';
9950 l_activity_amount := 0;
9951 l_days_late := 0;
9952
9953 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
9954 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Theory_Bal Actual_Bal Days_Late');
9955 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);
9956
9957 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating normal interest...');
9958 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_norm_prev_act_date || ' - *' || l_activity_date);
9959 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_norm_prev_amount);
9960 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
9961
9962 -- normal interest
9963 if (p_calc_method = 'SIMPLE') then
9964
9965 -- recalculate periodic rate for each period if day counting methodolgy varies
9966 l_periodic_rate := getPeriodicRate(
9967 p_period_start_date => l_norm_prev_act_date
9968 ,p_period_end_date => l_activity_date
9969 ,p_annualized_rate => p_interest_rate
9970 ,p_days_count_method => p_day_count_method);
9971
9972 elsif (p_calc_method = 'COMPOUND') then
9973
9974 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
9975 ,p_payment_freq => p_payment_freq
9976 ,p_annualized_rate => p_interest_rate
9977 ,p_period_start_date => l_norm_prev_act_date
9978 ,p_period_end_date => l_activity_date
9979 ,p_days_count_method => p_day_count_method);
9980
9981 end if;
9982 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
9983
9984 l_norm_interest := lns_financials.calculateInterest(p_amount => l_norm_prev_amount
9985 ,p_periodic_rate => l_periodic_rate
9986 ,p_compounding_period => null);
9987 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'normal interest = ' || l_norm_interest);
9988 l_cum_norm_interest := l_cum_norm_interest + l_norm_interest;
9989
9990 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Normal Interest = ' || l_cum_norm_interest);
9991 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9992 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
9993
9994 return l_cum_norm_interest;
9995
9996 end;
9997
9998
9999 -- This procedure calculates additional and penal interest
10000 procedure CALC_ADD_INTEREST(p_loan_id in number,
10001 p_calc_method in varchar2,
10002 p_period_start_date in date,
10003 p_period_end_date in date,
10004 p_interest_rate in number,
10005 p_day_count_method in varchar2,
10006 p_payment_freq in varchar2,
10007 p_compound_freq in varchar2,
10008 p_penal_int_rate in number,
10009 p_prev_grace_end_date in date,
10010 p_grace_start_date in date,
10011 p_grace_end_date in date,
10012 p_target in varchar2,
10013 x_add_interest out NOCOPY number,
10014 x_penal_interest out NOCOPY number)
10015 is
10016 l_api_name varchar2(25);
10017 l_activity_date date;
10018 l_activity_code varchar2(30);
10019 l_activity_amount number;
10020 l_theory_balance number;
10021 l_actual_balance number;
10022 l_days_late number;
10023 l_display_order number;
10024 l_rate number;
10025 l_day_count number;
10026 i number;
10027 l_add_prev_amount number;
10028 l_add_interest number;
10029 l_add_prev_act_date date;
10030 l_cum_add_interest number;
10031 l_periodic_rate number;
10032 l_penal_interest number;
10033 l_cum_penal_interest number;
10034 l_penal_period_rate number;
10035 l_interest_rate number;
10036 l_first_act_after_grace boolean;
10037 l_first_act_after_prev_grace boolean;
10038
10039 cursor c_trx_prin_activities(p_loan_id number, p_start_date date, p_end_date date) is
10040 select
10041 trunc(ACTIVITY_DATE),
10042 ACTIVITY_CODE,
10043 ACTIVITY_AMOUNT,
10044 INTEREST_RATE,
10045 THEORETICAL_BALANCE,
10046 ACTUAL_BALANCE,
10047 DAYS_LATE,
10048 display_order
10049 from LNS_PRIN_TRX_ACTIVITIES_V
10050 where loan_id = p_loan_id and
10051 trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
10052 trunc(ACTIVITY_DATE) < trunc(p_end_date)
10053 order by activity_date, display_order;
10054
10055 cursor c_trx_int_activities(p_loan_id number, p_start_date date, p_end_date date) is
10056 select
10057 trunc(ACTIVITY_DATE),
10058 ACTIVITY_CODE,
10059 ACTIVITY_AMOUNT,
10060 INTEREST_RATE,
10061 THEORETICAL_BALANCE,
10062 ACTUAL_BALANCE,
10063 DAYS_LATE,
10064 display_order
10065 from LNS_INT_TRX_ACTIVITIES_V
10066 where loan_id = p_loan_id and
10067 trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
10068 trunc(ACTIVITY_DATE) < trunc(p_end_date)
10069 order by activity_date, display_order;
10070
10071 begin
10072
10073 l_api_name := 'CALC_ADD_INTEREST';
10074 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
10075 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10076 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
10077 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
10078 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
10079 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
10080 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
10081 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
10082 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
10083 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
10084 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
10085 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': target: ' || p_target);
10086 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': penal_int_rate: ' || p_penal_int_rate);
10087 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prev_grace_end_date: ' || p_prev_grace_end_date);
10088 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': grace_start_date: ' || p_grace_start_date);
10089 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': grace_end_date: ' || p_grace_end_date);
10090
10091 if p_period_start_date > p_period_end_date then
10092 x_add_interest := 0;
10093 x_penal_interest := 0;
10094 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': x_add_interest: ' || x_add_interest);
10095 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': x_add_interest: ' || x_add_interest);
10096 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': exiting');
10097 return;
10098 end if;
10099
10100 -- calculating normal and additional interest
10101 i := 1;
10102 l_add_interest := 0;
10103 l_cum_add_interest := 0;
10104 l_add_prev_amount := 0;
10105 l_add_prev_act_date := p_period_start_date;
10106 l_penal_interest := 0;
10107 l_cum_penal_interest := 0;
10108 l_interest_rate := 0;
10109 l_first_act_after_grace := true;
10110 l_first_act_after_prev_grace := true;
10111
10112 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
10113
10114 if p_target = 'UNPAID_PRIN' then
10115 OPEN c_trx_prin_activities(p_loan_id, p_period_start_date, p_period_end_date);
10116 elsif p_target = 'UNPAID_INT' then
10117 OPEN c_trx_int_activities(p_loan_id, p_period_start_date, p_period_end_date);
10118 end if;
10119
10120 LOOP
10121
10122 if p_target = 'UNPAID_PRIN' then
10123 FETCH c_trx_prin_activities INTO
10124 l_activity_date
10125 ,l_activity_code
10126 ,l_activity_amount
10127 ,l_interest_rate
10128 ,l_theory_balance
10129 ,l_actual_balance
10130 ,l_days_late
10131 ,l_display_order;
10132
10133 EXIT WHEN c_trx_prin_activities%NOTFOUND;
10134 elsif p_target = 'UNPAID_INT' then
10135 FETCH c_trx_int_activities INTO
10136 l_activity_date
10137 ,l_activity_code
10138 ,l_activity_amount
10139 ,l_interest_rate
10140 ,l_theory_balance
10141 ,l_actual_balance
10142 ,l_days_late
10143 ,l_display_order;
10144
10145 EXIT WHEN c_trx_int_activities%NOTFOUND;
10146 end if;
10147
10148 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
10149 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Rate Theory_Bal Actual_Bal Days_Late');
10150 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);
10151
10152 -- additional interest
10153 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating additional interest...');
10154 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - ' || l_activity_date);
10155 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
10156 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || l_interest_rate);
10157
10158 if (p_calc_method = 'SIMPLE') then
10159
10160 -- recalculate periodic rate for each period if day counting methodolgy varies
10161 l_periodic_rate := getPeriodicRate(
10162 p_period_start_date => l_add_prev_act_date
10163 ,p_period_end_date => l_activity_date
10164 ,p_annualized_rate => l_interest_rate
10165 ,p_days_count_method => p_day_count_method);
10166
10167 elsif (p_calc_method = 'COMPOUND') then
10168
10169 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
10170 ,p_payment_freq => p_payment_freq
10171 ,p_annualized_rate => l_interest_rate
10172 ,p_period_start_date => l_add_prev_act_date
10173 ,p_period_end_date => l_activity_date
10174 ,p_days_count_method => p_day_count_method);
10175
10176 end if;
10177 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
10178
10179 l_add_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
10180 ,p_periodic_rate => l_periodic_rate
10181 ,p_compounding_period => null);
10182 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'additional interest = ' || l_add_interest);
10183
10184 if p_penal_int_rate > 0 and
10185 ((trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and trunc(l_activity_date) <= trunc(p_grace_start_date)) or
10186 (trunc(l_activity_date) > trunc(p_grace_end_date)))
10187 then
10188
10189 if trunc(l_activity_date) > trunc(p_grace_end_date) and
10190 l_first_act_after_grace = true
10191 then
10192 l_add_prev_act_date := p_grace_start_date;
10193 l_first_act_after_grace := false;
10194 elsif trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and
10195 trunc(l_activity_date) <= trunc(p_grace_start_date) and
10196 l_first_act_after_prev_grace = true
10197 then
10198 if trunc(p_prev_grace_end_date) < trunc(p_period_start_date) then
10199 l_add_prev_act_date := p_period_start_date;
10200 else
10201 l_add_prev_act_date := p_prev_grace_end_date;
10202 end if;
10203 l_first_act_after_prev_grace := false;
10204 end if;
10205
10206 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating penal interest...');
10207 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - ' || l_activity_date);
10208 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
10209 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_penal_int_rate);
10210
10211 -- calc penal interest rate
10212 if (p_calc_method = 'SIMPLE') then
10213
10214 l_penal_period_rate := getPeriodicRate(
10215 p_period_start_date => l_add_prev_act_date
10216 ,p_period_end_date => l_activity_date
10217 ,p_annualized_rate => p_penal_int_rate
10218 ,p_days_count_method => p_day_count_method);
10219
10220 elsif (p_calc_method = 'COMPOUND') then
10221
10222 l_penal_period_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
10223 ,p_payment_freq => p_payment_freq
10224 ,p_annualized_rate => p_penal_int_rate
10225 ,p_period_start_date => l_add_prev_act_date
10226 ,p_period_end_date => l_activity_date
10227 ,p_days_count_method => p_day_count_method);
10228
10229 end if;
10230
10231 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal periodic_rate = ' || l_penal_period_rate);
10232
10233 l_penal_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
10234 ,p_periodic_rate => l_penal_period_rate
10235 ,p_compounding_period => null);
10236 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal interest = ' || l_penal_interest);
10237
10238 end if;
10239
10240 l_cum_add_interest := l_cum_add_interest + l_add_interest;
10241 l_cum_penal_interest := l_cum_penal_interest + l_penal_interest;
10242 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative additional interest = ' || l_cum_add_interest);
10243 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative penal interest = ' || l_cum_penal_interest);
10244
10245 l_add_prev_amount := l_actual_balance - l_theory_balance;
10246 l_add_prev_act_date := l_activity_date;
10247 i := i + 1;
10248
10249 END LOOP;
10250 if p_target = 'UNPAID_PRIN' then
10251 close c_trx_prin_activities;
10252 elsif p_target = 'UNPAID_INT' then
10253 close c_trx_int_activities;
10254 end if;
10255
10256 -- manually adding last record for p_period_end_date date
10257 l_activity_date := p_period_end_date;
10258 l_activity_code := 'DUE';
10259 l_activity_amount := 0;
10260 l_days_late := 0;
10261
10262 if p_interest_rate is not null then
10263 l_interest_rate := p_interest_rate;
10264 end if;
10265
10266 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
10267 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date Act Act_Amount Rate Theory_Bal Actual_Bal Days_Late');
10268 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);
10269
10270 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating additional interest...');
10271 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - *' || l_activity_date);
10272 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
10273 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || l_interest_rate);
10274
10275 -- additional interest
10276 if (p_calc_method = 'SIMPLE') then
10277
10278 -- recalculate periodic rate for each period if day counting methodolgy varies
10279 l_periodic_rate := getPeriodicRate(
10280 p_period_start_date => l_add_prev_act_date
10281 ,p_period_end_date => l_activity_date
10282 ,p_annualized_rate => l_interest_rate
10283 ,p_days_count_method => p_day_count_method);
10284
10285 elsif (p_calc_method = 'COMPOUND') then
10286
10287 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
10288 ,p_payment_freq => p_payment_freq
10289 ,p_annualized_rate => l_interest_rate
10290 ,p_period_start_date => l_add_prev_act_date
10291 ,p_period_end_date => l_activity_date
10292 ,p_days_count_method => p_day_count_method);
10293
10294 end if;
10295 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
10296
10297 l_add_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
10298 ,p_periodic_rate => l_periodic_rate
10299 ,p_compounding_period => null);
10300 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'additional interest = ' || l_add_interest);
10301
10302 if p_penal_int_rate > 0 and
10303 ((trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and trunc(l_activity_date) <= trunc(p_grace_start_date)) or
10304 (trunc(l_activity_date) > trunc(p_grace_end_date)))
10305 then
10306
10307 if trunc(l_activity_date) > trunc(p_grace_end_date) and
10308 l_first_act_after_grace = true
10309 then
10310 l_add_prev_act_date := p_grace_start_date;
10311 l_first_act_after_grace := false;
10312 elsif trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and
10313 trunc(l_activity_date) <= trunc(p_grace_start_date) and
10314 l_first_act_after_prev_grace = true
10315 then
10316 if trunc(p_prev_grace_end_date) < trunc(p_period_start_date) then
10317 l_add_prev_act_date := p_period_start_date;
10318 else
10319 l_add_prev_act_date := p_prev_grace_end_date;
10320 end if;
10321 l_first_act_after_prev_grace := false;
10322 end if;
10323
10324 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating penal interest...');
10325 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - *' || l_activity_date);
10326 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
10327 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_penal_int_rate);
10328
10329 -- calc penal interest rate
10330 if (p_calc_method = 'SIMPLE') then
10331
10332 l_penal_period_rate := getPeriodicRate(
10333 p_period_start_date => l_add_prev_act_date
10334 ,p_period_end_date => l_activity_date
10335 ,p_annualized_rate => p_penal_int_rate
10336 ,p_days_count_method => p_day_count_method);
10337
10338 elsif (p_calc_method = 'COMPOUND') then
10339
10340 l_penal_period_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
10341 ,p_payment_freq => p_payment_freq
10342 ,p_annualized_rate => p_penal_int_rate
10343 ,p_period_start_date => l_add_prev_act_date
10344 ,p_period_end_date => l_activity_date
10345 ,p_days_count_method => p_day_count_method);
10346
10347 end if;
10348
10349 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal periodic_rate = ' || l_penal_period_rate);
10350
10351 l_penal_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
10352 ,p_periodic_rate => l_penal_period_rate
10353 ,p_compounding_period => null);
10354 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal interest = ' || l_penal_interest);
10355
10356 end if;
10357
10358 l_cum_add_interest := l_cum_add_interest + l_add_interest;
10359 l_cum_penal_interest := l_cum_penal_interest + l_penal_interest;
10360
10361 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Additional Interest = ' || l_cum_add_interest);
10362 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Penal Interest = ' || l_cum_penal_interest);
10363
10364 x_add_interest := l_cum_add_interest;
10365 x_penal_interest := l_cum_penal_interest;
10366
10367 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
10368 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
10369
10370 end;
10371
10372
10373 END LNS_FINANCIALS;