DBA Data[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;