DBA Data[Home] [Help]

PACKAGE BODY: APPS.LNS_FINANCIALS

Source


1 PACKAGE BODY LNS_FINANCIALS AS
2 /* $Header: LNS_FINANCIAL_B.pls 120.79.12020000.4 2013/02/11 16:13:32 scherkas ship $ */
3 
4 
5  --------------------------------------------
6  -- declaration of global variables and types
7  --------------------------------------------
8  G_DEBUG_COUNT  NUMBER := 0;
9  G_DEBUG        BOOLEAN := FALSE;
10  G_FILE_NAME    CONSTANT VARCHAR2(30) := 'LNS_FINANCIALS_B.pls';
11  G_PKG_NAME     CONSTANT VARCHAR2(30) := 'LNS_FINANCIALS';
12 
13 procedure LOAD_ORIGINAL_SCHEDULE(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC,
14                                  x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL);
15 
16  --------------------------------------------
17  -- internal package routines
18  --------------------------------------------
19 
20 procedure logMessage(log_level in number
21                     ,module    in varchar2
22                     ,message   in varchar2)
23 is
24 
25 begin
26 
27     IF log_level >= FND_LOG.G_CURRENT_RUNTIME_LEVEL THEN
28       FND_LOG.STRING(log_level, module, message);
29     END IF;
30 
31 end;
32 
33 -- internal usage only
34 function formatTerm(p_timeString IN varchar2) return varchar2
35 is
36 
37   l_temp varchar2(30);
38 begin
39 
40     -- this logic is to handle "MONTHLY" => "MONTHS" ETC...
41     if substr(p_timeString, length(p_timeString) - 1, 2) = 'LY' then
42         l_temp := substr(p_timeString, 1, length(p_timeString) - 2) || 'S';
43     else
44         l_temp := p_timeString;
45     end if;
46 
47     return l_temp;
48 
49 end;
50 
51 /*
52 || Overview:      debugging routine only
53 ||
54 || Parameter:     amortizationTable to log
55 ||
56 || Creation date:       12/08/2003 6:31PM
57 ||
58 */
59 procedure printAmortizationTable(p_amort_tbl IN lns_financials.amortization_tbl)
60 
61 is
62 
63   l_api_name             varchar2(30);
64   i                      number;
65   l_installment_number   varchar2(30);
66   l_due_date             varchar2(30);
67   l_principal_amount     varchar2(30);
68   l_interest_amount      varchar2(30);
69   l_fee_amount           varchar2(30);
70   l_other_amount         varchar2(30);
71   l_total                varchar2(30);
72   l_begin_balance        varchar2(30);
73   l_end_balance          varchar2(30);
74   l_principal_cumulative varchar2(30);
75   l_interest_cumulative  varchar2(30);
76   l_fees_cumulative      varchar2(30);
77   l_other_cumulative     varchar2(30);
78   l_rate_id              varchar2(30);
79 
80 begin
81         i := 0;
82         l_api_name  := 'printAmortizationTable';
83 
84         i := p_amort_tbl.count;
85         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
86         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization table count: ' || i);
87         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Period  Due Date     TOTAL DUE       Interest        Principal     Fees Other    '  ||
88                        ' Cum.Interest     Cum.Principal    Cum.Fees    Cum.Other    Begin Balance       End Balanace  ');
89 /*
90         for k in 1..i
91         loop
92             l_installment_number   := nvl(to_char(p_amort_tbl(k).installment_number), '       ');
93             l_due_date             := nvl(to_char(p_amort_tbl(k).due_date, 'mm/dd/yy'), '       ');
94             l_total                := nvl(to_char(p_amort_tbl(k).total), '       ');
95             l_interest_amount      := nvl(to_char(p_amort_tbl(k).interest_amount), '       ');
96             l_principal_amount     := nvl(to_char(p_amort_tbl(k).principal_amount), '       ');
97             l_other_amount         := nvl(to_char(p_amort_tbl(k).other_amount), '       ');
98             l_fee_amount           := nvl(to_char(p_amort_tbl(k).fee_amount), '       ');
99 --            l_interest_cumulative  := nvl(to_char(p_amort_tbl(k).interest_cumulative), '       ');
100 --            l_principal_cumulative := nvl(to_char(p_amort_tbl(k).principal_cumulative), '       ');
101 --            l_fees_cumulative      := nvl(to_char(p_amort_tbl(k).fees_cumulative), '       ');
102 --            l_other_cumulative     := nvl(to_char(p_amort_tbl(k).other_cumulative), '       ');
103 --            l_rate_id              := nvl(to_char(p_amort_tbl(k).rate_id), '       ');
104             l_begin_balance        := nvl(to_char(p_amort_tbl(k).begin_balance), '       ');
105             l_end_balance          := nvl(to_char(p_amort_tbl(k).end_balance), '       ');
106 
107             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ':   ' || l_installment_number ||
108                                                                               '    ' || l_due_date ||
109                                                                               '       ' || l_total ||
110                                                                               '    ' || l_interest_amount ||
111                                                                               '        ' || l_principal_amount ||
112                                                                               '     ' || l_other_amount ||
113                                                                               '        ' || l_fee_amount ||
114 --                                                                              '     ' ||  l_fees_cumulative ||
115 --                                                                              '     ' || l_other_cumulative ||
116 --                                                                              '     ' ||  l_interest_cumulative ||
117 --                                                                              '     ' || l_principal_cumulative ||
118                                                                               '     ' || l_begin_balance ||
119                                                                               '     ' || l_end_balance);
120         end loop;
121  */
122 end printAmortizationTable;
123 
124 /* routine will sort loanActivities by activityDate
125  */
126 procedure sortRows(p_loan_activity_tbl in out nocopy LNS_FINANCIALS.LOAN_ACTIVITY_TBL)
127 
128 is
129     j            number;                            -- counter
130     l_tmp_row    LNS_FINANCIALS.LOAN_ACTIVITY_REC;  -- to store temp row
131     l_min        date;                              -- minimum date
132 
133 begin
134 
135     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, ' - sorting the rows');
136     for i in 1..p_loan_activity_tbl.count loop
137         l_min := p_loan_activity_tbl(i).activity_date;
138 
139         for j in i + 1..p_loan_activity_tbl.count loop
140 
141             if p_loan_activity_tbl(j).activity_date < l_min then
142                 l_min := p_loan_activity_tbl(j).activity_date;
143                 l_tmp_row := p_loan_activity_tbl(i);
144                 p_loan_activity_tbl(i) := p_loan_activity_tbl(j);
145                 p_loan_activity_tbl(j) := l_tmp_row;
146             end if;
147         end loop;
148     end loop;
149 end sortRows;
150 
151 /*=========================================================================
152 || PUBLIC PROCEDURE floatingRatePostProcessing
153 ||
154 || DESCRIPTION
155 ||
156 || Overview: handle all post processing steps after BILLLING a FLOATING rate loan
157 ||
158 || Parameter: p_loan_id                  => loan id
159 ||            p_period_begin_date        => date at which interest was last adjusted
160 ||            p_annualized_interest_rate => rate for which installment was billed
161 ||            p_rate_id                  => rateID for rae
162 ||
163 || Return value:
164 ||
165 || Source Tables:
166 ||
167 || Target Tables:  LNS_TERMS, LNS_RATE_SCHEDULES
168 ||
169 || KNOWN ISSUES
170 ||
171 || NOTES
172 ||          -- POST PROCESSING STEPS recalculate and enter into LNS_TERMS
173 ||          --  1. next_rate_change_date
174 ||          --  2. new projected rate
175 ||          --  3. re-align rate schedule
176 ||
177 || MODIFICATION HISTORY
178 || Date                  Author            Description of Changes
179 || 11/24/2005 11:35AM     raverma           Created
180 || 06/16/2006 11:35AM     karamach          Added code to check and update only the existing rate sch row
181 || when begin_installment_number = end_installment_number = p_installment_number for the rate schedule row being processed
182 || as part of the fix for bug5331888
183 ||
184  *=======================================================================*/
185 procedure floatingRatePostProcessing(p_loan_id                  IN NUMBER
186                                     ,p_init_msg_list            IN VARCHAR2
187                                     ,p_commit                   IN VARCHAR2
188                                     ,p_installment_number       IN NUMBER
189                                     ,p_period_begin_date        IN DATE
190                                     ,p_interest_adjustment_freq IN VARCHAR2
191                                     ,p_annualized_interest_rate IN NUMBER
192                                     ,p_rate_id                  IN OUT NOCOPY NUMBER
193                                     ,p_phase                    IN VARCHAR2
194                                     ,x_return_status            OUT NOCOPY VARCHAR2
195                                     ,x_msg_count                OUT NOCOPY NUMBER
196                                     ,x_msg_data                 OUT NOCOPY VARCHAR2)
197 is
198    l_next_rate_change  date;
199    l_api_name          varchar2(30);
200    l_new_rate_id       number;
201    l_return_status      VARCHAR2(1);
202    l_msg_count          NUMBER;
203    l_msg_data           VARCHAR2(32767);
204 
205    Cursor c_get_rate_sch_info(pRateId number) is
206    select begin_installment_number, end_installment_number
207    from lns_rate_schedules where rate_id = pRateId;
208    l_begin_inst_num number;
209    l_end_inst_num number;
210 BEGIN
211 
212         l_api_name           := 'floatingRatePostProcessing';
213         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
214         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
215         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
216         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number ' || p_installment_number);
217         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_period_begin_date ' || p_period_begin_date);
218         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_interest_adjustment_freq ' || p_interest_adjustment_freq);
219         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_annualized_interest_rate ' || p_annualized_interest_rate);
220         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_rate_id ' || p_rate_id);
221         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase ' || p_phase);
222 
223         -- Standard Start of API savepoint
224         SAVEPOINT floatingPostProcessor;
225 
226         -- Initialize message list IF p_init_msg_list is set to TRUE.
227         IF FND_API.to_Boolean(p_init_msg_list) THEN
228             FND_MSG_PUB.initialize;
229         END IF;
230 
231         -- Initialize API return status to SUCCESS
232         x_return_status := FND_API.G_RET_STS_SUCCESS;
233 
234         --
235         -- Api body
236         -- ----------------------------------------------------------------
237 
238         if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
239                                                                       ,p_phase   => p_phase) then
240           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting next rate change info');
241           l_next_rate_change := lns_fin_utils.getNextDate(p_date          => p_period_begin_date
242                                                          ,p_interval_type => p_interest_adjustment_freq
243                                                          ,p_direction     => 1);
244           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating terms with new date ' || l_next_rate_change);
245           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating terms with new rate' || p_annualized_interest_rate);
246           if p_phase = 'OPEN' then
247             update lns_terms
248                set next_rate_change_date = l_next_rate_change
249                   ,open_projected_rate   = p_annualized_interest_rate
250                   ,last_update_date      = sysdate
251                   ,last_updated_by       = lns_utility_pub.user_id
252              where loan_id = p_loan_id;
253           elsif p_phase = 'TERM' then
254             update lns_terms
255                set next_rate_change_date = l_next_rate_change
256                   ,term_projected_rate    = p_annualized_interest_rate
257                   ,last_update_date      = sysdate
258                   ,last_updated_by       = lns_utility_pub.user_id
259              where loan_id = p_loan_id;
260           end if;
261 
262           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating the rate schedule ' || p_rate_id);
263           -- store the row on lns_rate_schedules(only if the existing row does not have begin and end installment numbers same as this installment) and update existing rate_schedule row
264 	 open c_get_rate_sch_info(p_rate_id);
265 	 fetch c_get_rate_sch_info into l_begin_inst_num,l_end_inst_num;
266          close c_get_rate_sch_info;
267 
268 	 if (l_begin_inst_num = l_end_inst_num and l_begin_inst_num = p_installment_number) then
269           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' (l_begin_inst_num = l_end_inst_num = p_installment_number) - NO need to insert new row - updating the existing rate schedule ' || p_rate_id);
270 
271           -- update existing rate_schedule row
272           update lns_rate_schedules
273              set current_interest_rate = p_annualized_interest_rate
274                 ,index_rate = p_annualized_interest_rate - nvl(spread,0)
275            where rate_id = p_rate_id;
276 
277 	 else --else for if (l_begin_inst_num = l_end_inst_num = p_installment_number) then
278           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' update the existing row as the next row and insert new row for the current rate sch');
279            update lns_rate_schedules
280              set begin_installment_number = begin_installment_number + 1
281                 ,current_interest_rate = spread
282                 ,index_rate = null
283            where rate_id = p_rate_id;
284 
285           select LNS_RATE_SCHEDULES_S.NEXTVAL into l_new_rate_id
286             from dual;
287 
288           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - adding new row into rate schedule');
289           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_rate_id ' || l_new_rate_id );
290           insert into lns_rate_schedules(RATE_ID
291                                         ,TERM_ID
292                                         ,INDEX_RATE
293                                         ,SPREAD
294                                         ,CURRENT_INTEREST_RATE
295                                         ,START_DATE_ACTIVE
296                                         ,END_DATE_ACTIVE
297                                         ,CREATED_BY
298                                         ,CREATION_DATE
299                                         ,LAST_UPDATED_BY
300                                         ,LAST_UPDATE_DATE
301                                         ,LAST_UPDATE_LOGIN
302                                         ,OBJECT_VERSION_NUMBER
303                                         ,INDEX_DATE
304                                         ,BEGIN_INSTALLMENT_NUMBER
305                                         ,END_INSTALLMENT_NUMBER
306                                         ,INTEREST_ONLY_FLAG
307                                         ,FLOATING_FLAG
308                                         ,PHASE)
309                                         (select
310                                           l_new_rate_id
311                                          ,TERM_ID
312                                          ,p_annualized_interest_rate - nvl(spread,0)
313                                          ,SPREAD
314                                          ,p_annualized_interest_rate  --make sure you only insert spread overtop of CIR
315                                          ,START_DATE_ACTIVE
316                                          ,END_DATE_ACTIVE
317                                          ,CREATED_BY
318                                          ,sysdate
319                                          ,LAST_UPDATED_BY
320                                          ,sysdate
321                                          ,LAST_UPDATE_LOGIN
322                                          ,1
323                                          ,INDEX_DATE
324                                          ,p_installment_number
325                                          ,p_installment_number
326                                          ,INTEREST_ONLY_FLAG
327                                          ,FLOATING_FLAG
328                                          ,PHASE
329                                          from lns_rate_schedules
330                                          where rate_id =  p_rate_id);
331 
332           -- assign new rate id for OUT parameter
333           p_rate_id := l_new_rate_id ;
334 
335          end if; --end else part for if (l_begin_inst_num = l_end_inst_num = p_installment_number) then
336 
337         else --else for if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
338 
339 	  logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - updating the rate schedule LAST ROW ' || p_rate_id);
340           -- update existing rate_schedule row
341           update lns_rate_schedules
342              set current_interest_rate = p_annualized_interest_rate
343                 ,index_rate = p_annualized_interest_rate - nvl(spread,0)
344            where rate_id = p_rate_id;
345 
346         end if; --end if p_installment_number <> lns_fin_utils.getNumberInstallments(p_loan_id => p_loan_id
347 
348 
349         --
350         -- End of API body
351         --
352         FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
353         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
354 
355     EXCEPTION
356         WHEN FND_API.G_EXC_ERROR THEN
357               ROLLBACK TO floatingPostProcessor;
358               x_return_status := FND_API.G_RET_STS_ERROR;
359               x_msg_count := l_msg_count;
360               x_msg_data  := l_msg_data;
361               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
362               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
363 
364          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
365               ROLLBACK TO floatingPostProcessor;
366               x_return_status := FND_API.G_RET_STS_ERROR;
367               x_msg_count := l_msg_count;
368               x_msg_data  := l_msg_data;
369               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
370               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
371 
372         WHEN OTHERS THEN
373               ROLLBACK TO floatingPostProcessor;
374               x_return_status := FND_API.G_RET_STS_ERROR;
375               x_msg_count := l_msg_count;
376               x_msg_data  := l_msg_data;
377               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
378               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
379 
380 end floatingRatePostProcessing;
381 
382  --------------------------------------------
383  -- validation routines
384  --------------------------------------------
385 
386 /*=========================================================================
387 || PUBLIC PROCEDURE validateLoan
388 ||
389 || DESCRIPTION
390 ||
391 || Overview: cover rountine to validate the loan
392 ||
393 || Parameter: loan_id
394 ||
395 || Return value:
396 ||
397 || Source Tables:  NA
398 ||
399 || Target Tables:
400 ||
401 || KNOWN ISSUES
402 ||
403 || NOTES
404 ||
405 || MODIFICATION HISTORY
406 || Date                  Author            Description of Changes
407 || 12/08/2003 11:35AM     raverma           Created
408 ||
409  *=======================================================================*/
410 procedure validateLoan(p_api_version    IN NUMBER
411                       ,p_init_msg_list  IN VARCHAR2
412                       ,p_loan_ID        IN NUMBER
413                       ,x_return_status  OUT NOCOPY VARCHAR2
414                       ,x_msg_count      OUT NOCOPY NUMBER
415                       ,x_msg_data       OUT NOCOPY VARCHAR2)
416 is
417     l_api_name           varchar2(25);
418     l_api_version_number number;
419     l_return_status      VARCHAR2(1);
420     l_msg_count          NUMBER;
421     l_msg_data           VARCHAR2(32767);
422 
423     l_rate_tbl           LNS_FINANCIALS.RATE_SCHEDULE_TBL;
424     l_amount             number;
425     l_status             varchar2(30);
426 
427     CURSOR c_terms(p_Loan_id NUMBER) IS
428         SELECT TERM_ID
429           FROM LNS_TERMS
430          WHERE LOAN_ID = p_Loan_id;
431 
432 BEGIN
433 
434         l_api_name           := 'validateLoan';
435         l_api_version_number := 1;
436         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
437 
438         -- Standard Start of API savepoint
439         SAVEPOINT validateLoan;
440 
441         -- Standard call to check for call compatibility.
442         IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
443                                             l_api_name, G_PKG_NAME)
444         THEN
445             RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
446         END IF;
447 
448         -- Initialize message list IF p_init_msg_list is set to TRUE.
449         IF FND_API.to_Boolean(p_init_msg_list) THEN
450             FND_MSG_PUB.initialize;
451         END IF;
452 
453         -- Initialize API return status to SUCCESS
454         x_return_status := FND_API.G_RET_STS_SUCCESS;
455 
456         --
457         -- Api body
458         -- ----------------------------------------------------------------
459         -- there should be one active row in the terms
460         -- ----------------------------------------------------------------
461         Begin
462             OPEN c_terms(p_loan_id);
463             CLOSE c_terms;
464 
465             Exception
466                 When No_Data_Found then
467                     CLOSE c_terms;
468                     FND_MESSAGE.Set_Name('LNS', 'LNS_NO_TERMS');
469                     FND_MSG_PUB.Add;
470                     RAISE FND_API.G_EXC_ERROR;
471         end;
472 
473         -- rate schedules should have one row
474         l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
475 
476         if l_rate_tbl.count = 0 then
477             FND_MESSAGE.Set_Name('LNS', 'LNS_NO_RATE_SCHEDULE');
478             FND_MSG_PUB.Add;
479             RAISE FND_API.G_EXC_ERROR;
480         end if;
481 
482         Begin
483             l_amount := lns_financials.getRemainingBalance(p_loan_id);
484             if l_amount <= 0 then
485                 FND_MESSAGE.Set_Name('LNS', 'LNS_NO_AMOUNT');
486                 FND_MSG_PUB.Add;
487                 RAISE FND_API.G_EXC_ERROR;
488             end if;
489 
490         end;
491 
492         --
493         -- End of API body
494         --
495 
496         FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
497 
498         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
499 
500         EXCEPTION
501             WHEN FND_API.G_EXC_ERROR THEN
502                  x_return_status := FND_API.G_RET_STS_ERROR;
503                  logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
504 
505             WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
506                  x_return_status := FND_API.G_RET_STS_ERROR;
507                  logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
508 
509             WHEN OTHERS THEN
510                  x_return_status := FND_API.G_RET_STS_ERROR;
511                  logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
512 
513 END validateLoan;
514 
515 ---------------------------------------------------------------------------
516 --- amortization routines
517 ---------------------------------------------------------------------------
518 
519 /*=========================================================================
520 || PUBLIC PROCEDURE runAmortization
521 ||
522 || DESCRIPTION
523 ||
524 || Overview: procedure will run an amortization and store it into a
525 ||           return an amortization table
526 ||
527 || Parameter:  loan_id
528 ||
529 || Source Tables:  NA
530 ||
531 || Target Tables: None
532 ||
533 || Return value: x_amort_tbl is table of amortization records
534 ||
535 || KNOWN ISSUES
536 ||
537 || NOTES
538 ||
539 || MODIFICATION HISTORY
540 || Date                  Author            Description of Changes
541 || 11/09/2004 11:35AM     raverma           Created
542 ||
543  *=======================================================================*/
544 procedure runAmortization(p_api_version    IN NUMBER
545                          ,p_init_msg_list  IN VARCHAR2
546                          ,p_commit         IN VARCHAR2
547                          ,p_loan_ID        IN NUMBER
548                          ,p_based_on_terms IN VARCHAR2
549                          ,x_amort_tbl      OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_TBL
550                          ,x_return_status  OUT NOCOPY VARCHAR2
551                          ,x_msg_count      OUT NOCOPY NUMBER
552                          ,x_msg_data       OUT NOCOPY VARCHAR2)
553 
554 is
555     l_api_name                varchar2(25);
556     l_api_version_number      number;
557     l_return_status           VARCHAR2(1);
558     l_msg_count               NUMBER;
559     l_msg_data                VARCHAR2(32767);
560 
561     l_amort_tbl               LNS_FINANCIALS.AMORTIZATION_TBL;
562     l_amort_tbl2              LNS_FINANCIALS.AMORTIZATION_TBL;
563     l_total_amortization      LNS_FINANCIALS.AMORTIZATION_REC;
564     l_key                     NUMBER;
565     b_showActual              boolean := false;
566     l_last_installment_billed number;
567 
568     l_installment_number      number;
569     l_due_date                date;
570     l_principal_amount        number;
571     l_interest_amount         number;
572     l_other_amount            number;
573     l_fee_amount              number;
574     l_begin_balance           number;
575     l_end_balance             number;
576     l_total                   number;
577     l_num_records             number;
578     i                         number;
579     m                         number;
580     l_records_to_copy         number;
581     l_num_installments        number;
582     l_num_rows                number;
583     l_manual_fee_amount       number;
584     l_records_to_destroy      number;
585     l_start_date              number;
586     l_funded_amount           number;
587     l_loan_details            LNS_FINANCIALS.LOAN_DETAILS_REC;
588 	l_amortization_rec		  LNS_FINANCIALS.AMORTIZATION_REC;
589 
590     l_last_payment            number;
591     l_disb_header_id                 number;
592     l_billed                         varchar2(1);
593     n                                number;
594     l_original_loan_amount    number;
595     l_fund_sched_count        number;
596 
597     l_fees_tbl                LNS_FEE_ENGINE.FEE_CALC_TBL;
598     l_fee_basis_tbl           LNS_FEE_ENGINE.FEE_BASIS_TBL;
599     l_custom_tbl              LNS_CUSTOM_PUB.CUSTOM_TBL;
600     l_AMORT_METHOD            varchar2(30);
601     l_rate_tbl                LNS_FINANCIALS.RATE_SCHEDULE_TBL;
602     l_CUSTOM_SET_REC          LNS_CUSTOM_PUB.custom_settings_type;
603 
604     cursor c_fund_sched_exist(p_loan_id number)  is
605         select decode(loan.loan_class_code,
606             'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
607             'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
608         from lns_loan_headers_all loan
609         where loan.loan_id = p_loan_id;
610 
611 BEGIN
612         -- Standard Start of API savepoint
613         SAVEPOINT runAmortization_PVT;
614         l_api_name                := 'runAmortization';
615         l_api_version_number      := 1;
616         i                         := 0;
617         l_manual_fee_amount       := 0;
618 
619         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
620         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_ID ' || p_loan_ID);
621         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_based_on_terms ' || p_based_on_terms);
622 
623         -- Standard call to check for call compatibility.
624         IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
625                                             l_api_name, G_PKG_NAME)
626         THEN
627             RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
628         END IF;
629 
630         -- Initialize message list IF p_init_msg_list is set to TRUE.
631         IF FND_API.to_Boolean( p_init_msg_list ) THEN
632             FND_MSG_PUB.initialize;
633         END IF;
634 
635         -- Initialize API return status to SUCCESS
636         x_return_status := FND_API.G_RET_STS_SUCCESS;
637 
638         --
639         -- Api body
640         -- ----------------------------------------------------------------
641         -- validate loan_id
642         lns_utility_pub.validate_any_id(p_api_version    =>  1.0
643                                        ,p_init_msg_list  =>  p_init_msg_list
644                                        ,x_msg_count      =>  l_msg_count
645                                        ,x_msg_data       =>  l_msg_data
646                                        ,x_return_status  =>  l_return_status
647                                        ,p_col_id         =>  p_loan_id
648                                        ,p_col_name       =>  'LOAN_ID'
649                                        ,p_table_name     =>  'LNS_LOAN_HEADERS_ALL');
650 
651         if l_return_status <> FND_API.G_RET_STS_SUCCESS then
652             FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
653             FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
654             FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
655             FND_MSG_PUB.ADD;
656             RAISE FND_API.G_EXC_ERROR;
657         end if;
658 
659         l_loan_details  := lns_financials.getLoanDetails(p_loan_Id         => p_loan_id
660                                                         ,p_based_on_terms  => p_based_on_terms
661                                                         ,p_phase           => 'TERM');
662 
663         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'LOAN_STATUS =  ' || l_loan_details.LOAN_STATUS);
664         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_based_on_terms =  ' || p_based_on_terms);
665         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'LOAN_PHASE =  ' || l_loan_details.LOAN_PHASE);
666 
667         l_amort_tbl.delete;
668         if l_loan_details.LOAN_STATUS NOT IN ('INCOMPLETE','DELETED','REJECTED','PENDING') and
669            p_based_on_terms <> 'CURRENT' --and l_loan_details.LOAN_PHASE = 'TERM'
670         then
671 
672             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calling LOAD_ORIGINAL_SCHEDULE...');
673             LOAD_ORIGINAL_SCHEDULE(p_loan_details => l_loan_details,
674                                  x_loan_amort_tbl => l_amort_tbl);
675 
676             x_amort_tbl := l_amort_tbl;
677             return;
678 
679         end if;
680 
681         if (l_loan_details.CUSTOM_SCHEDULE = 'N' or
682            (l_loan_details.CUSTOM_SCHEDULE = 'Y' and l_loan_details.loan_status <> 'INCOMPLETE' and
683             p_based_on_terms <> 'CURRENT' and l_loan_details.ORIG_PAY_CALC_METHOD is not null))
684         then
685 
686             -- preProcess will add a re-amortization row if the remaining amount < funded amount
687 			-- bug# 5664316
688 
689             if p_based_on_terms = 'CURRENT' and l_loan_details.reamortize_overpay = 'Y' then
690 
691                 -- call preProcessInstallment only for current amortization
692                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - preProcess the loan');
693                 preProcessInstallment(p_api_version    => 1.0
694                     ,p_init_msg_list  => p_init_msg_list
695                     ,p_commit         => FND_API.G_FALSE --p_commit
696                     ,p_loan_ID        => p_loan_id
697                     ,p_installment_number => lns_billing_util_pub.last_payment_number(p_loan_id)
698                     ,x_amortization_rec => l_amortization_rec
699                     ,x_return_status  => l_return_status
700                     ,x_msg_count      => l_msg_count
701                     ,x_msg_data       => l_msg_data);
702 
703             end if;
704 
705             -- call amortization API
706             lns_financials.amortizeLoan(p_loan_Id            => p_loan_id
707                                        ,p_based_on_terms     => p_based_on_terms
708                                        ,p_installment_number => null
709                                        ,x_loan_amort_tbl     => l_amort_tbl);
710         else
711 
712             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - loan is customized');
713 
714             if p_based_on_terms <> 'CURRENT' then
715                 open c_fund_sched_exist(p_loan_id);
716                 fetch c_fund_sched_exist into l_fund_sched_count;
717                 close c_fund_sched_exist;
718 
719                 if l_fund_sched_count = 0 then
720                     l_original_loan_amount := l_loan_details.requested_amount;
721                 else
722                     l_original_loan_amount := getFundedAmount(p_loan_id, l_loan_details.loan_start_date, p_based_on_terms);
723                 end if;
724             else
725                 l_original_loan_amount := getFundedAmount(p_loan_id, l_loan_details.loan_start_date, p_based_on_terms);
726             end if;
727 
728             l_fees_tbl.delete;
729             l_fee_amount := 0;
730 
731             -- filling out basis table
732             l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
733             l_fee_basis_tbl(1).fee_basis_amount := l_loan_details.remaining_balance;
734             l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
735             l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.requested_amount;
736             l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
737             l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
738             l_fee_basis_tbl(4).fee_basis_name   := 'TOTAL_UNDISB_AMT';
739             l_fee_basis_tbl(4).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
740 
741             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
742             LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
743                                         ,p_loan_id        => p_loan_id
744                                         ,p_installment    => 0
745                                         ,p_fee_basis_tbl  => l_fee_basis_tbl
746                                         ,p_based_on_terms => p_based_on_terms
747                                         ,p_phase          => 'TERM'
748                                         ,x_fees_tbl       => l_fees_tbl
749                                         ,x_return_status  => l_return_status
750                                         ,x_msg_count      => l_msg_count
751                                         ,x_msg_data       => l_msg_data);
752 
753             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
754             if l_return_status <> 'S' then
755                 RAISE FND_API.G_EXC_ERROR;
756             end if;
757 
758             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
759 
760             for k in 1..l_fees_tbl.count loop
761                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
762                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
763                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
764                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
765                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
766                 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
767             end loop;
768             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
769 
770             if l_fee_amount > 0 then
771                 i := i + 1;
772                 l_amort_tbl(i).installment_number   := 0;
773                 l_amort_tbl(i).due_date             := l_loan_details.loan_start_date;
774                 l_amort_tbl(i).PERIOD_START_DATE    := l_loan_details.loan_start_date;
775                 l_amort_tbl(i).PERIOD_END_DATE      := l_loan_details.loan_start_date;
776                 l_amort_tbl(i).principal_amount     := 0;
777                 l_amort_tbl(i).interest_amount      := 0;
778                 l_amort_tbl(i).fee_amount           := l_fee_amount;
779                 l_amort_tbl(i).other_amount         := 0;
780                 l_amort_tbl(i).begin_balance        := l_loan_details.requested_amount;
781                 l_amort_tbl(i).end_balance          := l_loan_details.requested_amount;
782                 l_amort_tbl(i).interest_cumulative  := 0;
783                 l_amort_tbl(i).principal_cumulative := 0;
784                 l_amort_tbl(i).fees_cumulative      := l_fee_amount;
785                 l_amort_tbl(i).other_cumulative     := 0;
786                 l_amort_tbl(i).UNPAID_PRIN          := 0;
787                 l_amort_tbl(i).UNPAID_INT           := 0;
788                 l_amort_tbl(i).NORMAL_INT_AMOUNT    := 0;
789                 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT  := 0;
790                 l_amort_tbl(i).ADD_INT_INT_AMOUNT   := 0;
791                 l_amort_tbl(i).PENAL_INT_AMOUNT     := 0;
792                 l_amort_tbl(i).PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_details.loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_details.loan_start_date, 1);
793                 l_amort_tbl(i).DISBURSEMENT_AMOUNT  := l_original_loan_amount;
794                 l_amort_tbl(i).FUNDED_AMOUNT        := l_original_loan_amount;
795                 l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT  := 0;
796                 l_amort_tbl(i).DEFERRED_INT_AMOUNT  := 0;
797                 l_amort_tbl(i).PREV_CAP_INT_AMOUNT  := 0;
798                 l_amort_tbl(i).CAP_INT_AMOUNT       := 0;
799                 l_amort_tbl(i).EARLY_PAY_CR_AMOUNT  := 0;
800                 -- add the record to the amortization table
801 
802                 l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
803                 l_amort_tbl(i).INTEREST_RATE        := l_rate_tbl(1).annual_rate;
804 
805                 l_amort_tbl(i).total                := l_fee_amount;
806             end if;
807 
808             -- load custom schedule
809             LNS_CUSTOM_PUB.loadCustomSchedule(
810                 P_API_VERSION		    => 1.0,
811                 P_INIT_MSG_LIST		    => FND_API.G_TRUE,
812                 P_COMMIT		        => FND_API.G_FALSE,
813                 P_VALIDATION_LEVEL	    => FND_API.G_VALID_LEVEL_FULL,
814                 P_LOAN_ID               => P_LOAN_ID,
815                 P_BASED_ON_TERMS        => p_based_on_terms,
816                 X_CUSTOM_SET_REC        => l_CUSTOM_SET_REC,
817                 X_CUSTOM_TBL            => l_custom_tbl,
818                 x_return_status         => l_return_status,
819                 x_msg_count             => l_msg_count,
820                 x_msg_data              => l_msg_data);
821 
822             IF l_return_status <> 'S' THEN
823                 RAISE FND_API.G_EXC_ERROR;
824             END IF;
825 
826             for p in 1..l_custom_tbl.count loop
827 
828                 i := i + 1;
829                 l_amort_tbl(i).installment_number   := l_custom_tbl(p).PAYMENT_NUMBER;
830                 l_amort_tbl(i).due_date             := l_custom_tbl(p).DUE_DATE;
831                 l_amort_tbl(i).PERIOD_START_DATE    := l_custom_tbl(p).PERIOD_START_DATE;
832                 l_amort_tbl(i).PERIOD_END_DATE      := l_custom_tbl(p).PERIOD_END_DATE;
833                 l_amort_tbl(i).principal_amount     := l_custom_tbl(p).PRINCIPAL_AMOUNT;
834                 l_amort_tbl(i).interest_amount      := l_custom_tbl(p).INTEREST_AMOUNT;
835                 l_amort_tbl(i).TOTAL                := l_custom_tbl(p).CURRENT_TERM_PAYMENT;
836                 l_amort_tbl(i).fee_amount           := l_custom_tbl(p).FEE_AMOUNT;
837                 l_amort_tbl(i).other_amount         := l_custom_tbl(p).other_amount;
838                 l_amort_tbl(i).begin_balance        := l_custom_tbl(p).INSTALLMENT_BEGIN_BALANCE;
839                 l_amort_tbl(i).end_balance          := l_custom_tbl(p).INSTALLMENT_END_BALANCE;
840                 l_amort_tbl(i).UNPAID_PRIN          := l_custom_tbl(p).UNPAID_PRIN;
841                 l_amort_tbl(i).UNPAID_INT           := l_custom_tbl(p).UNPAID_INT;
842                 l_amort_tbl(i).INTEREST_RATE        := l_custom_tbl(p).INTEREST_RATE;
843                 l_amort_tbl(i).NORMAL_INT_AMOUNT    := l_custom_tbl(p).NORMAL_INT_AMOUNT;
844                 l_amort_tbl(i).ADD_PRIN_INT_AMOUNT  := l_custom_tbl(p).ADD_PRIN_INT_AMOUNT;
845                 l_amort_tbl(i).ADD_INT_INT_AMOUNT   := l_custom_tbl(p).ADD_INT_INT_AMOUNT;
846                 l_amort_tbl(i).PENAL_INT_AMOUNT     := l_custom_tbl(p).PENAL_INT_AMOUNT;
847                 l_amort_tbl(i).NORMAL_INT_DETAILS   := l_custom_tbl(p).NORMAL_INT_DETAILS;
848                 l_amort_tbl(i).ADD_PRIN_INT_DETAILS := l_custom_tbl(p).ADD_PRIN_INT_DETAILS;
849                 l_amort_tbl(i).ADD_INT_INT_DETAILS  := l_custom_tbl(p).ADD_INT_INT_DETAILS;
850                 l_amort_tbl(i).PENAL_INT_DETAILS    := l_custom_tbl(p).PENAL_INT_DETAILS;
851                 l_amort_tbl(i).FUNDED_AMOUNT        := l_custom_tbl(p).FUNDED_AMOUNT;
852                 l_amort_tbl(i).PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_custom_tbl(p).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_custom_tbl(p).PERIOD_END_DATE-1), 1);
853                 l_amort_tbl(i).DISBURSEMENT_AMOUNT  := l_custom_tbl(p).DISBURSEMENT_AMOUNT;
854                 l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT  := l_custom_tbl(p).PREV_DEFERRED_INT_AMOUNT;
855                 l_amort_tbl(i).DEFERRED_INT_AMOUNT  := l_custom_tbl(p).DEFERRED_INT_AMOUNT;
856                 l_amort_tbl(i).DEFERRED_INT_DETAILS := l_custom_tbl(p).DEFERRED_INT_DETAILS;
857                 l_amort_tbl(i).PREV_CAP_INT_AMOUNT  := l_custom_tbl(p).PREV_CAP_INT_AMOUNT;
858                 l_amort_tbl(i).CAP_INT_AMOUNT       := l_custom_tbl(p).CAP_INT_AMOUNT;
859                 l_amort_tbl(i).CAP_INT_DETAILS      := l_custom_tbl(p).CAP_INT_DETAILS;
860                 l_amort_tbl(i).EARLY_PAY_CR_AMOUNT  := l_custom_tbl(p).EARLY_PAY_CR_AMOUNT;
861                 l_amort_tbl(i).EARLY_PAY_CR_DETAILS := l_custom_tbl(p).EARLY_PAY_CR_DETAILS;
862 
863             END LOOP;
864 
865         end if;
866 
867         -- delete predicted records based on ORIGINAL amortization
868         if p_based_on_terms = 'CURRENT' and
869            l_loan_details.LOAN_STATUS NOT IN ('INCOMPLETE','DELETED','REJECTED','PENDING','APPROVED')
870         then
871 
872             l_num_records := l_amort_tbl.count;
873             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - amortization returns # records '|| l_num_records);
874             l_last_installment_billed := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER_EXT_3(p_loan_id, 'TERM');
875             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - last installment billed '|| l_last_installment_billed);
876 
877             -- copy the records not billed to a temp collection
878             m := 0;
879             for i in 1..l_num_records
880             loop
881                 if l_amort_tbl(i).installment_number > l_last_installment_billed or
882                    (l_amort_tbl(i).installment_number = 0 and l_last_installment_billed = 0)
883                 then
884                     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - copying record ' || i ||
885                         ': installment ' || l_amort_tbl(i).installment_number);
886                     m := m + 1;
887                     l_amort_tbl2(m) := l_amort_tbl(i);
888                 end if;
889             end loop;
890 
891             -- copy back to original table
892             l_amort_tbl.delete;
893             m := 0;
894             for i in 1..l_amort_tbl2.count
895             loop
896                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - re-copying record ' || i);
897                 m := m + 1;
898                 l_amort_tbl(m) := l_amort_tbl2(i);
899             end loop;
900 
901 
902         end if;
903 
904         x_amort_tbl := l_amort_tbl;
905         --
906         -- End of API body
907         --
908 
909         -- Standard check for p_commit
910         IF FND_API.to_Boolean(p_commit) THEN
911             COMMIT WORK;
912         END IF;
913 
914         FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
915         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
916 
917     EXCEPTION
918         WHEN FND_API.G_EXC_ERROR THEN
919               ROLLBACK TO runAmortization_PVT;
920               x_return_status := FND_API.G_RET_STS_ERROR;
921               x_msg_count := l_msg_count;
922               x_msg_data  := l_msg_data;
923               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
924               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
925 
926          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
927               ROLLBACK TO runAmortization_PVT;
928               x_return_status := FND_API.G_RET_STS_ERROR;
929               x_msg_count := l_msg_count;
930               x_msg_data  := l_msg_data;
931               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
932               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
933 
934         WHEN OTHERS THEN
935               ROLLBACK TO runAmortization_PVT;
936               x_return_status := FND_API.G_RET_STS_ERROR;
937               x_msg_count := l_msg_count;
938               x_msg_data  := l_msg_data;
939               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
940               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
941 
942 END runAmortization;
943 
944 /*=========================================================================
945  | PUBLIC PROCEDURE termlyPayment
946  |
947  | DESCRIPTION
948 ||
949 || Overview:  number of periods to pay off a loan according to formula
950 ||  periods_to_payoff = [ LN(1-(rate*loanAmount)/(payment*payments_per_period)) /
951 ||                            LN(1 + rate/payments_per_period)]
952 ||
953 || Parameter:  p_termly amount = periodic amount to pay
954 ||             p_annual_rate   = annual interest rate on the loan
955 ||             p_loan_amount   = amount of the loan
956 ||             p_payments_per_year = payments @ termly_amount per year
957 ||             p_period_type = 'YEARS', 'QUARTERS', 'MONTHS'
958 ||
959 || Source Tables:  NA
960 ||
961 || Target Tables:  NA
962 ||
963 || Return value: number of periods to pay off the loan
964 ||               if return value = -1 then the loan can never be payed off
965 ||               at that termly amount and rate
966 ||
967 || KNOWN ISSUES
968 ||
969 || NOTES
970 ||      NOTE: INSTALLMENT_NUMBER WILL NOT GET YOU THE GIVEN INSTALLMENT
971 ||            NUMBER CORRESPONDING ON THE LOAN AMORTIZATION SCHEDULE
972 ||
973 || MODIFICATION HISTORY
974 || Date                  Author            Description of Changes
975 || 12/11/2003 6:42PM     raverma           Created
976 ||
977  *=======================================================================*/
978 function termlyPayment(p_termly_amount     in number
979                       ,p_annual_rate       in number
980                       ,p_loan_amount       in number
981                       ,p_payments_per_year in number
982                       ,p_period_type       in varchar2) return number
983 is
984   l_periodic_rate number;
985   l_num_periods   number;
986   l_api_name      varchar2(15);
987 
988 begin
989 
990      l_api_name := 'termlyPayment';
991      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
992 
993      l_periodic_rate := p_annual_rate / 100;
994 
995      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate: ' || l_periodic_rate);
996      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': termly amount: ' || p_termly_amount);
997      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payments per year: ' || p_payments_per_year);
998      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan amount : ' || p_loan_amount);
999 
1000      if l_periodic_rate <> 0 then
1001         -- we cannot have LN < 0
1002         -- this will be a loan that will never be paid off
1003         if ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount) >= 1 then
1004              FND_MESSAGE.Set_Name('LNS', 'LNS_NEVER_PAYOFF');
1005              FND_MSG_PUB.Add;
1006              RAISE FND_API.G_EXC_ERROR;
1007         end if;
1008 
1009         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate * p_loan_amount :' || l_periodic_rate * p_loan_amount);
1010         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_payments_per_year * p_termly_amount : ' || p_payments_per_year * p_termly_amount);
1011         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': LN(1-a/b) : ' || LN(1 - ( ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount))));
1012         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate / p_payments_per_year : ' || l_periodic_rate / p_payments_per_year);
1013         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': LN(1+d) : ' || LN(1 + (l_periodic_rate / p_payments_per_year)));
1014         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': - p_payments_per_year : ' || (- p_payments_per_year));
1015 
1016         l_num_periods := (LN(1 - ( ( l_periodic_rate * p_loan_amount ) / (p_payments_per_year * p_termly_amount))) /
1017                            LN(1 + (l_periodic_rate / p_payments_per_year))) / (- p_payments_per_year) ;
1018      else
1019         l_num_periods := p_loan_amount / p_termly_amount / p_payments_per_year;
1020 
1021      end if;
1022 
1023      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': num years to pay off = ' || l_num_periods);
1024 
1025      if p_period_type = 'MONTHS' then
1026         l_num_periods := l_num_periods * 12;
1027 
1028      elsif p_period_type = 'QUARTERS' then
1029         l_num_periods := l_num_periods * 4;
1030 
1031      elsif p_period_type = 'YEARS' then
1032         null;
1033 
1034      end if;
1035 
1036      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1037 
1038      return l_num_periods;
1039 
1040 Exception
1041 
1042     When FND_API.G_EXC_ERROR then
1043         return -1;
1044 
1045     When others then
1046         return -1;
1047 
1048 end termlyPayment;
1049 
1050 /*=========================================================================
1051 || PUBLIC PROCEDURE preProcessInstallment
1052 ||
1053 || DESCRIPTION
1054 ||
1055 || Overview:  this procedure will recalculate an installment for reamortization
1056 ||
1057 || PSEUDO CODE/LOGIC
1058 ||
1059 || PARAMETERS
1060 ||
1061 || Parameter:  p_loan_id => in loanID
1062 ||             p_installment_number = FLAG to notify to get the
1063 ||                                    latest installment
1064 ||
1065 || Return value: AMORTIZATION_REC => contains billing and payment information
1066 ||
1067 || Source Tables:  NA
1068 ||
1069 || Target Tables:  NA
1070 ||
1071 || KNOWN ISSUES
1072 ||
1073 || NOTES
1074 ||      NOTE: api used by Billing Engine
1075 ||
1076 || MODIFICATION HISTORY
1077 || Date                  Author            Description of Changes
1078 || 03/12/2004 12:40PM     raverma           Created
1079 ||
1080  *=======================================================================*/
1081 procedure preProcessInstallment(p_api_version        IN NUMBER
1082                                ,p_init_msg_list      IN VARCHAR2
1083                                ,p_commit             IN VARCHAR2
1084                                ,p_loan_ID            IN NUMBER
1085                                ,p_installment_number IN NUMBER
1086                                ,x_amortization_rec   OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1087                                ,x_return_status      OUT NOCOPY VARCHAR2
1088                                ,x_msg_count          OUT NOCOPY NUMBER
1089                                ,x_msg_data           OUT NOCOPY VARCHAR2)
1090 is
1091   l_amortization_rec      LNS_FINANCIALS.AMORTIZATION_REC;
1092   l_amort_tbl             LNS_FINANCIALS.AMORTIZATION_TBL;
1093   l_count                 NUMBER;
1094   l_api_name              varchar2(40);
1095   l_loan_details          LNS_FINANCIALS.LOAN_DETAILS_REC;
1096 
1097   l_theoretical_balance   NUMBER;
1098   l_actual_balance        NUMBER;
1099   l_api_version_number    number;
1100   l_return_status         VARCHAR2(1);
1101   l_msg_count             NUMBER;
1102   l_msg_data              VARCHAR2(32767);
1103   l_fee_structures        LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;  -- define what event(s) we are processing fees for
1104   l_fees_tbl              LNS_FEE_ENGINE.FEE_CALC_TBL;
1105   l_overdue_amount        number;
1106   i                       number;
1107   l_due_date              date;
1108   l_installment           number;
1109   l_arr_pos               number;
1110 
1111   -- this is for get custom dates
1112    cursor c_customized (p_loan_id number) is
1113    SELECT nvl(h.custom_payments_flag, 'N')
1114      FROM lns_loan_headers_all h
1115     WHERE loan_id = p_loan_id;
1116 
1117     cursor c_customSchedule(p_loan_id number, p_installment number) is
1118     select payment_number            installment_number
1119           ,due_date                  due_date
1120      from lns_custom_paymnt_scheds
1121     where loan_id = p_loan_id
1122       and payment_number = p_installment;
1123 
1124 begin
1125 
1126       l_api_name           := 'preProcessInstallment';
1127       l_api_version_number := 1;
1128 
1129       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1130       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1131       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1132 
1133       -- Standard Start of API savepoint
1134       SAVEPOINT preProcessInstallment;
1135 
1136       -- Standard call to check for call compatibility.
1137       IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
1138                                           l_api_name, G_PKG_NAME)
1139       THEN
1140           RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1141       END IF;
1142 
1143       -- Initialize message list IF p_init_msg_list is set to TRUE.
1144       IF FND_API.to_Boolean(p_init_msg_list) THEN
1145           FND_MSG_PUB.initialize;
1146       END IF;
1147       -- Initialize API return status to SUCCESS
1148       x_return_status := FND_API.G_RET_STS_SUCCESS;
1149 
1150       -- Api body
1151       -- get the loan details
1152       -- compare the actual balance to the theoretical balance
1153       -- if they are inconsistent and reamorization flag is set
1154       -- then insert reamortization information into LNS_AMORTIZATION_SCHEDS
1155 /*
1156       if p_installment_number = 0 then
1157         i := p_installment_number + 1;
1158       else
1159         i := p_installment_number;
1160       end if;
1161 */
1162       l_loan_details  := lns_financials.getLoanDetails(p_loan_Id         => p_loan_id
1163                                                       ,p_based_on_terms  => 'CURRENT'
1164 													  ,p_phase           => 'TERM');
1165 
1166       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting next installment info...');
1167       if l_loan_details.custom_schedule = 'N' then
1168           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - regular loan');
1169 
1170           -- this is a standard non-customized loan
1171           lns_financials.amortizeLoan(p_loan_Id            => p_loan_id
1172                                      ,p_based_on_terms     => 'CURRENT'
1173                                      ,p_installment_number => p_installment_number
1174                                      ,x_loan_amort_tbl     => l_amort_tbl);
1175           l_count :=  l_amort_tbl.count;
1176           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' table count is ' || l_count);
1177 
1178           for i in REVERSE 1..l_amort_tbl.count loop
1179             if p_installment_number = l_amort_tbl(i).INSTALLMENT_NUMBER then
1180                 l_due_date    := l_amort_tbl(i).due_date;
1181                 l_installment := l_amort_tbl(i).installment_number;
1182                 exit;
1183             end if;
1184           end loop;
1185 
1186       else
1187           -- we are on a customized loan
1188           -- check if this is 0th installment or not
1189           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - custom loan');
1190           if p_installment_number > 0 then
1191               open c_customSchedule(p_loan_id, p_installment_number);
1192               fetch c_customSchedule into
1193                        l_installment
1194                       ,l_due_date;
1195               close c_customSchedule;
1196           else
1197              -- we are on 0th installment
1198              l_installment := p_installment_number;
1199              l_due_date    := l_loan_details.loan_start_date;
1200           end if;
1201       end if;
1202 
1203       -- assign to output record
1204         l_amortization_rec.installment_number := l_installment;
1205         l_amortization_rec.due_date           := l_due_date;
1206       --l_amortization_rec.principal_amount     := l_amort_tbl(i).principal_amount;
1207       --l_amortization_rec.interest_amount      := l_amort_tbl(i).interest_amount;
1208       --l_amortization_rec.fee_amount           := l_amort_tbl(i).fee_amount;
1209       --l_amortization_rec.other_amount         := l_amort_tbl(i).other_amount;
1210       --l_amortization_rec.total                := l_amort_tbl(i).total;
1211       --l_amortization_rec.begin_balance        := l_amort_tbl(i).begin_balance;
1212       --l_amortization_rec.end_balance          := l_amort_tbl(i).end_balance;
1213       --l_amortization_rec.principal_cumulative := l_amort_tbl(i).principal_cumulative;
1214       --l_amortization_rec.interest_cumulative  := l_amort_tbl(i).interest_cumulative;
1215       --l_amortization_rec.fees_cumulative      := l_amort_tbl(i).fees_cumulative;
1216       --l_amortization_rec.other_cumulative     := l_amort_tbl(i).other_cumulative;
1217       --l_amortization_rec.rate_id              := l_amort_tbl(i).rate_id;
1218 
1219       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' next installment due: ' || l_amortization_rec.installment_number);
1220       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' next due date: ' || l_amortization_rec.due_date);
1221 
1222       -- get theoretical balance
1223 	  -- bug# 5664316 - remove installment number check
1224       if l_loan_details.reamortize_overpay = 'Y' and
1225          l_loan_details.custom_schedule = 'N' -- fix for bug 6902221
1226       then --and p_installment_number > 1  then
1227 
1228            logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - checking if we need to reamortize...');
1229 
1230            lns_financials.amortizeLoan(p_loan_Id            => p_loan_id
1231                                      ,p_based_on_terms     => 'ORIGINAL'
1232                                      ,p_installment_number => p_installment_number
1233                                      ,x_loan_amort_tbl     => l_amort_tbl);
1234 
1235            logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' comparing balances...');
1236            l_actual_balance      := l_loan_details.remaining_balance;
1237 
1238            if p_installment_number > 0 then
1239 
1240                 -- l_arr_pos is array index
1241                 l_arr_pos := p_installment_number;
1242 
1243                 -- will get inside if only if there is origination fee
1244                 if l_amort_tbl(1).INSTALLMENT_NUMBER = 0 then
1245                     l_arr_pos := p_installment_number + 1;
1246                 end if;
1247 
1248                 if l_amort_tbl.count < l_arr_pos then
1249                     l_theoretical_balance := 0;
1250                 else
1251                     l_theoretical_balance := l_amort_tbl(l_arr_pos).end_balance;
1252                 end if;
1253                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' p_installment_number ' || p_installment_number);
1254                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' l_arr_pos ' || l_arr_pos);
1255 
1256            elsif p_installment_number = 0 then
1257 			     -- this check will take care of multiple reAmortizations on 0th installment
1258 		         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize zero installment');
1259 				 if l_loan_details.reamortize_amount = 0 or l_loan_details.reamortize_amount is null then
1260 
1261 		           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize amount is zero - no previous reamortization ');
1262 				   l_theoretical_balance := l_loan_details.funded_amount;
1263 				 else
1264 
1265 		           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' reamortize amount is not zero - previous reamort amount');
1266 				   l_theoretical_balance := l_loan_details.reamortize_amount;
1267 				 end if;
1268 		   end if;
1269 
1270            logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' actual balance ' || l_actual_balance);
1271            logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' theoretical balance ' || l_theoretical_balance);
1272 			-- end bug# 5664316 11-23-2006
1273 
1274            if l_actual_balance < l_theoretical_balance then
1275 
1276               logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZING...');
1277 
1278               -- remove all reAmortize rows from amortization schedule
1279               logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' removing previous reAmortize rows');
1280 
1281               delete
1282               from lns_amortization_scheds
1283               where loan_id = p_loan_id
1284               and reamortization_amount is not null
1285               and reamortize_from_installment is not null;
1286 
1287               logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZE OVERPAY LOAN');
1288               logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' insert record into amortizations');
1289               insert into LNS_AMORTIZATION_SCHEDS(amortization_schedule_id
1290                                                  ,loan_id
1291                                                  ,reamortization_amount
1292                                                  ,reamortize_from_installment
1293                                                  ,reamortize_to_installment
1294                                                  ,created_by
1295                                                  ,creation_date
1296                                                  ,last_updated_by
1297                                                  ,last_update_date
1298                                                  ,object_version_number)
1299                                                  values
1300                                                  (LNS_AMORTIZATION_SCHEDS_S.NEXTVAL
1301                                                  ,p_loan_id
1302                                                  ,l_actual_balance
1303                                                  ,p_installment_number
1304                                                  ,null
1305                                                  ,lns_utility_pub.created_by
1306                                                  ,lns_utility_pub.creation_date
1307                                                  ,lns_utility_pub.last_updated_by
1308                                                  ,lns_utility_pub.last_update_date
1309                                                  ,1);
1310            -- bug #3718480
1311            -- we will need to credit out all unpaid principal documents
1312            /*
1313            elsif l_loan_details.reamortize_underpay = 'Y' and l_actual_balance > l_theoretical_balance then
1314               logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' REAMORTIZE UNDERPAY LOAN');
1315               logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' insert record into amortizations');
1316               insert into LNS_AMORTIZATION_SCHEDS(amortization_schedule_id
1317                                                  ,loan_id
1318                                                  ,reamortization_amount
1319                                                  ,reamortize_from_installment
1320                                                  ,reamortize_to_installment
1321                                                  ,created_by
1322                                                  ,creation_date
1323                                                  ,last_updated_by
1324                                                  ,last_update_date
1325                                                  ,object_version_number)
1326                                                  values
1327                                                  (LNS_AMORTIZATION_SCHEDS_S.NEXTVAL
1328                                                  ,p_loan_id
1329                                                  ,l_actual_balance
1330                                                  ,p_installment_number
1331                                                  ,null
1332                                                  ,lns_utility_pub.created_by
1333                                                  ,lns_utility_pub.creation_date
1334                                                  ,lns_utility_pub.last_updated_by
1335                                                  ,lns_utility_pub.last_update_date
1336                                                  ,1);
1337            */
1338            else
1339                logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' WILL NOT REAMORTIZE!');
1340            end if;
1341       end if;
1342 
1343       x_amortization_rec := l_amortization_rec;
1344 
1345       --
1346       -- End of API body
1347       -- ---------------------------------------------------------------
1348 
1349       -- Standard check for p_commit
1350       IF FND_API.to_Boolean(p_commit) THEN
1351           COMMIT WORK;
1352       END IF;
1353 
1354       FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
1355       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1356 
1357  Exception
1358     WHEN FND_API.G_EXC_ERROR THEN
1359           ROLLBACK TO preProcessInstallment;
1360           x_return_status := FND_API.G_RET_STS_ERROR;
1361           x_msg_count := l_msg_count;
1362           x_msg_data  := l_msg_data;
1363           FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1364           logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1365 
1366      WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1367           ROLLBACK TO preProcessInstallment;
1368           x_return_status := FND_API.G_RET_STS_ERROR;
1369           x_msg_count := l_msg_count;
1370           x_msg_data  := l_msg_data;
1371           FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1372           logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
1373 
1374     WHEN OTHERS THEN
1375           ROLLBACK TO preProcessInstallment;
1376           x_return_status := FND_API.G_RET_STS_ERROR;
1377           x_msg_count := l_msg_count;
1378           x_msg_data  := l_msg_data;
1379           FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1380           logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1381 
1382 end preProcessInstallment;
1383 
1384 /*=========================================================================
1385 || PUBLIC PROCEDURE preProcessOpenInstallment
1386 ||
1387 || DESCRIPTION
1388 ||
1389 || Overview:  this procedure will preProcess an installment
1390 ||
1391 || PSEUDO CODE/LOGIC
1392 ||
1393 || PARAMETERS
1394 ||
1395 || Parameter:  p_loan_id => in loanID
1396 ||             p_installment_number = FLAG to notify to get the
1397 ||                                    latest installment
1398 ||
1399 || Return value: AMORTIZATION_REC => contains billing and payment information
1400 ||
1401 || Source Tables:  NA
1402 ||
1403 || Target Tables:  NA
1404 ||
1405 || KNOWN ISSUES
1406 ||
1407 || NOTES
1408 ||      NOTE: api used by Billing Engine
1409 ||
1410 || MODIFICATION HISTORY
1411 || Date                  Author            Description of Changes
1412 || 03/12/2004 12:40PM     raverma           Created
1413 ||
1414  *=======================================================================*/
1415 procedure preProcessOpenInstallment(p_init_msg_list      IN VARCHAR2
1416                                    ,p_commit             IN VARCHAR2
1417                                    ,p_loan_ID            IN NUMBER
1418                                    ,p_installment_number IN NUMBER
1419                                    ,x_amortization_rec   OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1420                                    ,x_return_status      OUT NOCOPY VARCHAR2
1421                                    ,x_msg_count          OUT NOCOPY NUMBER
1422                                    ,x_msg_data           OUT NOCOPY VARCHAR2)
1423 is
1424   l_amortization_rec      LNS_FINANCIALS.AMORTIZATION_REC;
1425   l_count                 NUMBER;
1426   l_api_name              varchar2(40);
1427   l_loan_details          LNS_FINANCIALS.LOAN_DETAILS_REC;
1428 
1429   l_return_status         VARCHAR2(1);
1430   l_msg_count             NUMBER;
1431   l_msg_data              VARCHAR2(32767);
1432   l_fees_tbl              LNS_FINANCIALS.FEES_TBL;
1433   i                       number;
1434   l_installment           number;
1435 
1436 begin
1437 
1438       l_api_name           := 'preProcessOpenInstallment';
1439       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1440       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1441       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1442 
1443       -- Standard Start of API savepoint
1444       SAVEPOINT preProcessOpenInstallment;
1445 
1446       -- Initialize message list IF p_init_msg_list is set to TRUE.
1447       IF FND_API.to_Boolean(p_init_msg_list) THEN
1448           FND_MSG_PUB.initialize;
1449       END IF;
1450 
1451       -- Initialize API return status to SUCCESS
1452       x_return_status := FND_API.G_RET_STS_SUCCESS;
1453 
1454       -- ---------------------------------------------------------------
1455       -- Beginning of API body
1456       --
1457       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting loan details');
1458       l_loan_details  := lns_financials.getLoanDetails(p_loan_Id            => p_loan_id
1459                                                       ,p_based_on_terms     => 'CURRENT'
1460 													  ,p_phase              => 'OPEN');
1461 
1462       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting Open Installment');
1463       lns_financials.getOpenInstallment(p_init_msg_list      => 'T'
1464                                        ,p_loan_ID            => p_loan_ID
1465                                        ,p_installment_number => p_installment_number
1466                                        ,x_fees_tbl           => l_fees_tbl
1467                                        ,x_amortization_rec   => l_amortization_rec
1468                                        ,x_return_status      => l_return_Status
1469                                        ,x_msg_count          => l_msg_count
1470                                        ,x_msg_data           => l_msg_data);
1471 
1472       if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1473            FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1474            FND_MSG_PUB.ADD;
1475            RAISE FND_API.G_EXC_ERROR;
1476       end if;
1477 
1478       x_amortization_rec := l_amortization_rec;
1479 
1480       --
1481       -- End of API body
1482       -- ---------------------------------------------------------------
1483 
1484       -- Standard check for p_commit
1485       IF FND_API.to_Boolean(p_commit) THEN
1486           COMMIT WORK;
1487       END IF;
1488 
1489       FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
1490       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1491 
1492  Exception
1493     WHEN FND_API.G_EXC_ERROR THEN
1494           ROLLBACK TO preProcessOpenInstallment;
1495           x_return_status := FND_API.G_RET_STS_ERROR;
1496           x_msg_count := l_msg_count;
1497           x_msg_data  := l_msg_data;
1498           FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1499           logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1500 
1501      WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1502           ROLLBACK TO preProcessOpenInstallment;
1503           x_return_status := FND_API.G_RET_STS_ERROR;
1504           x_msg_count := l_msg_count;
1505           x_msg_data  := l_msg_data;
1506           FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1507           logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
1508 
1509     WHEN OTHERS THEN
1510           ROLLBACK TO preProcessOpenInstallment;
1511           x_return_status := FND_API.G_RET_STS_ERROR;
1512           x_msg_count := l_msg_count;
1513           x_msg_data  := l_msg_data;
1514           FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1515           logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1516 
1517 end preProcessOpenInstallment;
1518 
1519 
1520 /*=========================================================================
1521 || PUBLIC PROCEDURE getInstallment
1522 ||
1523 || DESCRIPTION
1524 ||
1525 || Overview:  returns interest and principal for a single installment
1526 ||            this is used for the billing concurrent program
1527 ||
1528 || PSEUDO CODE/LOGIC
1529 ||
1530 || PARAMETERS
1531 ||
1532 || Parameter:  p_loan_id => in loanID
1533 ||             p_installment_number = FLAG to notify to get the
1534 ||                                    latest installment
1535 ||
1536 || Return value: AMORTIZATION_REC => contains billing and payment information
1537 ||
1538 || Source Tables:  NA
1539 ||
1540 || Target Tables:  NA
1541 ||
1542 || KNOWN ISSUES
1543 ||
1544 || NOTES
1545 ||      NOTE: api used by Billing Engine
1546 ||
1547 || MODIFICATION HISTORY
1548 || Date                  Author            Description of Changes
1549 || 12/11/2003 12:40PM     raverma           Created
1550 ||
1551  *=======================================================================*/
1552 procedure getInstallment(p_api_version        IN NUMBER
1553                         ,p_init_msg_list      IN VARCHAR2
1554                         ,p_commit             IN VARCHAR2
1555                         ,p_loan_Id            in number
1556                         ,p_installment_number in number
1557                         ,x_amortization_rec   OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
1558                         ,x_fees_tbl           OUT NOCOPY LNS_FINANCIALS.FEES_TBL
1559                         ,x_return_status      OUT NOCOPY VARCHAR2
1560                         ,x_msg_count          OUT NOCOPY NUMBER
1561                         ,x_msg_data           OUT NOCOPY VARCHAR2)
1562 is
1563   l_amortization_rec      LNS_FINANCIALS.AMORTIZATION_REC;
1564   l_amortization_tbl      LNS_FINANCIALS.AMORTIZATION_TBL;
1565   l_loan_details          LNS_FINANCIALS.LOAN_DETAILS_REC;
1566   l_count                 NUMBER;
1567   l_api_version_number    number;
1568   l_return_status         VARCHAR2(1);
1569   l_msg_count             NUMBER;
1570   l_msg_data              VARCHAR2(32767);
1571   l_api_name              varchar2(25);
1572   l_fees_tbl              LNS_FEE_ENGINE.FEE_CALC_TBL;
1573   l_fees_tbl_1            LNS_FEE_ENGINE.FEE_CALC_TBL;
1574   l_fees_tbl_2            LNS_FINANCIALS.FEES_TBL;
1575   l_total_fees            number;
1576   l_fee_basis_tbl         LNS_FEE_ENGINE.FEE_BASIS_TBL;
1577   l_fee_structures        LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;  -- define what event(s) we are processing fees for
1578   i                       number;
1579   --l_begin_balance         number;       -- used for fees calculation
1580   l_customized            varchar2(1);
1581   l_loan_start_date       date;
1582   l_funded_amount         number;
1583   l_custom_tbl            LNS_CUSTOM_PUB.CUSTOM_TBL;
1584   l_AMORT_METHOD          varchar2(30);
1585   l_CUSTOM_SET_REC        LNS_CUSTOM_PUB.custom_settings_type;
1586 
1587   /* query custom amortization */
1588   CURSOR cust_amort_cur(P_LOAN_ID number, P_PAYMENT_NUMBER number) IS
1589       select
1590           cust.DUE_DATE
1591           ,nvl(cust.PRINCIPAL_AMOUNT, 0)
1592           ,nvl(cust.INTEREST_AMOUNT, 0)
1593           ,cust.installment_begin_balance
1594           ,cust.installment_end_balance
1595           --cust.FEE_AMOUNT
1596       from LNS_CUSTOM_PAYMNT_SCHEDS cust
1597       where cust.LOAN_ID = P_LOAN_ID and
1598           cust.PAYMENT_NUMBER = P_PAYMENT_NUMBER;
1599 
1600 begin
1601 
1602     l_api_version_number    := 1;
1603     l_api_name              := 'getInstallment';
1604     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
1605     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
1606     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
1607 
1608     -- Standard Start of API savepoint
1609     SAVEPOINT getInstallment;
1610 
1611     -- Standard call to check for call compatibility.
1612     IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
1613                                         l_api_name, G_PKG_NAME)
1614     THEN
1615         RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1616     END IF;
1617 
1618     -- Initialize message list IF p_init_msg_list is set to TRUE.
1619     IF FND_API.to_Boolean(p_init_msg_list) THEN
1620         FND_MSG_PUB.initialize;
1621     END IF;
1622 
1623     -- Initialize API return status to SUCCESS
1624     x_return_status := FND_API.G_RET_STS_SUCCESS;
1625 
1626     -- --------------------------------------------------------------------
1627     -- Api body
1628     -- --------------------------------------------------------------------
1629     l_total_fees                         := 0;
1630     l_amortization_rec.principal_amount  := 0;
1631     l_amortization_rec.interest_amount   := 0;
1632     l_amortization_rec.total             := 0;
1633     l_amortization_rec.fee_amount        := 0;
1634     l_amortization_rec.other_amount      := 0;
1635     l_amortization_rec.begin_balance     := 0;
1636     l_amortization_rec.end_balance       := 0;
1637 
1638     -- move logic for billing custom loans into FINANCIALS API
1639     l_loan_Details := lns_financials.getLoanDetails(p_loan_id, 'CURRENT', 'TERM');
1640 
1641     if l_loan_details.custom_schedule = 'N' then
1642 
1643         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan is not customized');
1644         if l_loan_details.reamortize_overpay = 'Y' then
1645             -- preProcess will add a re-amortization row if the remaining amount < funded amount
1646             -- bug# 5664316 11-23-2006
1647             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling preProcessInstallment...');
1648             preProcessInstallment(p_api_version    => 1.0
1649                 ,p_init_msg_list  => p_init_msg_list
1650                 ,p_commit         => p_commit
1651                 ,p_loan_ID        => p_loan_id
1652                 ,p_installment_number => lns_billing_util_pub.last_payment_number(p_loan_id)
1653                 ,x_amortization_rec => l_amortization_rec
1654                 ,x_return_status  => l_return_status
1655                 ,x_msg_count      => l_msg_count
1656                 ,x_msg_data       => l_msg_data);
1657         end if;
1658 
1659         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling amortizeLoan....');
1660         lns_financials.amortizeLoan(p_loan_Id            => p_loan_id
1661                                    ,p_installment_number => p_installment_number
1662                                    ,p_based_on_terms     => 'CURRENT'
1663                                    ,x_loan_amort_tbl     => l_amortization_tbl);
1664 
1665         for p in 1..l_amortization_tbl.count loop
1666             if l_amortization_tbl(p).installment_number = p_installment_number then
1667                 l_amortization_rec := l_amortization_tbl(p);
1668                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Found installment ' || p_installment_number);
1669                 exit;
1670             end if;
1671         end loop;
1672 
1673     else -- this is a customized loan
1674 
1675         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan is customized');
1676         if p_installment_number > 0 then
1677 
1678             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling LNS_CUSTOM_PUB.loadCustomSchedule....');
1679              -- load custom schedule
1680             LNS_CUSTOM_PUB.loadCustomSchedule(
1681                 P_API_VERSION		    => 1.0,
1682                 P_INIT_MSG_LIST		    => FND_API.G_TRUE,
1683                 P_COMMIT		        => FND_API.G_FALSE,
1684                 P_VALIDATION_LEVEL	    => FND_API.G_VALID_LEVEL_FULL,
1685                 P_LOAN_ID               => p_loan_id,
1686                 P_BASED_ON_TERMS        => 'CURRENT',
1687                 X_CUSTOM_SET_REC        => l_CUSTOM_SET_REC,
1688                 X_CUSTOM_TBL            => l_custom_tbl,
1689                 x_return_status         => l_return_status,
1690                 x_msg_count             => l_msg_count,
1691                 x_msg_data              => l_msg_data);
1692 
1693             IF l_return_status <> 'S' THEN
1694                 RAISE FND_API.G_EXC_ERROR;
1695             END IF;
1696 
1697             for p in 1..l_custom_tbl.count loop
1698 
1699                 if l_custom_tbl(p).PAYMENT_NUMBER = p_installment_number then
1700                     l_amortization_rec.installment_number   := l_custom_tbl(p).PAYMENT_NUMBER;
1701                     l_amortization_rec.due_date             := l_custom_tbl(p).DUE_DATE;
1702                     l_amortization_rec.PERIOD_START_DATE    := l_custom_tbl(p).PERIOD_START_DATE;
1703                     l_amortization_rec.PERIOD_END_DATE      := l_custom_tbl(p).PERIOD_END_DATE;
1704                     l_amortization_rec.principal_amount     := l_custom_tbl(p).PRINCIPAL_AMOUNT;
1705                     l_amortization_rec.interest_amount      := l_custom_tbl(p).INTEREST_AMOUNT;
1706                     l_amortization_rec.begin_balance        := l_custom_tbl(p).INSTALLMENT_BEGIN_BALANCE;
1707                     l_amortization_rec.end_balance          := l_custom_tbl(p).INSTALLMENT_END_BALANCE;
1708                     l_amortization_rec.UNPAID_PRIN          := l_custom_tbl(p).UNPAID_PRIN;
1709                     l_amortization_rec.UNPAID_INT           := l_custom_tbl(p).UNPAID_INT;
1710                     l_amortization_rec.INTEREST_RATE        := l_custom_tbl(p).INTEREST_RATE;
1711                     l_amortization_rec.NORMAL_INT_AMOUNT    := l_custom_tbl(p).NORMAL_INT_AMOUNT;
1712                     l_amortization_rec.ADD_PRIN_INT_AMOUNT  := l_custom_tbl(p).ADD_PRIN_INT_AMOUNT;
1713                     l_amortization_rec.ADD_INT_INT_AMOUNT   := l_custom_tbl(p).ADD_INT_INT_AMOUNT;
1714                     l_amortization_rec.PENAL_INT_AMOUNT     := l_custom_tbl(p).PENAL_INT_AMOUNT;
1715                     l_amortization_rec.FUNDED_AMOUNT        := l_custom_tbl(p).FUNDED_AMOUNT;
1716                     l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_custom_tbl(p).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_custom_tbl(p).PERIOD_END_DATE-1), 1);
1717                     l_amortization_rec.DISBURSEMENT_AMOUNT  := l_custom_tbl(p).DISBURSEMENT_AMOUNT;
1718                     l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := l_custom_tbl(p).PREV_DEFERRED_INT_AMOUNT;
1719                     l_amortization_rec.DEFERRED_INT_AMOUNT  := l_custom_tbl(p).DEFERRED_INT_AMOUNT;
1720                     l_amortization_rec.DEFERRED_INT_DETAILS := l_custom_tbl(p).DEFERRED_INT_DETAILS;
1721                     l_amortization_rec.PREV_CAP_INT_AMOUNT  := l_custom_tbl(p).PREV_CAP_INT_AMOUNT;
1722                     l_amortization_rec.CURR_CAP_INT_AMOUNT  := l_custom_tbl(p).CURR_CAP_INT_AMOUNT;
1723                     l_amortization_rec.CAP_INT_AMOUNT       := l_custom_tbl(p).CAP_INT_AMOUNT;
1724                     l_amortization_rec.CAP_INT_DETAILS      := l_custom_tbl(p).CAP_INT_DETAILS;
1725                     l_amortization_rec.EARLY_PAY_CR_AMOUNT  := l_custom_tbl(p).EARLY_PAY_CR_AMOUNT;
1726                     l_amortization_rec.EARLY_PAY_CR_DETAILS := l_custom_tbl(p).EARLY_PAY_CR_DETAILS;
1727                     exit;
1728                 end if;
1729             end loop;
1730         else
1731              l_amortization_rec.begin_balance      := l_loan_details.funded_amount;
1732              l_amortization_rec.due_date           := l_loan_details.loan_start_date;
1733              l_amortization_rec.installment_number := p_installment_number;
1734         end if;
1735     end if;
1736 /*
1737     -- bug # 3839974
1738     if l_amortization_rec.principal_amount > l_loan_details.unbilled_principal then
1739         l_amortization_rec.principal_amount     := l_loan_details.unbilled_principal;
1740         l_amortization_rec.principal_cumulative := l_amortization_rec.principal_cumulative - l_amortization_rec.principal_amount + l_loan_details.unbilled_principal;
1741     end if;
1742 */
1743     l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
1744     l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
1745     l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
1746     l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.requested_amount;
1747     l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
1748     l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
1749     l_fee_basis_tbl(4).fee_basis_name   := 'OVERDUE_PRIN';
1750     l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
1751     l_fee_basis_tbl(5).fee_basis_name   := 'OVERDUE_PRIN_INT';
1752     l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
1753     l_fee_basis_tbl(6).fee_basis_name   := 'IND_DISB_AMT';
1754     l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
1755     l_fee_basis_tbl(7).fee_basis_name   := 'TOTAL_UNDISB_AMT';
1756     l_fee_basis_tbl(7).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
1757     l_fee_basis_tbl(8).fee_basis_name   := 'OVERDUE_INT';
1758     l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
1759     l_fee_basis_tbl(9).fee_basis_name   := 'CURR_LOAN';
1760     l_fee_basis_tbl(9).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT;
1761 
1762     if p_installment_number = 0 or p_installment_number = 1 then
1763         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing origination fees');
1764         l_fee_structures(1).fee_category := 'EVENT';
1765         l_fee_structures(1).fee_type     := 'EVENT_ORIGINATION';
1766         l_fee_structures(1).phase        := l_loan_details.LOAN_PHASE;
1767 
1768         if p_installment_number = 0 then
1769             l_fee_structures(1).FEE_BILLING_OPTION := 'ORIGINATION';
1770         else
1771             l_fee_structures(1).FEE_BILLING_OPTION := 'BILL_WITH_INSTALLMENT';
1772         end if;
1773 
1774         lns_fee_engine.processFees(p_init_msg_list      => FND_API.G_TRUE
1775                                   ,p_commit             => FND_API.G_FALSE
1776                                   ,p_loan_id            => p_loan_id
1777                                   ,p_installment_number => p_installment_number
1778                                   ,p_fee_basis_tbl      => l_fee_basis_tbl
1779                                   ,p_fee_structures     => l_fee_structures
1780                                   ,x_fees_tbl           => l_fees_tbl
1781                                   ,x_return_status      => l_return_Status
1782                                   ,x_msg_count          => l_msg_count
1783                                   ,x_msg_data           => l_msg_data);
1784 
1785         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_return_status = ' || l_return_status);
1786         if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1787             FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1788             FND_MSG_PUB.ADD;
1789             RAISE FND_API.G_EXC_ERROR;
1790         end if;
1791     end if;
1792 
1793     if p_installment_number > 0 then
1794 
1795         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing late fees');
1796         lns_fee_engine.processLateFees(p_loan_id       => p_loan_id
1797                                     ,p_init_msg_list => p_init_msg_list
1798                                     ,p_commit        => 'F'
1799                                     ,p_phase         => l_loan_details.LOAN_PHASE
1800                                     ,x_return_status => l_return_status
1801                                     ,x_msg_count     => l_msg_count
1802                                     ,x_msg_data      => l_msg_data);
1803 
1804         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_return_status = ' || l_return_status);
1805         if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1806             FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1807             FND_MSG_PUB.ADD;
1808             RAISE FND_API.G_EXC_ERROR;
1809         end if;
1810 
1811         l_fee_structures.delete;
1812         l_fees_tbl.delete;
1813         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing recurring fees');
1814         -- add the recurring fees for the installment onto the fee schedule
1815         l_fee_structures(1).fee_category := 'RECUR';
1816         l_fee_structures(1).fee_type     := null;
1817 
1818         lns_fee_engine.processFees(p_init_msg_list      => FND_API.G_TRUE
1819                                   ,p_commit             => FND_API.G_FALSE
1820                                   ,p_loan_id            => p_loan_id
1821                                   ,p_installment_number => p_installment_number
1822                                   ,p_fee_basis_tbl      => l_fee_basis_tbl
1823                                   ,p_fee_structures     => l_fee_structures
1824                                   ,x_fees_tbl           => l_fees_tbl
1825                                   ,x_return_status      => l_return_Status
1826                                   ,x_msg_count          => l_msg_count
1827                                   ,x_msg_data           => l_msg_data);
1828 
1829         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_return_status = ' || l_return_status);
1830         if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1831             FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
1832             FND_MSG_PUB.ADD;
1833             RAISE FND_API.G_EXC_ERROR;
1834         end if;
1835     end if;
1836 
1837     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling lns_fee_engine.getFeeSchedule...');
1838     lns_fee_engine.getFeeSchedule(p_init_msg_list      => FND_API.G_FALSE
1839                                  ,p_loan_id            => p_loan_id
1840                                  ,p_installment_number => p_installment_number
1841 								 ,p_disb_header_id     => null
1842                                  ,p_phase              => 'TERM'
1843                                  ,x_fees_tbl           => l_fees_tbl_1
1844                                  ,x_return_status      => l_return_status
1845                                  ,x_msg_count          => l_msg_count
1846                                  ,x_msg_data           => l_msg_data);
1847 
1848     if l_return_status <> FND_API.G_RET_STS_SUCCESS then
1849         FND_MESSAGE.SET_NAME('LNS', 'LNS_READ_FEE_ERROR');
1850         FND_MSG_PUB.ADD;
1851         RAISE FND_API.G_EXC_ERROR;
1852     end if;
1853 
1854     for k in 1..l_fees_tbl_1.count loop
1855         l_fees_tbl_2(k).FEE_ID            := l_fees_tbl_1(k).FEE_ID;
1856         l_fees_tbl_2(k).FEE_NAME          := l_fees_tbl_1(k).FEE_NAME;
1857         l_fees_tbl_2(k).FEE_AMOUNT        := l_fees_tbl_1(k).FEE_AMOUNT;
1858         l_fees_tbl_2(k).FEE_INSTALLMENT   := l_fees_tbl_1(k).FEE_INSTALLMENT;
1859         l_fees_tbl_2(k).FEE_DESCRIPTION   := l_fees_tbl_1(k).FEE_DESCRIPTION;
1860         l_fees_tbl_2(k).FEE_SCHEDULE_ID   := l_fees_tbl_1(k).FEE_SCHEDULE_ID;
1861         l_fees_tbl_2(k).FEE_WAIVABLE_FLAG := l_fees_tbl_1(k).FEE_WAIVABLE_FLAG;
1862         l_fees_tbl_2(k).WAIVE_AMOUNT      := l_fees_tbl_1(k).WAIVE_AMOUNT;
1863         l_fees_tbl_2(k).BILLED_FLAG       := l_fees_tbl_1(k).BILLED_FLAG;
1864         l_fees_tbl_2(k).ACTIVE_FLAG       := l_fees_tbl_1(k).ACTIVE_FLAG;
1865         l_total_fees                      := l_total_fees + l_fees_tbl_1(k).FEE_AMOUNT;
1866     end loop;
1867     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_fees_tbl_2.count = ' || l_fees_tbl_2.count);
1868 
1869     -- overwrite amortization record returned from amortizationAPI
1870     l_amortization_rec.fee_amount := l_total_fees;
1871     x_fees_tbl                    := l_fees_tbl_2;
1872     x_amortization_rec            := l_amortization_rec;
1873     -- --------------------------------------------------------------------
1874     -- End of API body
1875     -- --------------------------------------------------------------------
1876 
1877     -- Standard check for p_commit
1878     IF FND_API.to_Boolean(p_commit) THEN
1879         COMMIT WORK;
1880     END IF;
1881 
1882     FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
1883     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
1884 
1885     EXCEPTION
1886         WHEN FND_API.G_EXC_ERROR THEN
1887               ROLLBACK TO getInstallment;
1888               x_return_status := FND_API.G_RET_STS_ERROR;
1889               x_msg_count := l_msg_count;
1890               x_msg_data  := l_msg_data;
1891               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1892               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1893 
1894          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1895               ROLLBACK TO getInstallment;
1896               x_return_status := FND_API.G_RET_STS_ERROR;
1897               x_msg_count := l_msg_count;
1898               x_msg_data  := l_msg_data;
1899               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1900               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1901 
1902         WHEN OTHERS THEN
1903               ROLLBACK TO getInstallment;
1904               x_return_status := FND_API.G_RET_STS_ERROR;
1905               x_msg_count := l_msg_count;
1906               x_msg_data  := l_msg_data;
1907               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
1908               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
1909 
1910 end getInstallment;
1911 
1912 
1913 -- created for bug 6599682: EQUALLY SPREAD PRINCIPAL FROM IO PERIODS FOR EPRP LOANS
1914 function get_num_non_ro_instal(p_rate_schedule      in  LNS_FINANCIALS.RATE_SCHEDULE_TBL
1915                                ,p_from_installment in NUMBER
1916                                ,p_to_installment in NUMBER) return NUMBER
1917 is
1918     l_local_rate_schedule   LNS_FINANCIALS.RATE_SCHEDULE_TBL;
1919     l_num_non_ro_payments   number;
1920     l_total_installments    number;
1921     i                       number;
1922     j                       number;
1923     l_api_name              varchar2(30);
1924     l_from_installment      number;
1925 
1926 begin
1927 
1928     l_api_name := 'get_num_non_ro_instal';
1929     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - BEGIN');
1930     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_from_installment=' || p_from_installment);
1931 
1932     l_from_installment := p_from_installment;
1933     if (l_from_installment is null or l_from_installment = 0) then
1934         l_from_installment := 1;
1935     end if;
1936     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_from_installment=' || l_from_installment);
1937 
1938     -- build normal rate schedule table
1939     for i in 1..p_rate_schedule.count loop
1940 
1941         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'rate schedule row ' || i || ': from ' || p_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER || ' to ' || p_rate_schedule(i).END_INSTALLMENT_NUMBER);
1942 
1943         for j in p_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER..p_rate_schedule(i).END_INSTALLMENT_NUMBER loop
1944 
1945             l_local_rate_schedule(j) := p_rate_schedule(i);
1946             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'adding local rate schedule row ' || j);
1947 
1948         end loop;
1949 
1950     end loop;
1951 
1952     l_num_non_ro_payments := 0;
1953     l_total_installments := l_local_rate_schedule.count;
1954 
1955     if p_to_installment is not null then
1956         l_total_installments := p_to_installment;
1957     end if;
1958 
1959     for i in l_from_installment..l_total_installments loop
1960 
1961         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'local rate schedule row ' || i || ': IO ' || l_local_rate_schedule(i).INTEREST_ONLY_FLAG);
1962 
1963         if (l_local_rate_schedule(i).INTEREST_ONLY_FLAG = 'N' or i = l_total_installments) then
1964             l_num_non_ro_payments := l_num_non_ro_payments + 1;
1965             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_num_non_ro_payments ' || l_num_non_ro_payments);
1966         end if;
1967 
1968     end loop;
1969 
1970     if (l_num_non_ro_payments = 0) then
1971         l_num_non_ro_payments := 1;
1972     end if;
1973 
1974     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Result num_payments ' || l_num_non_ro_payments);
1975     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - END');
1976 
1977     return l_num_non_ro_payments;
1978 
1979 end;
1980 
1981 
1982 
1983 /*=========================================================================
1984 || PUBLIC PROCEDURE getOpenInstallment
1985 ||
1986 || DESCRIPTION
1987 ||
1988 || Overview:  returns interest for an installment during openend loan
1989 ||            this is used for the billing concurrent program
1990 ||
1991 || PSEUDO CODE/LOGIC
1992 ||
1993 || PARAMETERS
1994 ||
1995 || Parameter:  p_loan_id => in loanID
1996 ||             p_installment_number = installment
1997 ||
1998 || Return value: AMORTIZATION_REC => contains billing and payment information
1999 ||
2000 || Source Tables:  NA
2001 ||
2002 || Target Tables:  NA
2003 ||
2004 || KNOWN ISSUES
2005 ||
2006 || NOTES
2007 ||      NOTE: api used by Billing Engine
2008 ||
2009 || MODIFICATION HISTORY
2010 || Date                  Author            Description of Changes
2011 || 12/11/2003 12:40PM     raverma           Created
2012 ||
2013  *=======================================================================*/
2014 procedure getOpenInstallment(p_init_msg_list      IN VARCHAR2
2015                             ,p_loan_Id            in number
2016                             ,p_installment_number in number
2017                             ,x_amortization_rec   OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_REC
2018                             ,x_fees_tbl           OUT NOCOPY LNS_FINANCIALS.FEES_TBL
2019                             ,x_return_status      OUT NOCOPY VARCHAR2
2020                             ,x_msg_count          OUT NOCOPY NUMBER
2021                             ,x_msg_data           OUT NOCOPY VARCHAR2)
2022 is
2023   l_amortization_rec      LNS_FINANCIALS.AMORTIZATION_REC;
2024   l_loan_details          LNS_FINANCIALS.LOAN_DETAILS_REC;
2025   l_payment_tbl           LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2026 	l_rate_schedule_tbl     LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2027 	l_rates_tbl             LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2028   l_rate_details          LNS_FINANCIALS.INTEREST_RATE_REC;
2029     l_amortization_tbl      LNS_FINANCIALS.AMORTIZATION_TBL;
2030 
2031   l_count                 NUMBER;
2032   l_return_status         VARCHAR2(1);
2033   l_msg_count             NUMBER;
2034   l_msg_data              VARCHAR2(32767);
2035   l_api_name              varchar2(25);
2036 
2037   l_fees_tbl              LNS_FEE_ENGINE.FEE_CALC_TBL;
2038   l_fees_tbl_1            LNS_FEE_ENGINE.FEE_CALC_TBL;
2039   l_fees_tbl_2            LNS_FINANCIALS.FEES_TBL;
2040   l_total_fees            number;
2041   l_fee_basis_tbl         LNS_FEE_ENGINE.FEE_BASIS_TBL;
2042   l_fee_structures        LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;  -- define what event(s) we are processing fees for
2043   i                       number;
2044 	m	                      number;
2045 	l_wtd_balance						number;
2046 	l_periodic_rate					number;
2047   l_annualized_rate       number;       -- needs to be converted to periodic rate
2048 	l_periodic_interest     number;
2049 	l_periodic_principal	  number;
2050 	l_installments          number;
2051 	l_weigted_rate          number;
2052 	l_days_at_rate					number;
2053 	l_total_days						number;
2054 	l_running_rate					number;
2055 	l_max_date              date;
2056 	l_spread	              number;
2057 	l_rate_schedule_id      number;
2058 	l_rate_to_store         number;
2059   l_raw_rate              number;
2060   l_next_rate_change      date;
2061 
2062 	cursor c_int_rates(p_rate_id number, p_rate_date date) is
2063 	select interest_rate
2064    from lns_int_rate_lines
2065   where start_date_active <= p_rate_date
2066     and end_date_active >= p_rate_date
2067     and interest_rate_id = p_rate_id;
2068 
2069 	cursor c_rate_info(p_loan_id number) is
2070 	select spread
2071 				,rate_id
2072 		from lns_rate_schedules rs
2073 				,lns_terms t
2074 		where t.loan_id = p_loan_id
2075 		  and t.term_id = rs.term_id
2076       and phase = 'OPEN';
2077 begin
2078 
2079     l_api_name              := 'getOpenInstallment';
2080     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2081     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - loan id ' || p_loan_id);
2082     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - instalment# ' || p_installment_number);
2083 
2084     -- Standard Start of API savepoint
2085     SAVEPOINT getOpenInstallment;
2086 
2087     -- Initialize message list IF p_init_msg_list is set to TRUE.
2088     IF FND_API.to_Boolean(p_init_msg_list) THEN
2089         FND_MSG_PUB.initialize;
2090     END IF;
2091 
2092     -- Initialize API return status to SUCCESS
2093     x_return_status := FND_API.G_RET_STS_SUCCESS;
2094 
2095     -- --------------------------------------------------------------------
2096     -- Api body
2097     -- --------------------------------------------------------------------
2098     l_total_fees                         := 0;
2099     l_amortization_rec.principal_amount  := 0;
2100     l_amortization_rec.interest_amount   := 0;
2101     l_amortization_rec.total             := 0;
2102     l_amortization_rec.fee_amount        := 0;
2103     l_amortization_rec.begin_balance     := 0;
2104     l_amortization_rec.end_balance       := 0;
2105 
2106     -- move logic for billing custom loans into FINANCIALS API
2107     l_loan_Details := lns_financials.getLoanDetails(p_loan_id, 'CURRENT', 'OPEN');
2108     l_rates_tbl     := lns_financials.getRateSchedule(p_loan_id, 'OPEN');
2109 
2110     -- call projection API
2111     lns_financials.loanProjection(p_loan_details     => l_loan_Details
2112                                 ,p_based_on_terms  => 'CURRENT'
2113                                 ,p_rate_schedule    => l_rates_tbl
2114                                 ,x_loan_amort_tbl   => l_amortization_tbl);
2115 
2116     for p in 1..l_amortization_tbl.count loop
2117         if l_amortization_tbl(p).installment_number = p_installment_number then
2118             l_amortization_rec := l_amortization_tbl(p);
2119             exit;
2120         end if;
2121     end loop;
2122 
2123     lns_fee_engine.getFeeSchedule(p_init_msg_list      => FND_API.G_FALSE
2124                                  ,p_loan_id            => p_loan_id
2125                                  ,p_installment_number => p_installment_number
2126 								 ,p_disb_header_id     => null
2127                                  ,p_phase              => 'OPEN'
2128                                  ,x_fees_tbl           => l_fees_tbl_1
2129                                  ,x_return_status      => l_return_status
2130                                  ,x_msg_count          => l_msg_count
2131                                  ,x_msg_data           => l_msg_data);
2132 
2133     if l_return_status <> FND_API.G_RET_STS_SUCCESS then
2134         FND_MESSAGE.SET_NAME('LNS', 'LNS_READ_FEE_ERROR');
2135         FND_MSG_PUB.ADD;
2136         RAISE FND_API.G_EXC_ERROR;
2137     end if;
2138 
2139     for k in 1..l_fees_tbl_1.count loop
2140         l_fees_tbl_2(k).FEE_ID            := l_fees_tbl_1(k).FEE_ID;
2141         l_fees_tbl_2(k).FEE_NAME          := l_fees_tbl_1(k).FEE_NAME;
2142         l_fees_tbl_2(k).FEE_AMOUNT        := l_fees_tbl_1(k).FEE_AMOUNT;
2143         l_fees_tbl_2(k).FEE_INSTALLMENT   := l_fees_tbl_1(k).FEE_INSTALLMENT;
2144         l_fees_tbl_2(k).FEE_DESCRIPTION   := l_fees_tbl_1(k).FEE_DESCRIPTION;
2145         l_fees_tbl_2(k).FEE_SCHEDULE_ID   := l_fees_tbl_1(k).FEE_SCHEDULE_ID;
2146         l_fees_tbl_2(k).FEE_WAIVABLE_FLAG := l_fees_tbl_1(k).FEE_WAIVABLE_FLAG;
2147         l_fees_tbl_2(k).WAIVE_AMOUNT      := l_fees_tbl_1(k).WAIVE_AMOUNT;
2148         l_fees_tbl_2(k).BILLED_FLAG       := l_fees_tbl_1(k).BILLED_FLAG;
2149         l_fees_tbl_2(k).ACTIVE_FLAG       := l_fees_tbl_1(k).ACTIVE_FLAG;
2150         l_total_fees                      := l_total_fees + l_fees_tbl_1(k).FEE_AMOUNT;
2151     end loop;
2152 
2153     -- overwrite amortization record returned from amortizationAPI
2154     l_amortization_rec.rate_id         := l_rate_Details.rate_id;
2155     l_amortization_rec.rate_unadj      := l_annualized_rate;
2156     l_amortization_rec.RATE_CHANGE_FREQ:= l_loan_details.OPEN_RATE_CHG_FREQ;
2157     l_amortization_rec.fee_amount      := l_total_fees;
2158     x_fees_tbl                         := l_fees_tbl_2;
2159     x_amortization_rec                 := l_amortization_rec;
2160     -- --------------------------------------------------------------------
2161     -- End of API body
2162     -- --------------------------------------------------------------------
2163 
2164     FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
2165     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
2166 
2167     EXCEPTION
2168         WHEN FND_API.G_EXC_ERROR THEN
2169               ROLLBACK TO getOpenInstallment;
2170               x_return_status := FND_API.G_RET_STS_ERROR;
2171               x_msg_count := l_msg_count;
2172               x_msg_data  := l_msg_data;
2173               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2174               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2175 
2176          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
2177               ROLLBACK TO getOpenInstallment;
2178               x_return_status := FND_API.G_RET_STS_ERROR;
2179               x_msg_count := l_msg_count;
2180               x_msg_data  := l_msg_data;
2181               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2182               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2183 
2184         WHEN OTHERS THEN
2185               ROLLBACK TO getOpenInstallment;
2186               x_return_status := FND_API.G_RET_STS_ERROR;
2187               x_msg_count := l_msg_count;
2188               x_msg_data  := l_msg_data;
2189               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
2190               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
2191 
2192 end getOpenInstallment;
2193 
2194 /*=========================================================================
2195 || PUBLIC PROCEDURE getRatesTable
2196 ||
2197 || DESCRIPTION
2198 ||
2199 || Overview: function will return a table of dates for interest rates
2200 ||
2201 || Parameter: p_index_rate_id => index reference
2202 ||            p_index_date    => date to start pulling rates
2203 ||            p_rate_change_frequency => frequency of rate changes
2204 ||            p_maturity_date  => final date to get rates
2205 ||
2206 || Source Tables:  NA
2207 ||
2208 || Target Tables:
2209 ||
2210 ||
2211 || KNOWN ISSUES
2212 ||
2213 || NOTES
2214 ||
2215 || MODIFICATION HISTORY
2216 || Date                  Author            Description of Changes
2217 || 08/15/2005 11:35AM     raverma           Created
2218  *=======================================================================*/
2219 function getRatesTable(p_index_rate_id           in number
2220                       ,p_index_date              in date
2221                       ,p_rate_change_frequency   in varchar2
2222                       ,p_maturity_date           in date) return LNS_FINANCIALS.RATE_SCHEDULE_TBL is
2223 
2224  l_intial_date  date;
2225  l_rate_date    date;
2226  l_rate         number;
2227  l_Rates_tbl    LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2228  i              number;
2229  l_api_name     varchar2(25);
2230 
2231 begin
2232 
2233 	l_api_name := 'getRatesTable';
2234 
2235 	logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2236 	i := 1;
2237 	l_Rates_tbl(i).begin_date  := p_index_date;
2238 	l_rate_date := p_index_date;
2239 	logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_index_date ' || p_index_date);
2240 	logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_rate_change_frequency ' || p_rate_change_frequency);
2241 	logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_maturity_date ' || p_maturity_date           );
2242 	logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_index_rate_id ' || p_index_rate_id           );
2243 
2244   WHILE l_rate_date <= p_maturity_date LOOP
2245        l_rate_date               := lns_fin_utils.getNextDate(l_rate_date, p_rate_change_frequency, 1);
2246 			 i                         := i + 1;
2247        l_Rates_tbl(i).begin_date := l_rate_date;
2248 			 --logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_date ' || l_rate_date);
2249   END LOOP;
2250 	/*
2251 	for k in 1..l_Rates_tbl.count loop
2252 				dbms_output.put_line(l_Rates_tbl(k).begin_date);
2253 	end loop;
2254 	 */
2255   logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
2256 	return l_Rates_tbl;
2257 
2258 end getRatesTable;
2259 
2260 
2261 -- created for bug 6498771
2262 function get_remain_num_prin_instal(p_payment_tbl in LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL
2263                                     ,p_from_installment in NUMBER) return NUMBER
2264 is
2265     l_num_prin_payments     number;
2266     l_total_installments    number;
2267     i                       number;
2268 begin
2269 
2270     -- loop throught the amortization schedule and count number of PRIN and PRIN_INT rows
2271     l_num_prin_payments := 0;
2272     l_total_installments := p_payment_tbl.count;
2273     for i in p_from_installment..l_total_installments loop
2274         if (p_payment_tbl(i).CONTENTS = 'PRIN' or p_payment_tbl(i).CONTENTS = 'PRIN_INT') then
2275             l_num_prin_payments := l_num_prin_payments + 1;
2276         end if;
2277     end loop;
2278 
2279     return l_num_prin_payments;
2280 
2281 end;
2282 
2283 
2284 /*=========================================================================
2285 || PUBLIC PROCEDURE amortizeSIPLoan
2286 ||
2287 || DESCRIPTION
2288 ||
2289 || Overview: procedure generates seperate interest and principal amortization
2290 ||           this is the main calculation API for amortization
2291 ||            THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
2292 ||           1. Amortization UI - when creating a loan
2293 ||           2. Billing Engine  - to generate installment bills
2294 ||
2295 || Parameter: p_loan_details  = details of the loan
2296 ||            p_rate_schedule = rate schedule for the loan
2297 ||            p_installment_number => billing will pass in an installment
2298 ||                                    number to generate a billt
2299 ||            x_loan_amort_tbl => table of amortization records
2300 ||
2301 || Source Tables:  NA
2302 ||
2303 || Target Tables:  LNS_TEMP_AMORTIZATIONS
2304 ||
2305 ||
2306 || KNOWN ISSUES
2307 ||
2308 || NOTES
2309 ||
2310 || MODIFICATION HISTORY
2311 ||
2312 || Date                  Author            Description of Changes
2313 || 10/08/2007            scherkas          Created: fix for bug 6498771
2314 || 16/01/2008            scherkas          Fixed bug 6749924
2315 || 08/04/2008            scherkas          Fixed bug 6945153: change procedure to query past installments
2316 || 18/06/2008            scherkas          Fixed bug 7184830
2317  *=======================================================================*/
2318 procedure amortizeSIPLoan(p_loan_details       in  LNS_FINANCIALS.LOAN_DETAILS_REC
2319                       ,p_rate_schedule      in  LNS_FINANCIALS.RATE_SCHEDULE_TBL
2320                       ,p_based_on_terms     in  varchar2
2321                       ,p_installment_number in  number
2322                       ,x_loan_amort_tbl     out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
2323 is
2324     l_return_status                  varchar2(1);
2325     l_msg_count                      NUMBER;
2326     l_msg_data                       VARCHAR2(32767);
2327     l_loan_id                        number;
2328     l_original_loan_amount           number;  -- loan amount
2329     l_amortized_term                 number;
2330     l_loan_term                      number;
2331     l_amortized_term_period          varchar2(30);
2332     l_amortization_frequency         varchar2(30);
2333     l_loan_period_number             number;
2334     l_loan_period_type               varchar2(30);
2335     l_first_payment_date             date;
2336     l_pay_in_arrears                 boolean;
2337     l_payment_frequency              varchar2(30);
2338     l_day_count_method               varchar2(30);
2339     l_interest_comp_freq             varchar2(30);
2340     l_calculation_method             varchar2(30);
2341     l_reamortize_from_installment    number;
2342     l_reamortize_amount              number;
2343     l_annualized_rate                number;  -- annual rate on the loan
2344     l_intervals_remaining            number;
2345     l_rate_details                   LNS_FINANCIALS.INTEREST_RATE_REC;
2346     l_current_rate_id                number;
2347     l_previous_rate_id               number;
2348     l_precision                      number;
2349 
2350     l_period_start_Date              date;
2351     l_period_end_date                date;
2352     l_periodic_rate                  number;
2353     l_maturity_date                  date;
2354     l_amortized_maturity_date        date;
2355 
2356     l_amortization_rec               LNS_FINANCIALS.AMORTIZATION_REC;
2357     l_amortization_tbl               LNS_FINANCIALS.AMORTIZATION_TBL;
2358     l_rate_tbl                       LNS_FINANCIALS.RATE_SCHEDULE_TBL;
2359     l_payment_tbl                    LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2360     l_principal_tbl                  LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
2361     l_loan_start_date                date;
2362     l_num_pay_dates                  number;  -- number of dates on installment schedule
2363     l_periodic_payment               number;
2364     l_periodic_principal             number;
2365     l_periodic_interest              number;
2366     l_interest_based_on_amount       number;  -- do we calculate interest from actual or predicted remaining balance
2367     l_pay_date                       date;
2368     l_total_principal                number;
2369     l_payment_number                 number;
2370     l_fee_amount                     number;
2371     l_fee_amount1                    number;
2372     l_other_amount                   number;
2373     l_begin_balance                  number;
2374     l_end_balance                    number;
2375     l_unbilled_principal             number;
2376     l_unpaid_principal               number;
2377     l_unpaid_interest                number;
2378 
2379     l_remaining_balance_actual       number;
2380     l_remaining_balance_theory       number;
2381     l_total                          number;
2382     l_interest_cumulative            number;
2383     l_principal_cumulative           number;
2384     l_fees_cumulative                number;
2385     l_other_cumulative               number;
2386     i                                number;
2387     l_installment_number             number;
2388     l_billing                        boolean;  -- switch to notify if billing is calling API
2389     l_api_name                       varchar2(20);
2390     l_last_installment_billed        number;
2391     l_rate_to_calculate              number;
2392     l_previous_annualized            number;
2393     l_interest_only_flag             varchar2(1);
2394     l_calc_method                    varchar2(30);
2395     l_compound_freq                  varchar2(30);
2396     l_interest                       number;
2397     l_hidden_cumul_interest          number;
2398     l_num_prin_payments              number;
2399     l_hidden_periodic_prin           number;
2400     l_prin_first_pay_date            date;
2401     l_prin_payment_frequency         varchar2(30);
2402     l_prin_intervals                 number;
2403     l_prin_pay_in_arrears            boolean;
2404     l_prin_amortized_intervals       number;
2405     l_prin_intervals_diff            number;
2406     l_remaining_balance_actual1      number;
2407     l_extend_from_installment        number;
2408     l_norm_interest                  number;
2409     l_add_prin_interest              number;
2410     l_add_int_interest               number;
2411     l_add_start_date                 date;
2412     l_add_end_date                   date;
2413     l_start_installment              number;
2414     l_end_installment                number;
2415     l_first_installment_billed       number;
2416     l_hidden_cumul_norm_int          number;
2417     l_hidden_cumul_add_prin_int      number;
2418     l_hidden_cumul_add_int_int       number;
2419     l_hidden_cumul_penal_int         number;
2420     l_periodic_norm_int              number;
2421     l_periodic_add_prin_int          number;
2422     l_periodic_add_int_int           number;
2423     l_periodic_penal_int             number;
2424     l_penal_prin_interest            number;
2425     l_penal_int_interest             number;
2426     l_penal_interest                 number;
2427     l_prev_grace_end_date            date;
2428     l_raw_rate                       number;
2429     l_balloon_amount                 number;
2430     l_remaining_balance              number;
2431     l_disb_header_id                 number;
2432     l_billed                         varchar2(1);
2433     n                                number;
2434     l_sum_periodic_principal         number;
2435     l_date1                          date;
2436     l_billed_principal               number;
2437     l_detail_int_calc_flag           boolean;
2438     l_increased_amount               number;
2439     l_increased_amount1              number;
2440     l_begin_funded_amount            number;
2441     l_end_funded_amount              number;
2442     l_increase_amount_instal         number;
2443     l_prev_increase_amount_instal    number;
2444     l_begin_funded_amount_new        number;
2445     l_begin                          number;
2446     l_last_prin_installment          number;
2447     l_fund_sched_count               number;
2448     l_wtd_balance                    number;
2449     l_balance1                       number;
2450     l_balance2                       number;
2451     l_remaining_balance_theory1      number;
2452     l_prev_cap_int                   number;
2453     l_early_pay_cr                   number;
2454     l_bill_on_appr_amounts           varchar2(1);
2455 
2456     l_norm_int_detail_str            varchar2(2000);
2457     l_add_prin_int_detail_str        varchar2(2000);
2458     l_add_int_int_detail_str         varchar2(2000);
2459     l_penal_prin_int_detail_str      varchar2(2000);
2460     l_penal_int_int_detail_str       varchar2(2000);
2461     l_penal_int_detail_str           varchar2(2000);
2462     l_hid_cumul_norm_int_dtl_str     varchar2(2000);
2463     l_cap_int_detail_str             varchar2(2000);
2464     l_early_pay_cr_detail_str        varchar2(2000);
2465 
2466     l_fees_tbl                       LNS_FEE_ENGINE.FEE_CALC_TBL;
2467     l_fee_basis_tbl                  LNS_FEE_ENGINE.FEE_BASIS_TBL;
2468     l_int_freq_schedule_tbl          LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
2469     l_prin_freq_schedule_tbl         LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
2470     l_PRIN_FREQUENCY_REC             LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
2471     l_INT_FREQUENCY_REC              LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
2472     l_current_prin_pay_freq          varchar2(30);
2473     l_prev_prin_pay_freq             varchar2(30);
2474 
2475     -- get last bill date
2476     cursor c_get_last_bill_date(p_loan_id number, p_installment_number number)  is
2477         select ACTIVITY_DATE
2478         from LNS_PRIN_TRX_ACTIVITIES_V
2479         where loan_id = p_loan_id
2480         and PAYMENT_NUMBER = p_installment_number
2481         and PARENT_AMORTIZATION_ID is null
2482         and ACTIVITY_CODE in ('BILLING', 'START');
2483 
2484     -- get last billed principal info
2485     cursor c_get_last_payment(p_loan_id number, p_installment_number number)  is
2486         select PRINCIPAL_AMOUNT, PAYMENT_NUMBER
2487         from lns_amortization_scheds
2488         where loan_id = p_loan_id
2489         and PAYMENT_NUMBER > 0
2490         and PAYMENT_NUMBER <= p_installment_number
2491         and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
2492         and PARENT_AMORTIZATION_ID is null
2493         and REAMORTIZE_TO_INSTALLMENT is null
2494         and PRINCIPAL_AMOUNT > 0
2495         and nvl(PHASE, 'TERM') = 'TERM'
2496         order by PAYMENT_NUMBER desc;
2497 
2498     -- get infor from last billed installment
2499     cursor c_get_funded_amount(p_loan_id number, p_installment_number number)  is
2500         select FUNDED_AMOUNT, nvl(CAP_INT_AMOUNT, 0)
2501         from LNS_AMORTIZATION_SCHEDS
2502         where loan_id = p_loan_id
2503         and PAYMENT_NUMBER = p_installment_number
2504         and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
2505         and PARENT_AMORTIZATION_ID is null
2506         and nvl(PHASE, 'TERM') = 'TERM';
2507 
2508     cursor c_fund_sched_exist(p_loan_id number)  is
2509         select decode(loan.loan_class_code,
2510             'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
2511             'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
2512         from lns_loan_headers_all loan
2513         where loan.loan_id = p_loan_id;
2514 
2515     cursor c_get_bill_opt(p_loan_id number) is
2516         select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
2517         from lns_loan_headers_all
2518         where loan_id = p_loan_id;
2519 
2520 begin
2521 
2522     -- initialize all variables
2523     l_api_name                       := 'amortizeSIPLoan MAIN';
2524 
2525     l_original_loan_amount           := 0;  -- loan amount
2526     l_loan_period_number             := 0;
2527     l_previous_rate_id               := -1;
2528     l_previous_annualized            := -1;
2529     l_periodic_payment               := 0;
2530     l_periodic_principal             := 0;
2531     l_periodic_interest              := 0;
2532 	l_balloon_amount                 := 0;
2533     l_total_principal                := 0;
2534     l_payment_number                 := 0;
2535     l_fee_amount                     := 0;
2536     l_other_amount                   := 0;
2537     l_begin_balance                  := 0;
2538     l_unbilled_principal             := 0;
2539     l_unpaid_principal               := 0;
2540     l_remaining_balance_actual       := 0;
2541     l_remaining_balance_theory       := 0;
2542     l_total                          := 0;
2543     l_interest_cumulative            := 0;
2544     l_principal_cumulative           := 0;
2545     l_fees_cumulative                := 0;
2546     l_other_cumulative               := 0;
2547     i                                := 0;
2548     l_installment_number             := 1;  -- begin from #1 installment, NOT #0 installment
2549     l_rate_to_calculate              := 0;
2550     l_billing                        := false;  -- switch to notify if billing is calling API
2551     l_hidden_cumul_interest          := 0;
2552     l_hidden_periodic_prin           := 0;
2553 
2554     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
2555     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
2556     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
2557 
2558     l_loan_term                     := p_loan_details.loan_term;
2559     l_amortized_term                := p_loan_details.amortized_term;
2560     l_amortized_term_period         := p_loan_details.amortized_term_period;
2561     l_amortization_frequency        := p_loan_details.amortization_frequency;
2562     l_payment_frequency             := p_loan_details.payment_frequency;
2563     l_first_payment_date            := p_loan_details.first_payment_date;
2564     l_original_loan_amount          := p_loan_details.requested_amount;
2565     l_remaining_balance_actual      := p_loan_details.remaining_balance;
2566     l_remaining_balance_actual1     := p_loan_details.remaining_balance;
2567     l_maturity_date                 := p_loan_details.maturity_date;
2568 	l_balloon_amount                := p_loan_details.balloon_payment_amount;
2569     l_last_installment_billed       := p_loan_details.last_installment_billed;
2570     l_day_count_method              := p_loan_details.day_count_method;
2571     l_loan_start_date               := p_loan_details.loan_start_date;
2572     l_pay_in_arrears                := p_loan_details.pay_in_arrears_boolean;
2573     l_precision                     := p_loan_details.currency_precision;
2574     l_reamortize_from_installment   := p_loan_details.reamortize_from_installment;
2575     l_reamortize_amount             := p_loan_details.reamortize_amount;
2576     l_loan_id                       := p_loan_details.loan_id;
2577     l_calc_method                   := p_loan_details.CALCULATION_METHOD;
2578     l_compound_freq                 := p_loan_details.INTEREST_COMPOUNDING_FREQ;
2579     l_prin_first_pay_date           := p_loan_details.PRIN_FIRST_PAY_DATE;
2580     l_prin_payment_frequency        := p_loan_details.PRIN_PAYMENT_FREQUENCY;
2581     l_prin_pay_in_arrears           := p_loan_details.PRIN_PAY_IN_ARREARS_BOOL;
2582     l_extend_from_installment       := p_loan_details.EXTEND_FROM_INSTALLMENT;
2583 
2584     -- get the interest rate schedule
2585     l_rate_tbl := p_rate_schedule;
2586     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
2587 
2588     -- get payment schedule
2589     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
2590 
2591     l_int_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
2592                                         P_LOAN_ID           => l_loan_id,
2593                                         P_PHASE             => 'TERM',
2594                                         P_COMPONENT         => 'INT');
2595 
2596     l_prin_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
2597                                         P_LOAN_ID           => l_loan_id,
2598                                         P_PHASE             => 'TERM',
2599                                         P_COMPONENT         => 'PRIN');
2600 
2601     l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
2602                              p_loan_start_date      => l_loan_start_date,
2603                              p_loan_maturity_date  => l_maturity_date,
2604                              p_prin_freq_schedule_tbl => l_prin_freq_schedule_tbl,
2605                              p_int_freq_schedule_tbl => l_int_freq_schedule_tbl);
2606 /*
2607     l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
2608                              p_loan_start_date      => l_loan_start_date
2609                              ,p_loan_maturity_date  => l_maturity_date
2610                              ,p_int_first_pay_date  => l_first_payment_date
2611                              ,p_int_num_intervals   => null --l_intervals
2612                              ,p_int_interval_type   => l_payment_frequency
2613                              ,p_int_pay_in_arrears  => l_pay_in_arrears
2614                              ,p_prin_first_pay_date => l_prin_first_pay_date
2615                              ,p_prin_num_intervals  => null --l_prin_intervals
2616                              ,p_prin_interval_type  => l_prin_payment_frequency
2617                              ,p_prin_pay_in_arrears => l_prin_pay_in_arrears);
2618 */
2619     l_num_pay_dates := l_payment_tbl.count;
2620 
2621     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
2622 
2623     -- get amortize principal schedule
2624     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting principal schedule');
2625 
2626     l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
2627                                                     ,p_loan_maturity_date => l_maturity_date
2628                                                     ,p_freq_schedule_tbl => l_prin_freq_schedule_tbl);
2629 
2630 /*
2631     l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
2632                                                     ,p_loan_maturity_date => l_maturity_date
2633                                                     ,p_first_pay_date     => l_prin_first_pay_date
2634                                                     ,p_num_intervals      => null --l_intervals
2635                                                     ,p_interval_type      => l_prin_payment_frequency
2636                                                     ,p_pay_in_arrears     => l_prin_pay_in_arrears);
2637 */
2638     l_prin_intervals := l_principal_tbl.count;
2639     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-  principal schedule count = ' || l_prin_intervals);
2640 
2641     if l_loan_term <> l_amortized_term then
2642         -- get amortize maturity date
2643         l_amortized_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term         => l_amortized_term
2644                                                             ,p_term_period  => l_amortized_term_period
2645                                                             ,p_frequency    => l_prin_payment_frequency
2646                                                             ,p_start_date   => l_loan_start_date);
2647         -- get amortize principal schedule
2648         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting amortize principal schedule');
2649         l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
2650                                                     ,p_loan_maturity_date => l_amortized_maturity_date
2651                                                     ,p_freq_schedule_tbl => l_prin_freq_schedule_tbl);
2652 /*
2653         l_principal_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
2654                                                         ,p_loan_maturity_date => l_amortized_maturity_date
2655                                                         ,p_first_pay_date     => l_prin_first_pay_date
2656                                                         ,p_num_intervals      => null --l_intervals
2657                                                         ,p_interval_type      => l_prin_payment_frequency
2658                                                         ,p_pay_in_arrears     => l_prin_pay_in_arrears);
2659 */
2660         l_prin_amortized_intervals := l_principal_tbl.count;
2661     else
2662         l_prin_amortized_intervals := l_prin_intervals;
2663     end if;
2664     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- amortize principal schedule count = ' || l_prin_amortized_intervals);
2665 
2666     l_prin_intervals_diff := l_prin_amortized_intervals - l_prin_intervals;
2667     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- l_prin_intervals_diff = ' || l_prin_intervals_diff);
2668 
2669     if p_based_on_terms <> 'CURRENT' then
2670         open c_fund_sched_exist(l_loan_id);
2671         fetch c_fund_sched_exist into l_fund_sched_count;
2672         close c_fund_sched_exist;
2673 
2674         if l_fund_sched_count = 0 then
2675             l_original_loan_amount := p_loan_details.requested_amount;
2676         else
2677             l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
2678         end if;
2679     else
2680         l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
2681     end if;
2682 
2683     l_fees_tbl.delete;
2684     l_fee_amount := 0;
2685 
2686     -- filling out basis table
2687     l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
2688     l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
2689     l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
2690     l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
2691     l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
2692     l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
2693     l_fee_basis_tbl(4).fee_basis_name   := 'TOTAL_UNDISB_AMT';
2694     l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
2695 
2696     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
2697     LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
2698                                 ,p_loan_id        => l_loan_id
2699                                 ,p_installment    => 0
2700                                 ,p_fee_basis_tbl  => l_fee_basis_tbl
2701                                 ,p_based_on_terms => p_based_on_terms
2702                                 ,p_phase          => 'TERM'
2703                                 ,x_fees_tbl       => l_fees_tbl
2704                                 ,x_return_status  => l_return_status
2705                                 ,x_msg_count      => l_msg_count
2706                                 ,x_msg_data       => l_msg_data);
2707 
2708     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
2709     if l_return_status <> 'S' then
2710         RAISE FND_API.G_EXC_ERROR;
2711     end if;
2712 
2713     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
2714 
2715     for k in 1..l_fees_tbl.count loop
2716         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
2717         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
2718         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
2719         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
2720         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
2721         l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
2722     end loop;
2723     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
2724 
2725     if l_fee_amount > 0 then
2726         i := i + 1;
2727         l_amortization_rec.installment_number   := 0;
2728         l_amortization_rec.due_date             := l_loan_start_date;
2729         l_amortization_rec.PERIOD_START_DATE    := l_loan_start_date;
2730         l_amortization_rec.PERIOD_END_DATE      := l_loan_start_date;
2731         l_amortization_rec.principal_amount     := 0;
2732         l_amortization_rec.interest_amount      := 0;
2733         l_amortization_rec.fee_amount           := l_fee_amount;
2734         l_amortization_rec.other_amount         := 0;
2735         l_amortization_rec.begin_balance        := l_original_loan_amount;
2736         l_amortization_rec.end_balance          := l_original_loan_amount;
2737         l_amortization_rec.interest_cumulative  := 0;
2738         l_amortization_rec.principal_cumulative := 0;
2739         l_amortization_rec.fees_cumulative      := l_fee_amount;
2740         l_amortization_rec.other_cumulative     := 0;
2741         l_amortization_rec.rate_id              := 0;
2742         l_amortization_rec.SOURCE               := 'PREDICTED';
2743         l_amortization_rec.total                := l_fee_amount;
2744         l_amortization_rec.UNPAID_PRIN          := 0;
2745         l_amortization_rec.UNPAID_INT           := 0;
2746         l_amortization_rec.INTEREST_RATE        := l_rate_tbl(1).annual_rate;
2747         l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
2748         l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
2749         l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
2750         l_amortization_rec.PENAL_INT_AMOUNT     := 0;
2751         l_amortization_rec.FUNDED_AMOUNT        := l_original_loan_amount;
2752         l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
2753         l_amortization_rec.DISBURSEMENT_AMOUNT  := l_original_loan_amount;
2754         l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := 0;
2755         l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
2756         l_amortization_rec.PREV_CAP_INT_AMOUNT  := 0;
2757         l_amortization_rec.CAP_INT_AMOUNT       := 0;
2758         l_amortization_rec.CAP_INT_DETAILS      := null;
2759         l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
2760 
2761         -- add the record to the amortization table
2762         l_amortization_tbl(i)                   := l_amortization_rec;
2763     end if;
2764 
2765     -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
2766     if p_installment_number is not null then
2767 
2768        l_billing        := true;
2769        if p_installment_number > 0 then
2770 
2771            if p_installment_number > l_num_pay_dates then
2772                 l_payment_number := l_num_pay_dates;
2773            else
2774                 l_payment_number := p_installment_number;
2775            end if;
2776 
2777        else
2778            l_payment_number := p_installment_number;
2779        end if;
2780 
2781     else
2782 
2783        l_payment_number := l_num_pay_dates;
2784 
2785     end if;
2786 
2787     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
2788     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
2789 
2790     l_begin := 1;
2791 
2792     if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
2793 
2794         -- find last installment with billed principal
2795         open c_get_last_payment(l_loan_id, l_last_installment_billed);
2796         fetch c_get_last_payment into l_hidden_periodic_prin, l_last_prin_installment;
2797         close c_get_last_payment;
2798 
2799         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
2800         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_prin_installment = ' || l_last_prin_installment);
2801 
2802         l_begin := 0;
2803         -- find last installment with billed interest
2804         for j in REVERSE 1..l_last_installment_billed loop
2805             if l_payment_tbl(j).CONTENTS <> 'PRIN' then
2806                 l_begin := j;
2807                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': installment ' || j || ' = ' || l_payment_tbl(j).CONTENTS);
2808                 exit;
2809             end if;
2810         end loop;
2811 
2812         l_begin_funded_amount := 0;
2813         if l_begin > 0 then
2814 
2815             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2816             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_begin  || '-----');
2817             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2818 
2819             open c_get_funded_amount(l_loan_id, l_begin);
2820             fetch c_get_funded_amount into l_begin_funded_amount, l_prev_cap_int;
2821             close c_get_funded_amount;
2822 
2823         end if;
2824         l_begin := l_begin + 1;
2825     else
2826         l_remaining_balance_theory := l_original_loan_amount;
2827         l_begin_funded_amount := 0;  --l_original_loan_amount;
2828         l_end_funded_amount := l_original_loan_amount;
2829         l_prev_cap_int := 0;
2830 
2831         open c_get_bill_opt(l_loan_id);
2832         fetch c_get_bill_opt into l_bill_on_appr_amounts;
2833         close c_get_bill_opt;
2834         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
2835     end if;
2836 
2837     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2838     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin = ' || l_begin);
2839     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.REAMORTIZE_ON_FUNDING = ' || p_loan_details.REAMORTIZE_ON_FUNDING);
2840     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
2841 
2842     l_hidden_cumul_norm_int := 0;
2843     l_hidden_cumul_add_prin_int := 0;
2844     l_hidden_cumul_add_int_int := 0;
2845     l_hidden_cumul_interest := 0;
2846     l_hidden_cumul_penal_int := 0;
2847     l_increase_amount_instal := -1;
2848 
2849     if l_begin = 1 then
2850         l_prev_prin_pay_freq := '';
2851     else
2852         LNS_FIN_UTILS.fetchPayFreqRecByDate(
2853             p_FREQUENCY_SCHEDULE => l_prin_freq_schedule_tbl,
2854             p_DATE => l_payment_tbl(l_begin-1).PERIOD_DUE_DATE,
2855             x_FREQUENCY_REC	=> l_PRIN_FREQUENCY_REC);
2856         l_prev_prin_pay_freq := l_PRIN_FREQUENCY_REC.FREQUENCY;
2857     end if;
2858 
2859     -- loop to build the amortization schedule
2860     for l_installment_number in l_begin..l_payment_number
2861     loop
2862 
2863      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2864      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || ' -----');
2865      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
2866 
2867        i := i + 1;
2868        l_periodic_interest      := 0;
2869        l_periodic_norm_int      := 0;
2870        l_periodic_add_prin_int  := 0;
2871        l_periodic_add_int_int   := 0;
2872        l_periodic_penal_int     := 0;
2873        l_periodic_principal     := 0;
2874        l_fee_amount             := 0;
2875        l_other_amount           := 0;
2876        l_unpaid_principal       := 0;
2877        l_unpaid_interest        := 0;
2878        l_intervals_remaining    := l_num_pay_dates - l_installment_number + 1;
2879        l_detail_int_calc_flag   := false;
2880        l_increased_amount       := 0;
2881        l_increased_amount1      := 0;
2882        l_prev_increase_amount_instal := l_increase_amount_instal;
2883 
2884        if l_fund_sched_count > 0 or p_based_on_terms = 'CURRENT' then
2885 
2886             if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number) then
2887 
2888                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 = l_installment_number');
2889 
2890                 l_principal_cumulative := 0;
2891                 l_interest_cumulative  := 0;
2892                 l_fees_cumulative      := 0;
2893                 l_other_cumulative     := 0;
2894                 l_sum_periodic_principal := 0;
2895                 l_billed_principal     := p_loan_details.billed_principal;
2896                 l_unbilled_principal   := p_loan_details.unbilled_principal;
2897                 l_unpaid_principal     := p_loan_details.unpaid_principal;
2898                 l_unpaid_interest      := p_loan_details.UNPAID_INTEREST;
2899 
2900                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
2901                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
2902                     l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
2903                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
2904 
2905                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
2906                     l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
2907                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
2908 
2909                     if l_end_funded_amount > l_begin_funded_amount then
2910                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
2911 
2912                         if l_end_funded_amount = l_begin_funded_amount_new then
2913                             l_increase_amount_instal := l_installment_number;
2914                         else
2915                             if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
2916                                 l_increase_amount_instal := l_installment_number + 1;
2917                             elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
2918                                 l_increase_amount_instal := l_installment_number;
2919                             end if;
2920                         end if;
2921 
2922                     elsif l_begin_funded_amount_new > l_begin_funded_amount then
2923                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new > l_begin_funded_amount');
2924                         l_increase_amount_instal := l_installment_number;
2925                     end if;
2926 
2927                     l_detail_int_calc_flag := true;
2928 
2929                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
2930                     l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
2931                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2932 
2933                     l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
2934                     l_begin_funded_amount := l_begin_funded_amount_new;
2935                     l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
2936                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
2937                     l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal;
2938                 else
2939                     l_remaining_balance_theory := 0;
2940                 end if;
2941 
2942             elsif (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 > l_installment_number) then
2943 
2944                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 > l_installment_number');
2945                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
2946                     open c_get_funded_amount(l_loan_id, l_installment_number);
2947                     fetch c_get_funded_amount into l_end_funded_amount, l_prev_cap_int;
2948                     close c_get_funded_amount;
2949 
2950                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2951                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
2952                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
2953                     if l_end_funded_amount > l_begin_funded_amount then
2954                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
2955                         l_detail_int_calc_flag := true;
2956 
2957                         if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
2958                             l_increase_amount_instal := l_installment_number + 1;
2959                         elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
2960                             l_increase_amount_instal := l_installment_number;
2961                         end if;
2962 
2963                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
2964                         l_remaining_balance_theory := l_begin_funded_amount - l_sum_periodic_principal;
2965                         l_increased_amount := l_end_funded_amount - l_begin_funded_amount_new;
2966                     end if;
2967                 else
2968                     l_remaining_balance_theory := 0;
2969                 end if;
2970 
2971             elsif (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 < l_installment_number) then
2972 
2973                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 < l_installment_number');
2974                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
2975                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
2976                     l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
2977                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
2978 
2979                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
2980                     l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
2981                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
2982 
2983                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
2984                     l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
2985                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
2986 
2987                     if l_end_funded_amount > l_begin_funded_amount then
2988                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
2989                         l_detail_int_calc_flag := true;
2990 
2991                         if l_end_funded_amount = l_begin_funded_amount_new then
2992                             l_increase_amount_instal := l_installment_number;
2993                         else
2994                             if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
2995                                 l_increase_amount_instal := l_installment_number + 1;
2996                             elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
2997                                 l_increase_amount_instal := l_installment_number;
2998                             end if;
2999                         end if;
3000 
3001                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
3002                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
3003 
3004                         l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
3005                         l_begin_funded_amount := l_begin_funded_amount_new;
3006                         l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
3007                         l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal - l_sum_periodic_principal;
3008                     end if;
3009                 else
3010                     l_remaining_balance_theory := 0;
3011                 end if;
3012 
3013             end if;
3014 
3015         elsif l_installment_number = 1 and l_fund_sched_count = 0 and p_based_on_terms <> 'CURRENT' then
3016             l_increased_amount := l_original_loan_amount;
3017         end if;
3018 
3019         if p_loan_details.REAMORTIZE_ON_FUNDING = 'NO' then
3020             l_increase_amount_instal := -1;
3021         end if;
3022 
3023         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3024 
3025         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
3026         l_rate_details := getRateDetails(p_installment => l_installment_number
3027                                         ,p_rate_tbl    => l_rate_tbl);
3028 
3029         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
3030         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
3031         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
3032 
3033         l_current_rate_id             := l_rate_details.rate_id;
3034         l_annualized_rate             := l_rate_details.annual_rate;
3035         l_interest_only_flag          := l_rate_details.interest_only_flag;
3036 
3037         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id = ' || l_current_rate_id);
3038         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag = ' || l_interest_only_flag);
3039         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized = ' || l_previous_annualized);
3040         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate = ' || l_annualized_rate);
3041         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
3042         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
3043         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment = ' || l_extend_from_installment);
3044         if l_detail_int_calc_flag then
3045             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = true');
3046         else
3047             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = false');
3048         end if;
3049         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount = ' || l_increased_amount);
3050         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount1 = ' || l_increased_amount1);
3051         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increase_amount_instal = ' || l_increase_amount_instal);
3052 
3053         -- getting current frequency record
3054         LNS_FIN_UTILS.fetchPayFreqRecByDate(
3055             p_FREQUENCY_SCHEDULE => l_prin_freq_schedule_tbl,
3056             p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
3057             x_FREQUENCY_REC	=> l_PRIN_FREQUENCY_REC);
3058         l_current_prin_pay_freq := l_PRIN_FREQUENCY_REC.FREQUENCY;
3059 
3060         LNS_FIN_UTILS.fetchPayFreqRecByDate(
3061             p_FREQUENCY_SCHEDULE => l_int_freq_schedule_tbl,
3062             p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
3063             x_FREQUENCY_REC	=> l_INT_FREQUENCY_REC);
3064         l_payment_frequency := l_INT_FREQUENCY_REC.FREQUENCY;
3065 
3066         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_prin_pay_freq = ' || l_current_prin_pay_freq);
3067         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_prin_pay_freq = ' || l_prev_prin_pay_freq);
3068         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_frequency = ' || l_payment_frequency);
3069 
3070         -- conditions to recalculate principal payment
3071         -- 1. 1-st installment
3072         -- 2. reamortization from installment = current installment
3073         -- 3. reamortize because loan term has been extended
3074         -- 4. hidden_periodic_prin = 0
3075         -- 5. funded amount has increased since last installment
3076         -- 6. principal payment frequency has changed since last period
3077 
3078         if ((l_installment_number = 1) OR
3079             (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
3080             (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
3081             (l_hidden_periodic_prin = 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
3082             (l_prev_increase_amount_instal = l_installment_number or l_increase_amount_instal = l_installment_number) OR
3083             (l_current_prin_pay_freq <> l_prev_prin_pay_freq))
3084         then
3085 
3086             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- RE-calculating periodic principal payment');
3087 
3088             l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number) + l_prin_intervals_diff;
3089             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_num_prin_payments = ' || l_num_prin_payments);
3090 
3091             l_remaining_balance := l_remaining_balance_theory + l_increased_amount1;
3092 
3093             l_hidden_periodic_prin := lns_financials.calculateEPPayment(p_loan_amount   => l_remaining_balance
3094                                                                     ,p_num_intervals => l_num_prin_payments
3095                                                                     ,p_ending_balance=> l_balloon_amount
3096                                                                     ,p_pay_in_arrears=> l_prin_pay_in_arrears);
3097 
3098             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic principal payment = ' || l_hidden_periodic_prin);
3099 
3100         else
3101             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD principal payment = ' || l_hidden_periodic_prin);
3102         end if;
3103 
3104        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_interest = ' || l_hidden_cumul_interest);
3105        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_norm_int = ' || l_hidden_cumul_norm_int);
3106        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_prin_int = ' || l_hidden_cumul_add_prin_int);
3107        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_int_int = ' || l_hidden_cumul_add_int_int);
3108 
3109        l_norm_interest := 0;
3110        l_add_prin_interest := 0;
3111        l_add_int_interest := 0;
3112        l_penal_prin_interest := 0;
3113        l_penal_int_interest := 0;
3114        l_penal_interest := 0;
3115        l_interest := 0;
3116        l_early_pay_cr := 0;
3117        l_norm_int_detail_str := null;
3118        l_add_prin_int_detail_str := null;
3119        l_add_int_int_detail_str := null;
3120        l_penal_prin_int_detail_str := null;
3121        l_penal_int_int_detail_str := null;
3122        l_penal_int_detail_str := null;
3123        l_early_pay_cr_detail_str := null;
3124 
3125        -- now we will calculate the interest due for this period
3126        if (p_based_on_terms = 'CURRENT' and l_detail_int_calc_flag = true) then
3127 
3128             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
3129             LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
3130                                 p_calc_method => l_calc_method,
3131                                 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3132                                 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
3133                                 p_interest_rate => l_annualized_rate,
3134                                 p_day_count_method => l_day_count_method,
3135                                 p_payment_freq => l_payment_frequency,
3136                                 p_compound_freq => l_compound_freq,
3137                                 p_adj_amount => l_sum_periodic_principal,
3138                                 p_CAP_AMOUNT => l_prev_cap_int,
3139                                 x_norm_interest => l_norm_interest,
3140                                 x_norm_int_details => l_norm_int_detail_str);
3141 
3142             l_norm_interest  := round(l_norm_interest, l_precision);
3143 
3144             if (l_installment_number-1) >= 0 and l_last_installment_billed + 1 = l_installment_number then
3145 
3146                 -- get additional interest start date
3147                 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
3148                 fetch c_get_last_bill_date into l_add_start_date;
3149                 close c_get_last_bill_date;
3150 
3151                 -- get additional interest end date
3152                 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
3153                     l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
3154                 else
3155                     l_add_end_date := sysdate;
3156                 end if;
3157 
3158                 if (l_installment_number-1) > 0 then
3159                     l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
3160                 else
3161                     l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
3162                 end if;
3163 
3164                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
3165                 -- calculate additional interest on unpaid principal
3166                 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
3167                                     p_calc_method => l_calc_method,
3168                                     p_period_start_date => l_add_start_date,
3169                                     p_period_end_date => l_add_end_date,
3170                                     p_interest_rate => l_annualized_rate,
3171                                     p_day_count_method => l_day_count_method,
3172                                     p_payment_freq => l_payment_frequency,
3173                                     p_compound_freq => l_compound_freq,
3174                                     p_prev_grace_end_date => l_prev_grace_end_date,
3175                                     p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
3176                                     p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3177                                     p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
3178                                     p_target => 'UNPAID_PRIN',
3179                                     x_add_interest => l_add_prin_interest,
3180                                     x_penal_interest => l_penal_prin_interest,
3181                                     x_add_int_details => l_add_prin_int_detail_str,
3182                                     x_penal_int_details => l_penal_prin_int_detail_str);
3183                 l_add_prin_interest  := round(l_add_prin_interest, l_precision);
3184 
3185                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
3186                 -- calculate additional interest on unpaid interest
3187                 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
3188                                     p_calc_method => l_calc_method,
3189                                     p_period_start_date => l_add_start_date,
3190                                     p_period_end_date => l_add_end_date,
3191                                     p_interest_rate => l_annualized_rate,
3192                                     p_day_count_method => l_day_count_method,
3193                                     p_payment_freq => l_payment_frequency,
3194                                     p_compound_freq => l_compound_freq,
3195                                     p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
3196                                     p_prev_grace_end_date => l_prev_grace_end_date,
3197                                     p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
3198                                     p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
3199                                     p_target => 'UNPAID_INT',
3200                                     x_add_interest => l_add_int_interest,
3201                                     x_penal_interest => l_penal_int_interest,
3202                                     x_add_int_details => l_add_int_int_detail_str,
3203                                     x_penal_int_details => l_penal_int_int_detail_str);
3204                 l_add_int_interest  := round(l_add_int_interest, l_precision);
3205 
3206                 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
3207                     l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
3208                 else
3209                     l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
3210                 end if;
3211 
3212                 -- calculate interest credit on early payment
3213                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
3214                 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => l_loan_id,
3215                                     p_calc_method => l_calc_method,
3216                                     p_installment => l_installment_number,
3217                                     p_interest_rate => l_previous_annualized,
3218                                     p_day_count_method => l_day_count_method,
3219                                     p_payment_freq => l_payment_frequency,
3220                                     p_compound_freq => l_compound_freq,
3221                                     x_early_pay_cr => l_early_pay_cr,
3222                                     x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
3223 
3224             end if;
3225 
3226        elsif (p_based_on_terms <> 'CURRENT' and l_detail_int_calc_flag = true and l_bill_on_appr_amounts = 'N') then
3227 
3228             if (l_calc_method = 'SIMPLE') then
3229 
3230                 -- recalculate periodic rate for each period if day counting methodolgy varies
3231                 l_periodic_rate := lns_financials.getPeriodicRate(
3232                                             p_payment_freq      => l_payment_frequency
3233                                             ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3234                                             ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
3235                                             ,p_annualized_rate   => l_annualized_rate
3236                                             ,p_days_count_method => l_day_count_method
3237                                             ,p_target            => 'INTEREST');
3238 
3239             elsif (l_calc_method = 'COMPOUND') then
3240 
3241                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
3242                                 ,p_payment_freq => l_payment_frequency
3243                                 ,p_annualized_rate => l_annualized_rate
3244                                 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3245                                 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3246                                 ,p_days_count_method => l_day_count_method
3247                                 ,p_target => 'INTEREST');
3248 
3249             end if;
3250 
3251             lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
3252                                             ,p_from_date        => l_payment_tbl(l_installment_number).period_begin_date
3253                                             ,p_to_date          => l_payment_tbl(l_installment_number).period_end_date
3254                                             ,p_calc_method      => 'TARGET'
3255                                             ,p_phase            => 'TERM'
3256                                             ,p_day_count_method => l_day_count_method
3257                                             ,p_adj_amount       => l_sum_periodic_principal
3258                                             ,x_wtd_balance      => l_wtd_balance
3259                                             ,x_begin_balance    => l_balance1
3260                                             ,x_end_balance      => l_balance2);
3261 
3262             l_wtd_balance := l_wtd_balance + l_prev_cap_int;
3263             l_norm_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
3264                                                                 ,p_periodic_rate => l_periodic_rate
3265                                                                 ,p_compounding_period => null);
3266             l_norm_interest := round(l_norm_interest, l_precision);
3267 
3268             l_norm_int_detail_str := l_norm_interest || ' (' ||
3269                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
3270                 ' * Balance ' || l_wtd_balance ||
3271                 ' * Rate ' || l_annualized_rate || '%)';
3272             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
3273 
3274        else
3275 
3276             l_remaining_balance_theory1 := l_remaining_balance_theory + l_prev_cap_int;
3277             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_theory1);
3278 
3279             if (l_calc_method = 'SIMPLE') then
3280 
3281                 -- recalculate periodic rate for each period if day counting methodolgy varies
3282                 l_periodic_rate := lns_financials.getPeriodicRate(
3283                                             p_payment_freq      => l_payment_frequency
3284                                             ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3285                                             ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
3286                                             ,p_annualized_rate   => l_annualized_rate
3287                                             ,p_days_count_method => l_day_count_method
3288                                             ,p_target            => 'INTEREST');
3289 
3290             elsif (l_calc_method = 'COMPOUND') then
3291 
3292                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
3293                                 ,p_payment_freq => l_payment_frequency
3294                                 ,p_annualized_rate => l_annualized_rate
3295                                 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
3296                                 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
3297                                 ,p_days_count_method => l_day_count_method
3298                                 ,p_target => 'INTEREST');
3299 
3300             end if;
3301 
3302             l_norm_interest := lns_financials.calculateInterest(p_amount => l_remaining_balance_theory1
3303                                                                 ,p_periodic_rate => l_periodic_rate
3304                                                                 ,p_compounding_period => null);
3305             l_norm_interest := round(l_norm_interest, l_precision);
3306 
3307             l_norm_int_detail_str := l_norm_interest || ' (' ||
3308                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
3309                 ' * Balance ' || l_remaining_balance_theory1 ||
3310                 ' * Rate ' || l_annualized_rate || '%)';
3311             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
3312 
3313        end if;
3314 
3315        if l_hidden_cumul_norm_int > 0 then
3316             l_hid_cumul_norm_int_dtl_str := 'Previously Deferred Interest ' || l_hidden_cumul_norm_int ||
3317                 ' +<br>Current Normal Interest ' || l_norm_int_detail_str;
3318        else
3319             l_hid_cumul_norm_int_dtl_str := 'Current Normal Interest ' || l_norm_int_detail_str;
3320        end if;
3321 
3322        l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
3323        l_interest := l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest - l_early_pay_cr;
3324        l_hidden_cumul_norm_int := l_hidden_cumul_norm_int + l_norm_interest;
3325        l_hidden_cumul_add_prin_int := l_hidden_cumul_add_prin_int + l_add_prin_interest;
3326        l_hidden_cumul_add_int_int := l_hidden_cumul_add_int_int + l_add_int_interest;
3327        l_hidden_cumul_interest := l_hidden_cumul_interest + l_interest;
3328        l_hidden_cumul_penal_int := l_hidden_cumul_penal_int + l_penal_interest;
3329 
3330        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_norm_interest = ' || l_norm_interest);
3331        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_prin_interest = ' || l_add_prin_interest);
3332        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_interest = ' || l_add_int_interest);
3333        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
3334        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest = ' || l_interest);
3335 
3336         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CONTENTS = ' || l_payment_tbl(l_installment_number).CONTENTS);
3337 
3338         if (l_payment_tbl(l_installment_number).CONTENTS = 'PRIN') then
3339 
3340             l_periodic_interest := 0;
3341             l_periodic_norm_int := 0;
3342             l_periodic_add_prin_int := 0;
3343             l_periodic_add_int_int := 0;
3344             l_periodic_penal_int := 0;
3345 
3346             l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number);
3347 
3348             if (l_remaining_balance_theory + l_increased_amount1) < l_hidden_periodic_prin then
3349                 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3350                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3351             else
3352                 if (l_num_prin_payments = 1) then
3353                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
3354                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal = ' || l_unbilled_principal);
3355                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3356                     if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
3357                         l_periodic_principal := l_unbilled_principal;
3358                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
3359                     else
3360                         l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3361                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3362                     end if;
3363                 else
3364                     l_periodic_principal := l_hidden_periodic_prin;
3365                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_hidden_periodic_prin');
3366                 end if;
3367            end if;
3368 
3369            if l_hidden_cumul_interest > 0 then
3370                 l_norm_int_detail_str := l_hid_cumul_norm_int_dtl_str || ' <br>' || 'Interest is deferred';
3371            end if;
3372 
3373         elsif (l_payment_tbl(l_installment_number).CONTENTS = 'INT') then
3374 
3375             l_periodic_interest := l_hidden_cumul_interest;
3376             l_periodic_norm_int := l_hidden_cumul_norm_int;
3377             l_periodic_add_prin_int := l_hidden_cumul_add_prin_int;
3378             l_periodic_add_int_int := l_hidden_cumul_add_int_int;
3379             l_periodic_penal_int := l_hidden_cumul_penal_int;
3380             l_hidden_cumul_interest := 0;
3381             l_hidden_cumul_norm_int := 0;
3382             l_hidden_cumul_add_prin_int := 0;
3383             l_hidden_cumul_add_int_int := 0;
3384             l_hidden_cumul_penal_int := 0;
3385             l_periodic_principal := 0;
3386             l_norm_int_detail_str := l_hid_cumul_norm_int_dtl_str;
3387 
3388         else
3389 
3390             l_periodic_interest := l_hidden_cumul_interest;
3391             l_periodic_norm_int := l_hidden_cumul_norm_int;
3392             l_periodic_add_prin_int := l_hidden_cumul_add_prin_int;
3393             l_periodic_add_int_int := l_hidden_cumul_add_int_int;
3394             l_periodic_penal_int := l_hidden_cumul_penal_int;
3395             l_hidden_cumul_interest := 0;
3396             l_hidden_cumul_norm_int := 0;
3397             l_hidden_cumul_add_prin_int := 0;
3398             l_hidden_cumul_add_int_int := 0;
3399             l_hidden_cumul_penal_int := 0;
3400             l_norm_int_detail_str := l_hid_cumul_norm_int_dtl_str;
3401 
3402             l_num_prin_payments := get_remain_num_prin_instal(l_payment_tbl, l_installment_number);
3403 
3404             if (l_remaining_balance_theory + l_increased_amount1) < l_hidden_periodic_prin then
3405                 l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3406                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3407             else
3408                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
3409                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal = ' || l_unbilled_principal);
3410                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3411                 if (l_num_prin_payments = 1) then
3412                     if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
3413                         l_periodic_principal := l_unbilled_principal;
3414                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
3415                     else
3416                         l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
3417                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
3418                     end if;
3419                 else
3420                     l_periodic_principal := l_hidden_periodic_prin;
3421                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_hidden_periodic_prin');
3422                 end if;
3423            end if;
3424 
3425         end if;
3426 
3427         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_norm_int = ' || l_hidden_cumul_norm_int);
3428         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_prin_int = ' || l_hidden_cumul_add_prin_int);
3429         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_add_int_int = ' || l_hidden_cumul_add_int_int);
3430         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_interest = ' || l_hidden_cumul_interest);
3431         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_cumul_penal_int = ' || l_hidden_cumul_penal_int);
3432         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_hidden_periodic_prin = ' || l_hidden_periodic_prin);
3433 
3434         -- round int and prin and calc total
3435         l_periodic_principal := round(l_periodic_principal, l_precision);
3436         l_periodic_interest  := round(l_periodic_interest, l_precision);
3437         l_periodic_payment := l_periodic_principal + l_periodic_interest;
3438 
3439         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': principal = ' || l_periodic_principal);
3440         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest = ' || l_periodic_interest);
3441         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': total = ' || l_periodic_payment);
3442        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
3443 
3444        -- calculate balances and total payment
3445        l_begin_balance        := l_remaining_balance_theory;
3446        l_end_balance          := l_remaining_balance_theory - l_periodic_principal + l_increased_amount1;
3447 
3448        -- check to see if this loan has been billed
3449        if l_unbilled_principal > 0 then
3450          l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
3451        end if;
3452 
3453        -- build the amortization record
3454        l_amortization_rec.installment_number   := l_installment_number;  /* needed to calculate fees */
3455        l_amortization_rec.due_date             := l_payment_tbl(l_installment_number).period_due_date;
3456        l_amortization_rec.PERIOD_START_DATE    := l_payment_tbl(l_installment_number).period_begin_date;
3457        l_amortization_rec.PERIOD_END_DATE      := l_payment_tbl(l_installment_number).period_end_date;
3458        l_amortization_rec.principal_amount     := l_periodic_principal;  /* needed to calculate fees */
3459        l_amortization_rec.interest_amount      := l_periodic_interest;
3460        l_amortization_rec.UNPAID_PRIN          := l_unpaid_principal;
3461        l_amortization_rec.UNPAID_INT           := l_unpaid_interest;
3462        l_amortization_rec.INTEREST_RATE        := l_annualized_rate;
3463        l_amortization_rec.NORMAL_INT_AMOUNT    := l_periodic_norm_int;
3464        l_amortization_rec.ADD_PRIN_INT_AMOUNT  := l_periodic_add_prin_int;
3465        l_amortization_rec.ADD_INT_INT_AMOUNT   := l_periodic_add_int_int;
3466        l_amortization_rec.PENAL_INT_AMOUNT     := l_periodic_penal_int;
3467        l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
3468        l_amortization_rec.DISBURSEMENT_AMOUNT  := l_increased_amount;
3469        l_amortization_rec.FUNDED_AMOUNT        := l_end_funded_amount;
3470        l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := 0;
3471        l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
3472        l_amortization_rec.EARLY_PAY_CR_AMOUNT  := -l_early_pay_cr;
3473 
3474        if l_amortization_rec.FUNDED_AMOUNT is null then
3475             l_amortization_rec.FUNDED_AMOUNT := 0;
3476        end if;
3477 
3478        l_cap_int_detail_str := null;
3479        l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
3480        if p_loan_details.CAPITALIZE_INT = 'Y' then
3481             l_amortization_rec.begin_balance := l_begin_balance + l_prev_cap_int;
3482             if l_end_balance = 0 and l_amortization_rec.interest_amount > 0 then
3483                 l_amortization_rec.end_balance := l_end_balance;
3484                 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_prev_cap_int;
3485                 l_amortization_rec.CAP_INT_AMOUNT := 0;
3486                 l_prev_cap_int := 0;
3487                 l_amortization_rec.interest_amount := l_amortization_rec.interest_amount + l_amortization_rec.PREV_CAP_INT_AMOUNT;
3488             else
3489                 l_amortization_rec.end_balance := l_end_balance + l_prev_cap_int;
3490                 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
3491                 l_amortization_rec.CAP_INT_AMOUNT := l_prev_cap_int + l_amortization_rec.interest_amount;
3492                 if l_amortization_rec.CAP_INT_AMOUNT > 0 then
3493                     if l_prev_cap_int <> 0 then
3494                         l_cap_int_detail_str := 'Previously Capitalized Interest ' || l_prev_cap_int;
3495                     end if;
3496                     if l_norm_interest <> 0 and l_hidden_cumul_interest = 0 then
3497                         if l_cap_int_detail_str is not null then
3498                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3499                         end if;
3500                         l_cap_int_detail_str := l_cap_int_detail_str || l_norm_int_detail_str;
3501                     end if;
3502                     if l_add_prin_interest <> 0 then
3503                         if l_cap_int_detail_str is not null then
3504                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3505                         end if;
3506                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Prin ' || l_add_prin_int_detail_str;
3507                     end if;
3508                     if l_add_int_interest <> 0 then
3509                         if l_cap_int_detail_str is not null then
3510                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3511                         end if;
3512                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Interest ' || l_add_int_int_detail_str;
3513                     end if;
3514                     if l_penal_interest <> 0 then
3515                         if l_cap_int_detail_str is not null then
3516                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
3517                         end if;
3518                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Penal Interest ' || l_penal_interest || ' (' || l_penal_int_detail_str || ')';
3519                     end if;
3520                     if l_early_pay_cr <> 0 then
3521                         if l_cap_int_detail_str is not null then
3522                             l_cap_int_detail_str := l_cap_int_detail_str || ' -<br>';
3523                         end if;
3524                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Int Cr on Early Payment ' || l_early_pay_cr || ' (' || l_early_pay_cr_detail_str || ')';
3525                     end if;
3526                 end if;
3527                 l_prev_cap_int := l_amortization_rec.CAP_INT_AMOUNT;
3528                 if l_amortization_rec.NORMAL_INT_AMOUNT > 0 then
3529                     l_norm_int_detail_str := 'Interest amount is capitalized';
3530                 end if;
3531 
3532                 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_amortization_rec.interest_amount;
3533                 l_amortization_rec.interest_amount      := 0;
3534                 l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
3535                 l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
3536                 l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
3537                 l_amortization_rec.PENAL_INT_AMOUNT     := 0;
3538                 l_amortization_rec.EARLY_PAY_CR_AMOUNT := 0;
3539 
3540                 l_add_prin_int_detail_str := null;
3541                 l_add_int_int_detail_str := null;
3542                 l_penal_prin_int_detail_str := null;
3543                 l_penal_int_int_detail_str := null;
3544                 l_penal_int_detail_str := null;
3545                 l_early_pay_cr_detail_str := null;
3546             end if;
3547        else
3548             l_amortization_rec.begin_balance := l_begin_balance;
3549             l_amortization_rec.end_balance := l_end_balance;
3550             l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
3551             l_amortization_rec.CAP_INT_AMOUNT := 0;
3552             l_prev_cap_int := 0;
3553        end if;
3554         l_amortization_rec.total := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
3555 
3556         l_fees_tbl.delete;
3557         l_fee_amount := 0;
3558         l_other_amount := 0;
3559 
3560         -- filling out basis table
3561         l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
3562         l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
3563         l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
3564         l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
3565         l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
3566         l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
3567         l_fee_basis_tbl(4).fee_basis_name   := 'OVERDUE_PRIN';
3568         l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
3569         l_fee_basis_tbl(5).fee_basis_name   := 'OVERDUE_PRIN_INT';
3570         l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
3571         l_fee_basis_tbl(6).fee_basis_name   := 'IND_DISB_AMT';
3572         l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
3573         l_fee_basis_tbl(7).fee_basis_name   := 'TOTAL_UNDISB_AMT';
3574         l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
3575         l_fee_basis_tbl(8).fee_basis_name   := 'OVERDUE_INT';
3576         l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
3577         l_fee_basis_tbl(9).fee_basis_name   := 'CURR_LOAN';
3578         l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
3579 
3580         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
3581         LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
3582                                     ,p_loan_id        => l_loan_id
3583                                     ,p_installment    => l_installment_number
3584                                     ,p_fee_basis_tbl  => l_fee_basis_tbl
3585                                     ,p_based_on_terms => p_based_on_terms
3586                                     ,p_phase          => 'TERM'
3587                                     ,x_fees_tbl       => l_fees_tbl
3588                                     ,x_return_status  => l_return_status
3589                                     ,x_msg_count      => l_msg_count
3590                                     ,x_msg_data       => l_msg_data);
3591 
3592         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
3593         if l_return_status <> 'S' then
3594             RAISE FND_API.G_EXC_ERROR;
3595         end if;
3596 
3597         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
3598 
3599         for k in 1..l_fees_tbl.count loop
3600             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
3601             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
3602             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
3603             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
3604             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
3605             if l_fees_tbl(k).FEE_CATEGORY = 'MEMO' then
3606                 l_other_amount := l_other_amount + l_fees_tbl(k).FEE_AMOUNT;
3607             else
3608                 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
3609             end if;
3610         end loop;
3611         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for this installment = ' || l_fee_amount);
3612 
3613        l_amortization_rec.fee_amount           := l_fee_amount;
3614        l_amortization_rec.other_amount         := l_other_amount;
3615        l_amortization_rec.total                := l_amortization_rec.total + l_amortization_rec.fee_amount + l_amortization_rec.other_amount;
3616 
3617        -- running totals calculated here
3618        l_principal_cumulative := l_principal_cumulative + l_amortization_rec.principal_amount;
3619        l_interest_cumulative  := l_interest_cumulative + l_amortization_rec.interest_amount;
3620        l_fees_cumulative      := l_fees_cumulative + l_amortization_rec.fee_amount;
3621        l_other_cumulative     := l_other_cumulative + l_amortization_rec.other_amount;
3622 
3623        l_amortization_rec.interest_cumulative  := l_interest_cumulative;
3624        l_amortization_rec.principal_cumulative := l_principal_cumulative;
3625        l_amortization_rec.fees_cumulative      := l_fees_cumulative;
3626        l_amortization_rec.other_cumulative     := l_other_cumulative;
3627        l_amortization_rec.rate_id              := l_current_rate_id;
3628        l_amortization_rec.SOURCE               := 'PREDICTED';
3629 
3630        l_amortization_rec.NORMAL_INT_DETAILS   := l_norm_int_detail_str;
3631        l_amortization_rec.ADD_PRIN_INT_DETAILS := l_add_prin_int_detail_str;
3632        l_amortization_rec.ADD_INT_INT_DETAILS  := l_add_int_int_detail_str;
3633        l_amortization_rec.PENAL_INT_DETAILS    := l_penal_int_detail_str;
3634        l_amortization_rec.CAP_INT_DETAILS      := l_cap_int_detail_str;
3635        l_amortization_rec.EARLY_PAY_CR_DETAILS := l_early_pay_cr_detail_str;
3636 
3637        -- add the record to the amortization table
3638        l_amortization_tbl(i)                   := l_amortization_rec;
3639 
3640        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
3641        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INSTALLMENT ' || l_installment_number);
3642        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
3643        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD = ' || l_amortization_rec.PERIOD);
3644        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_START_DATE = ' || l_amortization_rec.PERIOD_START_DATE);
3645        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_END_DATE = ' || l_amortization_rec.PERIOD_END_DATE);
3646        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'due date = ' || l_amortization_rec.due_date);
3647        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_principal = ' || l_amortization_rec.principal_amount);
3648        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_interest = ' || l_amortization_rec.interest_amount);
3649        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fee_amount = ' || l_amortization_rec.fee_amount);
3650        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_amount = ' || l_amortization_rec.other_amount);
3651        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'total = ' || l_amortization_rec.total);
3652        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'begin_balance = ' || l_amortization_rec.begin_balance);
3653        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'end_balance = ' || l_amortization_rec.end_balance);
3654        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'interest_cumulative = ' || l_amortization_rec.interest_cumulative);
3655        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'principal_cumulative = ' || l_amortization_rec.principal_cumulative);
3656        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fees_cumulative = ' || l_amortization_rec.fees_cumulative);
3657        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_cumulative = ' || l_amortization_rec.other_cumulative);
3658        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'current_rate_id = ' || l_amortization_rec.rate_id );
3659        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_RATE = ' || l_amortization_rec.INTEREST_RATE );
3660        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_PRIN = ' || l_amortization_rec.UNPAID_PRIN );
3661        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_INT = ' || l_amortization_rec.UNPAID_INT );
3662        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
3663        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_AMOUNT = ' || l_amortization_rec.ADD_PRIN_INT_AMOUNT );
3664        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_AMOUNT );
3665        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_AMOUNT = ' || l_amortization_rec.PENAL_INT_AMOUNT );
3666        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FUNDED_AMOUNT = ' || l_amortization_rec.FUNDED_AMOUNT );
3667        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amortization_rec.NORMAL_INT_DETAILS );
3668        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_DETAILS = ' || l_amortization_rec.ADD_PRIN_INT_DETAILS );
3669        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_DETAILS_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_DETAILS );
3670        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_DETAILS = ' || l_amortization_rec.PENAL_INT_DETAILS );
3671        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amortization_rec.PREV_CAP_INT_AMOUNT );
3672        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amortization_rec.CURR_CAP_INT_AMOUNT );
3673        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amortization_rec.CAP_INT_AMOUNT );
3674        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amortization_rec.CAP_INT_DETAILS );
3675        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_AMOUNT = ' || l_amortization_rec.EARLY_PAY_CR_AMOUNT );
3676        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_DETAILS = ' || l_amortization_rec.EARLY_PAY_CR_DETAILS );
3677        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
3678 
3679        l_remaining_balance_theory :=  l_end_balance;
3680        l_sum_periodic_principal := l_sum_periodic_principal + l_periodic_principal;
3681 
3682        l_previous_rate_id            := l_current_rate_id;
3683        l_previous_annualized         := l_annualized_rate;
3684        l_prev_prin_pay_freq          := l_current_prin_pay_freq;
3685 
3686     end loop;
3687 
3688     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT IS ' || l_amortization_tbl.count);
3689     x_loan_amort_tbl := l_amortization_tbl;
3690 
3691     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
3692 
3693  Exception
3694     WHEN FND_API.G_EXC_ERROR THEN
3695          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
3696 
3697     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
3698          logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
3699 
3700     WHEN OTHERS THEN
3701          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
3702 
3703 end amortizeSIPLoan;
3704 
3705 
3706 
3707 /*=========================================================================
3708 || PUBLIC PROCEDURE amortizeEPLoan
3709 ||
3710 || DESCRIPTION
3711 ||
3712 || Overview: this is the main calculation API for EP amortization
3713 ||            THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
3714 ||           1. Amortization UI - when creating a loan
3715 ||           2. Billing Engine  - to generate installment bills
3716 ||
3717 || Parameter: p_loan_details  = details of the loan
3718 ||            p_rate_schedule = rate schedule for the loan
3719 ||            p_installment_number => billing will pass in an installment
3720 ||                                    number to generate a billt
3721 ||            x_loan_amort_tbl => table of amortization records
3722 ||
3723 || Source Tables:  NA
3724 ||
3725 || Target Tables:  LNS_TEMP_AMORTIZATIONS
3726 ||
3727 ||
3728 || KNOWN ISSUES
3729 ||
3730 || NOTES
3731 ||
3732 || MODIFICATION HISTORY
3733 |
3734 | Date                  Author            Description of Changes
3735 || 09/13/2007           scherkas          Created
3736 || 16/01/2008            scherkas          Fixed bug 6749924
3737  *=======================================================================*/
3738 procedure amortizeEPLoan(p_loan_details       in  LNS_FINANCIALS.LOAN_DETAILS_REC
3739                       ,p_rate_schedule      in  LNS_FINANCIALS.RATE_SCHEDULE_TBL
3740                       ,p_based_on_terms     in  varchar2
3741                       ,p_installment_number in  number
3742                       ,x_loan_amort_tbl     out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
3743 is
3744     l_return_status                  varchar2(1);
3745     l_msg_count                      NUMBER;
3746     l_msg_data                       VARCHAR2(32767);
3747     l_loan_id                        number;
3748     l_original_loan_amount           number;  -- loan amount
3749     l_amortized_term                 number;
3750     l_loan_term                      number;
3751     l_amortized_term_period          varchar2(30);
3752     l_amortization_frequency         varchar2(30);
3753     l_loan_period_number             number;
3754     l_loan_period_type               varchar2(30);
3755     l_first_payment_date             date;
3756     l_pay_in_arrears                 boolean;
3757     l_payment_frequency              varchar2(30);
3758     l_day_count_method               varchar2(30);
3759     l_interest_comp_freq             varchar2(30);
3760     l_calculation_method             varchar2(30);
3761     l_reamortize_from_installment    number;
3762     l_reamortize_amount              number;
3763     l_annualized_rate                number;  -- annual rate on the loan
3764     l_intervals_remaining            number;
3765     l_amortization_intervals         number;  -- number of intervals to amortize over
3766     l_rate_details                   LNS_FINANCIALS.INTEREST_RATE_REC;
3767     l_current_rate_id                number;
3768     l_previous_rate_id               number;
3769     l_precision                      number;
3770 
3771     l_period_start_Date              date;
3772     l_period_end_date                date;
3773     l_periodic_rate                  number;
3774     l_maturity_date                  date;
3775     l_amortized_maturity_date        date;
3776 
3777     l_amortization_rec               LNS_FINANCIALS.AMORTIZATION_REC;
3778     l_amortization_tbl               LNS_FINANCIALS.AMORTIZATION_TBL;
3779     l_rate_tbl                       LNS_FINANCIALS.RATE_SCHEDULE_TBL;
3780     l_payment_tbl                    LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
3781     l_amortized_payment_tbl          LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
3782     l_loan_start_date                date;
3783     l_num_pay_dates                  number;  -- number of dates on installment schedule
3784     l_periodic_payment               number;
3785     l_periodic_principal             number;
3786     l_periodic_interest              number;
3787     l_interest_based_on_amount       number;  -- do we calculate interest from actual or predicted remaining balance
3788     l_pay_date                       date;
3789     l_total_principal                number;
3790     l_payment_number                 number;
3791     l_fee_amount                     number;
3792     l_fee_amount1                    number;
3793     l_other_amount                   number;
3794     l_begin_balance                  number;
3795     l_end_balance                    number;
3796     l_unbilled_principal             number;
3797     l_unpaid_principal               number;
3798     l_unpaid_interest                number;
3799 
3800     l_remaining_balance_actual       number;
3801     l_remaining_balance_theory       number;
3802     l_total                          number;
3803     l_interest_cumulative            number;
3804     l_principal_cumulative           number;
3805     l_fees_cumulative                number;
3806     l_other_cumulative               number;
3807     i                                number;
3808     l_installment_number             number;
3809     l_billing                        boolean;  -- switch to notify if billing is calling API
3810     l_api_name                       varchar2(20);
3811     l_last_installment_billed        number;
3812     l_rate_to_calculate              number;
3813     l_previous_annualized            number;
3814     l_previous_interest_only_flag    varchar2(1);
3815     l_interest_only_flag             varchar2(1);
3816     l_calc_method                    varchar2(30);
3817     l_compound_freq                  varchar2(30);
3818     l_non_ro_intervals               number;
3819     l_prev_periodic_principal        number;
3820     l_intervals_diff                 number;
3821     l_remaining_balance_actual1      number;
3822     l_extend_from_installment        number;
3823     l_orig_num_install               number;
3824     l_first_installment_billed       number;
3825     l_begin                          number;
3826     l_norm_interest                  number;
3827     l_add_prin_interest              number;
3828     l_add_int_interest               number;
3829     l_add_start_date                 date;
3830     l_add_end_date                   date;
3831     l_penal_prin_interest            number;
3832     l_penal_int_interest             number;
3833     l_penal_interest                 number;
3834     l_prev_grace_end_date            date;
3835     l_raw_rate                       number;
3836     l_balloon_amount                 number;
3837     l_remaining_balance              number;
3838     l_disb_header_id                 number;
3839     l_billed                         varchar2(1);
3840     n                                number;
3841     l_sum_periodic_principal         number;
3842     l_date1                          date;
3843     l_billed_principal               number;
3844     l_detail_int_calc_flag           boolean;
3845     l_increased_amount               number;
3846     l_increased_amount1              number;
3847     l_begin_funded_amount            number;
3848     l_end_funded_amount              number;
3849     l_increase_amount_instal         number;
3850     l_prev_increase_amount_instal    number;
3851     l_begin_funded_amount_new        number;
3852     l_fund_sched_count               number;
3853     l_wtd_balance                    number;
3854     l_balance1                       number;
3855     l_balance2                       number;
3856     l_remaining_balance_theory1      number;
3857     l_prev_cap_int                   number;
3858     l_early_pay_cr                   number;
3859     l_bill_on_appr_amounts           varchar2(1);
3860 
3861     l_norm_int_detail_str            varchar2(2000);
3862     l_add_prin_int_detail_str        varchar2(2000);
3863     l_add_int_int_detail_str         varchar2(2000);
3864     l_penal_prin_int_detail_str      varchar2(2000);
3865     l_penal_int_int_detail_str       varchar2(2000);
3866     l_penal_int_detail_str           varchar2(2000);
3867     l_cap_int_detail_str             varchar2(2000);
3868     l_early_pay_cr_detail_str        varchar2(2000);
3869 
3870     l_fees_tbl                       LNS_FEE_ENGINE.FEE_CALC_TBL;
3871     l_fee_basis_tbl                  LNS_FEE_ENGINE.FEE_BASIS_TBL;
3872     l_freq_schedule_tbl              LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
3873     l_FREQUENCY_REC                  LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
3874     l_prev_payment_frequency         varchar2(30);
3875 
3876     -- get last bill date
3877     cursor c_get_last_bill_date(p_loan_id number, p_installment_number number)  is
3878         select ACTIVITY_DATE
3879         from LNS_PRIN_TRX_ACTIVITIES_V
3880         where loan_id = p_loan_id
3881         and PAYMENT_NUMBER = p_installment_number
3882         and PARENT_AMORTIZATION_ID is null
3883         and ACTIVITY_CODE in ('BILLING', 'START');
3884 
3885     -- get last billed principal info
3886     cursor c_get_last_payment(p_loan_id number, p_installment_number number)  is
3887         select PRINCIPAL_AMOUNT, FUNDED_AMOUNT, nvl(CAP_INT_AMOUNT, 0)
3888         from lns_amortization_scheds
3889         where loan_id = p_loan_id
3890         and PAYMENT_NUMBER > 0
3891         and PAYMENT_NUMBER <= p_installment_number
3892         and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
3893         and PARENT_AMORTIZATION_ID is null
3894         and REAMORTIZE_TO_INSTALLMENT is null
3895         --and PRINCIPAL_AMOUNT > 0
3896         and nvl(PHASE, 'TERM') = 'TERM'
3897         order by PAYMENT_NUMBER desc;
3898 
3899     cursor c_fund_sched_exist(p_loan_id number)  is
3900         select decode(loan.loan_class_code,
3901             'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
3902             'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
3903         from lns_loan_headers_all loan
3904         where loan.loan_id = p_loan_id;
3905 
3906     cursor c_get_bill_opt(p_loan_id number) is
3907         select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
3908         from lns_loan_headers_all
3909         where loan_id = p_loan_id;
3910 
3911 begin
3912 
3913     -- initialize all variables
3914     l_original_loan_amount           := 0;  -- loan amount
3915     l_loan_period_number             := 0;
3916     l_previous_rate_id               := -1;
3917     l_previous_annualized            := -1;
3918     l_previous_interest_only_flag    := 'N';    -- default to regular interest + principal
3919     l_periodic_payment               := 0;
3920     l_periodic_principal             := 0;
3921     l_periodic_interest              := 0;
3922 	l_balloon_amount                 := 0;
3923     l_total_principal                := 0;
3924     l_payment_number                 := 0;
3925     l_fee_amount                     := 0;
3926     l_other_amount                   := 0;
3927     l_begin_balance                  := 0;
3928     l_unbilled_principal             := 0;
3929     l_unpaid_principal               := 0;
3930     l_remaining_balance_actual       := 0;
3931     l_remaining_balance_theory       := 0;
3932     l_total                          := 0;
3933     l_interest_cumulative            := 0;
3934     l_principal_cumulative           := 0;
3935     l_fees_cumulative                := 0;
3936     l_other_cumulative               := 0;
3937     i                                := 0;
3938     l_installment_number             := 1;  -- begin from #1 installment, NOT #0 installment
3939     l_rate_to_calculate              := 0;
3940     l_billing                        := false;  -- switch to notify if billing is calling API
3941     l_api_name                       := 'amortizeEPLoan MAIN';
3942 
3943     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
3944     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
3945     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
3946 
3947     l_loan_term                     := p_loan_details.loan_term;
3948     l_amortized_term                := p_loan_details.amortized_term;
3949     l_amortized_term_period         := p_loan_details.amortized_term_period;
3950     l_amortization_frequency        := p_loan_details.amortization_frequency;
3951     l_payment_frequency             := p_loan_details.payment_frequency;
3952     l_first_payment_date            := p_loan_details.first_payment_date;
3953     l_original_loan_amount          := p_loan_details.requested_amount; --funded_amount;
3954     l_remaining_balance_actual      := p_loan_details.remaining_balance;
3955     l_remaining_balance_actual1     := p_loan_details.remaining_balance;
3956     l_maturity_date                 := p_loan_details.maturity_date;
3957 	l_balloon_amount                := p_loan_details.balloon_payment_amount;
3958     l_last_installment_billed       := p_loan_details.last_installment_billed;
3959     l_day_count_method              := p_loan_details.day_count_method;
3960     l_loan_start_date               := p_loan_details.loan_start_date;
3961     l_pay_in_arrears                := p_loan_details.pay_in_arrears_boolean;
3962     l_precision                     := p_loan_details.currency_precision;
3963     l_reamortize_from_installment   := p_loan_details.reamortize_from_installment;
3964     l_reamortize_amount             := p_loan_details.reamortize_amount;
3965     l_loan_id                       := p_loan_details.loan_id;
3966     l_calc_method                   := p_loan_details.CALCULATION_METHOD;
3967     l_compound_freq                 := p_loan_details.INTEREST_COMPOUNDING_FREQ;
3968     l_extend_from_installment       := p_loan_details.EXTEND_FROM_INSTALLMENT;
3969     l_orig_num_install              := p_loan_details.ORIG_NUMBER_INSTALLMENTS;
3970 
3971     -- get the interest rate schedule
3972     l_rate_tbl := p_rate_schedule;
3973     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
3974 
3975     -- get payment schedule
3976     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
3977 
3978     l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
3979                                         P_LOAN_ID           => l_loan_id,
3980                                         P_PHASE             => 'TERM',
3981                                         P_COMPONENT         => 'PRIN_INT');
3982 
3983     l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
3984                              p_loan_start_date      => l_loan_start_date,
3985                              p_loan_maturity_date  => l_maturity_date,
3986                              p_freq_schedule_tbl => l_freq_schedule_tbl);
3987 /*
3988     l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
3989                                                        ,p_loan_maturity_date => l_maturity_date
3990                                                        ,p_first_pay_date     => l_first_payment_date
3991                                                        ,p_num_intervals      => null --l_intervals
3992                                                        ,p_interval_type      => l_payment_frequency
3993                                                        ,p_pay_in_arrears     => l_pay_in_arrears);
3994 */
3995     l_num_pay_dates := l_payment_tbl.count;
3996     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
3997 
3998     if l_loan_term <> l_amortized_term then
3999 
4000         -- get amortize maturity date
4001         l_amortized_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term         => l_amortized_term
4002                                                             ,p_term_period  => l_amortized_term_period
4003                                                             ,p_frequency    => l_payment_frequency
4004                                                             ,p_start_date   => l_loan_start_date);
4005         -- get amortize payment schedule
4006         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting amortize payment schedule');
4007 
4008         l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
4009                                             P_LOAN_ID           => l_loan_id,
4010                                             P_PHASE             => 'TERM',
4011                                             P_COMPONENT         => 'PRIN_INT');
4012 
4013         l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
4014                                 p_loan_start_date      => l_loan_start_date,
4015                                 p_loan_maturity_date  => l_amortized_maturity_date,
4016                                 p_freq_schedule_tbl => l_freq_schedule_tbl);
4017 /*
4018         l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
4019                                                         ,p_loan_maturity_date => l_amortized_maturity_date
4020                                                         ,p_first_pay_date     => l_first_payment_date
4021                                                         ,p_num_intervals      => null --l_intervals
4022                                                         ,p_interval_type      => l_payment_frequency
4023                                                         ,p_pay_in_arrears     => l_pay_in_arrears);
4024 */
4025         l_amortization_intervals := l_amortized_payment_tbl.count;
4026     else
4027         l_amortization_intervals := l_num_pay_dates;
4028     end if;
4029     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- amortize payment schedule count: ' || l_amortization_intervals);
4030 
4031     l_intervals_diff := l_amortization_intervals - l_num_pay_dates;
4032 
4033     if p_based_on_terms <> 'CURRENT' then
4034         open c_fund_sched_exist(l_loan_id);
4035         fetch c_fund_sched_exist into l_fund_sched_count;
4036         close c_fund_sched_exist;
4037 
4038         if l_fund_sched_count = 0 then
4039             l_original_loan_amount := p_loan_details.requested_amount;
4040         else
4041             l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
4042         end if;
4043     else
4044         l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
4045     end if;
4046 
4047     l_fees_tbl.delete;
4048     l_fee_amount := 0;
4049 
4050     -- filling out basis table
4051     l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
4052     l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
4053     l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
4054     l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
4055     l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
4056     l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
4057     l_fee_basis_tbl(4).fee_basis_name   := 'TOTAL_UNDISB_AMT';
4058     l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
4059 
4060     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
4061     LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
4062                                 ,p_loan_id        => l_loan_id
4063                                 ,p_installment    => 0
4064                                 ,p_fee_basis_tbl  => l_fee_basis_tbl
4065                                 ,p_based_on_terms => p_based_on_terms
4066                                 ,p_phase          => 'TERM'
4067                                 ,x_fees_tbl       => l_fees_tbl
4068                                 ,x_return_status  => l_return_status
4069                                 ,x_msg_count      => l_msg_count
4070                                 ,x_msg_data       => l_msg_data);
4071 
4072     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
4073     if l_return_status <> 'S' then
4074         RAISE FND_API.G_EXC_ERROR;
4075     end if;
4076 
4077     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
4078 
4079     for k in 1..l_fees_tbl.count loop
4080         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
4081         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
4082         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
4083         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
4084         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
4085         l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
4086     end loop;
4087     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
4088 
4089 
4090     if l_fee_amount > 0 then
4091         i := i + 1;
4092         l_amortization_rec.installment_number   := 0;
4093         l_amortization_rec.due_date             := l_loan_start_date;
4094         l_amortization_rec.PERIOD_START_DATE    := l_loan_start_date;
4095         l_amortization_rec.PERIOD_END_DATE      := l_loan_start_date;
4096         l_amortization_rec.principal_amount     := 0;
4097         l_amortization_rec.interest_amount      := 0;
4098         l_amortization_rec.fee_amount           := l_fee_amount;
4099         l_amortization_rec.other_amount         := 0;
4100         l_amortization_rec.begin_balance        := l_original_loan_amount;
4101         l_amortization_rec.end_balance          := l_original_loan_amount;
4102         l_amortization_rec.interest_cumulative  := 0;
4103         l_amortization_rec.principal_cumulative := 0;
4104         l_amortization_rec.fees_cumulative      := l_fee_amount;
4105         l_amortization_rec.other_cumulative     := 0;
4106         l_amortization_rec.rate_id              := 0;
4107         l_amortization_rec.SOURCE               := 'PREDICTED';
4108         l_amortization_rec.total                := l_fee_amount;
4109         l_amortization_rec.UNPAID_PRIN          := 0;
4110         l_amortization_rec.UNPAID_INT           := 0;
4111         l_amortization_rec.INTEREST_RATE        := l_rate_tbl(1).annual_rate;
4112         l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
4113         l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
4114         l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
4115         l_amortization_rec.PENAL_INT_AMOUNT     := 0;
4116         l_amortization_rec.FUNDED_AMOUNT        := l_original_loan_amount;
4117         l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
4118         l_amortization_rec.DISBURSEMENT_AMOUNT  := l_original_loan_amount;
4119         l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := 0;
4120         l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
4121         l_amortization_rec.PREV_CAP_INT_AMOUNT  := 0;
4122         l_amortization_rec.CAP_INT_AMOUNT       := 0;
4123         l_amortization_rec.CAP_INT_DETAILS      := null;
4124         l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
4125 
4126         -- add the record to the amortization table
4127         l_amortization_tbl(i)                   := l_amortization_rec;
4128     end if;
4129 
4130     -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
4131     if p_installment_number is not null then
4132 
4133        l_billing        := true;
4134        if p_installment_number > 0 then
4135 
4136            if p_installment_number > l_num_pay_dates then
4137                 l_payment_number := l_num_pay_dates;
4138            else
4139                 l_payment_number := p_installment_number;
4140            end if;
4141 
4142        else
4143            l_payment_number := p_installment_number;
4144        end if;
4145 
4146     else
4147 
4148        l_payment_number := l_num_pay_dates;
4149 
4150     end if;
4151 
4152     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
4153     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
4154 
4155     l_begin := 1;
4156 
4157     if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
4158 
4159         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4160         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_last_installment_billed  || '-----');
4161         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4162 
4163         l_periodic_principal := null;
4164         open c_get_last_payment(l_loan_id, l_last_installment_billed);
4165         fetch c_get_last_payment into l_periodic_principal, l_begin_funded_amount, l_prev_cap_int;
4166         close c_get_last_payment;
4167 
4168         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic principal = ' || l_periodic_principal);
4169         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
4170         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
4171 
4172         if l_periodic_principal is not null then
4173 
4174             l_prev_periodic_principal := l_periodic_principal;
4175             l_begin := l_last_installment_billed + 1;
4176 
4177             if l_rate_tbl.count = 1 then
4178                 l_previous_annualized := l_rate_tbl(1).annual_rate;
4179                 l_previous_interest_only_flag := l_rate_tbl(1).interest_only_flag;
4180             else
4181                 l_rate_details := lns_financials.getRateDetails(p_installment => l_last_installment_billed
4182                                                                 ,p_rate_tbl => l_rate_tbl);
4183                 l_previous_annualized := l_rate_details.annual_rate;
4184                 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
4185             end if;
4186 
4187         end if;
4188 
4189     else
4190         l_remaining_balance_theory := l_original_loan_amount;
4191         l_begin_funded_amount := 0;  --l_original_loan_amount;
4192         l_end_funded_amount := l_original_loan_amount;
4193         l_prev_cap_int := 0;
4194 
4195         open c_get_bill_opt(l_loan_id);
4196         fetch c_get_bill_opt into l_bill_on_appr_amounts;
4197         close c_get_bill_opt;
4198         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
4199     end if;
4200 
4201     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin = ' || l_begin);
4202     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.REAMORTIZE_ON_FUNDING = ' || p_loan_details.REAMORTIZE_ON_FUNDING);
4203     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
4204 
4205     l_increase_amount_instal := -1;
4206 
4207     if l_begin = 1 then
4208         l_prev_payment_frequency := '';
4209     else
4210         LNS_FIN_UTILS.fetchPayFreqRecByDate(
4211             p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
4212             p_DATE => l_payment_tbl(l_begin-1).PERIOD_DUE_DATE,
4213             x_FREQUENCY_REC	=> l_FREQUENCY_REC);
4214         l_prev_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
4215     end if;
4216 
4217     -- loop to build the amortization schedule
4218     for l_installment_number in l_begin..l_payment_number
4219     loop
4220 
4221        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4222        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || '-----');
4223        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4224 
4225        i := i + 1;
4226        l_periodic_interest      := 0;
4227 --       l_periodic_principal     := 0;
4228        l_fee_amount             := 0;
4229        l_other_amount           := 0;
4230        l_unpaid_principal       := 0;
4231        l_unpaid_interest        := 0;
4232        l_intervals_remaining    := l_num_pay_dates - l_installment_number + 1;
4233        l_detail_int_calc_flag   := false;
4234        l_increased_amount       := 0;
4235        l_increased_amount1      := 0;
4236        l_prev_increase_amount_instal := l_increase_amount_instal;
4237 
4238        if l_fund_sched_count > 0 or p_based_on_terms = 'CURRENT' then
4239 
4240             if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number) then
4241 
4242                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 = l_installment_number');
4243 
4244                 l_principal_cumulative := 0;
4245                 l_interest_cumulative  := 0;
4246                 l_fees_cumulative      := 0;
4247                 l_other_cumulative     := 0;
4248                 l_sum_periodic_principal := 0;
4249                 l_billed_principal     := p_loan_details.billed_principal;
4250                 l_unbilled_principal   := p_loan_details.unbilled_principal;
4251                 l_unpaid_principal     := p_loan_details.unpaid_principal;
4252                 l_unpaid_interest      := p_loan_details.UNPAID_INTEREST;
4253 
4254                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
4255                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
4256                     l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
4257                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
4258 
4259                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
4260                     l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
4261                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
4262 
4263                     if l_end_funded_amount > l_begin_funded_amount_new then
4264                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
4265 
4266                         if l_end_funded_amount = l_begin_funded_amount_new then
4267                             l_increase_amount_instal := l_installment_number;
4268                         else
4269                             if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
4270                                 l_increase_amount_instal := l_installment_number + 1;
4271                             elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
4272                                 l_increase_amount_instal := l_installment_number;
4273                             end if;
4274                         end if;
4275 
4276                     elsif l_begin_funded_amount_new > l_begin_funded_amount then
4277                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new > l_begin_funded_amount');
4278                         l_increase_amount_instal := l_installment_number;
4279                     end if;
4280 
4281                     l_detail_int_calc_flag := true;
4282 
4283                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
4284                     l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
4285                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
4286 
4287                     l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
4288                     l_begin_funded_amount := l_begin_funded_amount_new;
4289                     l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
4290                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
4291                     l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal;
4292                 else
4293                     l_remaining_balance_theory := 0;
4294                 end if;
4295 
4296             else
4297 
4298                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 < l_installment_number');
4299                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
4300                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
4301                     l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
4302                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
4303 
4304                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
4305                     l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
4306                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
4307 
4308                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
4309                     l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
4310                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
4311 
4312                     if l_end_funded_amount > l_begin_funded_amount then
4313                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
4314                         l_detail_int_calc_flag := true;
4315 
4316                         if l_end_funded_amount = l_begin_funded_amount_new then
4317                             l_increase_amount_instal := l_installment_number;
4318                         else
4319                             if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
4320                                 l_increase_amount_instal := l_installment_number + 1;
4321                             elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
4322                                 l_increase_amount_instal := l_installment_number;
4323                             end if;
4324                         end if;
4325 
4326                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
4327                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
4328 
4329                         l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
4330                         l_begin_funded_amount := l_begin_funded_amount_new;
4331                         l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
4332                         l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal - l_sum_periodic_principal;
4333                     end if;
4334                 else
4335                     l_remaining_balance_theory := 0;
4336                 end if;
4337 
4338             end if;
4339 
4340        elsif l_installment_number = 1 and l_fund_sched_count = 0 and p_based_on_terms <> 'CURRENT' then
4341             l_increased_amount := l_original_loan_amount;
4342        end if;
4343 
4344        if p_loan_details.REAMORTIZE_ON_FUNDING = 'NO' then
4345             l_increase_amount_instal := -1;
4346        end if;
4347 
4348        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
4349 
4350        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
4351        l_rate_details := getRateDetails(p_installment => l_installment_number
4352                                        ,p_rate_tbl    => l_rate_tbl);
4353 
4354        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
4355        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
4356        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
4357 
4358         l_current_rate_id             := l_rate_details.rate_id;
4359         l_annualized_rate             := l_rate_details.annual_rate;
4360         l_interest_only_flag          := l_rate_details.interest_only_flag;
4361 
4362         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_rate_id = ' || l_previous_rate_id);
4363         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id = ' || l_current_rate_id);
4364         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized = ' || l_previous_annualized);
4365         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate = ' || l_annualized_rate);
4366         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_interest_only_flag = ' || l_previous_interest_only_flag);
4367         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag = ' || l_interest_only_flag);
4368         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
4369         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment = ' || l_extend_from_installment);
4370         if l_detail_int_calc_flag then
4371             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = true');
4372         else
4373             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = false');
4374         end if;
4375         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount = ' || l_increased_amount);
4376         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount1 = ' || l_increased_amount1);
4377         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increase_amount_instal = ' || l_increase_amount_instal);
4378 
4379         -- getting current frequency record
4380         LNS_FIN_UTILS.fetchPayFreqRecByDate(
4381             p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
4382             p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
4383             x_FREQUENCY_REC	=> l_FREQUENCY_REC);
4384         l_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
4385 
4386         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_payment_frequency = ' || l_prev_payment_frequency);
4387         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_frequency = ' || l_payment_frequency);
4388 
4389         -- conditions to recalculate principal payment
4390         -- 1. 1-st installment
4391         -- 2. reamortization from installment = current installment
4392         -- 3. reamortize because loan term has been extended
4393         -- 4. emerging from interest only period
4394         -- 5. funded amount has increased since last installment
4395 
4396         if ((l_installment_number = 1) OR
4397             (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
4398             (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
4399             (l_previous_interest_only_flag = 'Y' and  l_interest_only_flag = 'N' and l_prev_periodic_principal = 0) OR
4400             (l_prev_increase_amount_instal = l_installment_number or l_increase_amount_instal = l_installment_number) OR
4401             (l_payment_frequency <> l_prev_payment_frequency))
4402         then
4403 
4404             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- RE-calculating periodic principal payment');
4405 
4406             -- fix for bug 6599682: EQUALLY SPREAD PRINCIPAL FROM IO PERIODS FOR EPRP LOANS
4407             l_non_ro_intervals := get_num_non_ro_instal(l_rate_tbl, l_installment_number, l_orig_num_install) + l_intervals_diff;
4408 
4409             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ': l_non_ro_intervals = ' || l_non_ro_intervals);
4410             l_remaining_balance := l_remaining_balance_theory + l_increased_amount1;
4411 
4412             l_periodic_principal := lns_financials.calculateEPPayment(p_loan_amount   => l_remaining_balance
4413                                                             ,p_num_intervals => l_non_ro_intervals
4414                                                             --,p_num_intervals => l_amortization_intervals
4415                                                             ,p_ending_balance=> l_balloon_amount
4416                                                             ,p_pay_in_arrears=> l_pay_in_arrears);
4417             l_prev_periodic_principal := l_periodic_principal;
4418 
4419             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic principal = ' || l_periodic_principal);
4420 
4421         else
4422             l_periodic_principal := l_prev_periodic_principal;
4423             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD periodic principal = ' || l_periodic_principal);
4424         end if;
4425 
4426         l_norm_interest := 0;
4427         l_add_prin_interest := 0;
4428         l_add_int_interest := 0;
4429         l_penal_prin_interest := 0;
4430         l_penal_int_interest := 0;
4431         l_penal_interest := 0;
4432         l_early_pay_cr := 0;
4433         l_norm_int_detail_str := null;
4434         l_add_prin_int_detail_str := null;
4435         l_add_int_int_detail_str := null;
4436         l_penal_prin_int_detail_str := null;
4437         l_penal_int_int_detail_str := null;
4438         l_penal_int_detail_str := null;
4439         l_early_pay_cr_detail_str := null;
4440 
4441         -- now we will caculate the interest due for this period
4442        if (p_based_on_terms = 'CURRENT' and l_detail_int_calc_flag = true) then
4443 
4444             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
4445             LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
4446                                 p_calc_method => l_calc_method,
4447                                 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4448                                 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
4449                                 p_interest_rate => l_annualized_rate,
4450                                 p_day_count_method => l_day_count_method,
4451                                 p_payment_freq => l_payment_frequency,
4452                                 p_compound_freq => l_compound_freq,
4453                                 p_adj_amount => l_sum_periodic_principal,
4454                                 p_CAP_AMOUNT => l_prev_cap_int,
4455                                 x_norm_interest => l_norm_interest,
4456                                 x_norm_int_details => l_norm_int_detail_str);
4457 
4458             l_norm_interest  := round(l_norm_interest, l_precision);
4459 
4460             if (l_installment_number-1) >= 0 and l_last_installment_billed + 1 = l_installment_number then
4461 
4462                 -- get additional interest start date
4463                 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
4464                 fetch c_get_last_bill_date into l_add_start_date;
4465                 close c_get_last_bill_date;
4466 
4467                 -- get additional interest end date
4468                 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
4469                     l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
4470                 else
4471                     l_add_end_date := sysdate;
4472                 end if;
4473 
4474                 if (l_installment_number-1) > 0 then
4475                     l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
4476                 else
4477                     l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
4478                 end if;
4479 
4480                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
4481                 -- calculate additional interest on unpaid principal
4482                 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
4483                                     p_calc_method => l_calc_method,
4484                                     p_period_start_date => l_add_start_date,
4485                                     p_period_end_date => l_add_end_date,
4486                                     p_interest_rate => l_annualized_rate,
4487                                     p_day_count_method => l_day_count_method,
4488                                     p_payment_freq => l_payment_frequency,
4489                                     p_compound_freq => l_compound_freq,
4490                                     p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
4491                                     p_prev_grace_end_date => l_prev_grace_end_date,
4492                                     p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4493                                     p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
4494                                     p_target => 'UNPAID_PRIN',
4495                                     x_add_interest => l_add_prin_interest,
4496                                     x_penal_interest => l_penal_prin_interest,
4497                                     x_add_int_details => l_add_prin_int_detail_str,
4498                                     x_penal_int_details => l_penal_prin_int_detail_str);
4499                 l_add_prin_interest  := round(l_add_prin_interest, l_precision);
4500 
4501                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
4502                 -- calculate additional interest on unpaid interest
4503                 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
4504                                     p_calc_method => l_calc_method,
4505                                     p_period_start_date => l_add_start_date,
4506                                     p_period_end_date => l_add_end_date,
4507                                     p_interest_rate => l_annualized_rate,
4508                                     p_day_count_method => l_day_count_method,
4509                                     p_payment_freq => l_payment_frequency,
4510                                     p_compound_freq => l_compound_freq,
4511                                     p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
4512                                     p_prev_grace_end_date => l_prev_grace_end_date,
4513                                     p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
4514                                     p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
4515                                     p_target => 'UNPAID_INT',
4516                                     x_add_interest => l_add_int_interest,
4517                                     x_penal_interest => l_penal_int_interest,
4518                                     x_add_int_details => l_add_int_int_detail_str,
4519                                     x_penal_int_details => l_penal_int_int_detail_str);
4520                 l_add_int_interest  := round(l_add_int_interest, l_precision);
4521 
4522                 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
4523                     l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
4524                 else
4525                     l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
4526                 end if;
4527 
4528                 -- calculate interest credit on early payment
4529                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
4530                 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => l_loan_id,
4531                                     p_calc_method => l_calc_method,
4532                                     p_installment => l_installment_number,
4533                                     p_interest_rate => l_previous_annualized,
4534                                     p_day_count_method => l_day_count_method,
4535                                     p_payment_freq => l_payment_frequency,
4536                                     p_compound_freq => l_compound_freq,
4537                                     x_early_pay_cr => l_early_pay_cr,
4538                                     x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
4539 
4540             end if;
4541 
4542        elsif (p_based_on_terms <> 'CURRENT' and l_detail_int_calc_flag = true and l_bill_on_appr_amounts = 'N') then
4543 
4544             if (l_calc_method = 'SIMPLE') then
4545 
4546                 l_periodic_rate := lns_financials.getPeriodicRate(
4547                                             p_payment_freq      => l_payment_frequency
4548                                             ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4549                                             ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
4550                                             ,p_annualized_rate   => l_annualized_rate
4551                                             ,p_days_count_method => l_day_count_method
4552                                             ,p_target            => 'INTEREST');
4553 
4554             elsif (l_calc_method = 'COMPOUND') then
4555 
4556                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
4557                                 ,p_payment_freq => l_payment_frequency
4558                                 ,p_annualized_rate => l_annualized_rate
4559                                 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4560                                 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4561                                 ,p_days_count_method => l_day_count_method
4562                                 ,p_target => 'INTEREST');
4563 
4564             end if;
4565 
4566             lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
4567                                             ,p_from_date        => l_payment_tbl(l_installment_number).period_begin_date
4568                                             ,p_to_date          => l_payment_tbl(l_installment_number).period_end_date
4569                                             ,p_calc_method      => 'TARGET'
4570                                             ,p_phase            => 'TERM'
4571                                             ,p_day_count_method => l_day_count_method
4572                                             ,p_adj_amount       => l_sum_periodic_principal
4573                                             ,x_wtd_balance      => l_wtd_balance
4574                                             ,x_begin_balance    => l_balance1
4575                                             ,x_end_balance      => l_balance2);
4576 
4577             l_wtd_balance := l_wtd_balance + l_prev_cap_int;
4578             l_norm_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
4579                                                                 ,p_periodic_rate => l_periodic_rate
4580                                                                 ,p_compounding_period => null);
4581             l_norm_interest := round(l_norm_interest, l_precision);
4582 
4583             l_norm_int_detail_str := l_norm_interest || ' (' ||
4584                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
4585                 ' * Balance ' || l_wtd_balance ||
4586                 ' * Rate ' || l_annualized_rate || '%)';
4587             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
4588 
4589        else
4590 
4591             l_remaining_balance_theory1 := l_remaining_balance_theory + l_prev_cap_int;
4592             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_theory1);
4593 
4594             if (l_calc_method = 'SIMPLE') then
4595 
4596                 l_periodic_rate := lns_financials.getPeriodicRate(
4597                                         p_payment_freq      => l_payment_frequency
4598                                         ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4599                                         ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
4600                                         ,p_annualized_rate   => l_annualized_rate
4601                                         ,p_days_count_method => l_day_count_method
4602                                         ,p_target            => 'INTEREST');
4603 
4604             elsif (l_calc_method = 'COMPOUND') then
4605 
4606                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
4607                                 ,p_payment_freq => l_payment_frequency
4608                                 ,p_annualized_rate => l_annualized_rate
4609                                 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
4610                                 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
4611                                 ,p_days_count_method => l_day_count_method
4612                                 ,p_target => 'INTEREST');
4613 
4614             end if;
4615 
4616             l_norm_interest := lns_financials.calculateInterest(p_amount             => l_remaining_balance_theory1
4617                                                                 ,p_periodic_rate      => l_periodic_rate
4618                                                                 ,p_compounding_period => null);
4619             l_norm_interest  := round(l_norm_interest, l_precision);
4620 
4621             l_norm_int_detail_str := l_norm_interest || ' (' ||
4622                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
4623                 ' * Balance ' || l_remaining_balance_theory1 ||
4624                 ' * Rate ' || l_annualized_rate || '%)';
4625             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
4626 
4627        end if;
4628 
4629        l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
4630        l_periodic_interest := round(l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest - l_early_pay_cr, l_precision);
4631 
4632        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal = ' || l_periodic_principal);
4633        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
4634        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
4635        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_intervals_remaining = ' || l_intervals_remaining);
4636        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled_principal = ' || l_unbilled_principal);
4637 
4638        if l_interest_only_flag <> 'Y' or l_intervals_remaining = 1 then
4639 
4640            if (l_remaining_balance_theory  + l_increased_amount1) < l_periodic_principal or l_intervals_remaining = 1 then
4641               l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
4642               logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
4643            end if;
4644 
4645        else
4646            -- we are in an interest only period
4647            l_periodic_principal := 0;
4648 
4649        end if;
4650 
4651        l_periodic_principal := round(l_periodic_principal, l_precision);
4652        l_periodic_payment := l_periodic_principal + l_periodic_interest;
4653 
4654        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
4655        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_payment = ' || l_periodic_payment);
4656 
4657        -- calculate balances
4658        l_begin_balance        := l_remaining_balance_theory;
4659        l_end_balance          := l_remaining_balance_theory - l_periodic_principal + l_increased_amount1;
4660 
4661        -- check to see if this loan has been billed
4662        if l_unbilled_principal > 0 then
4663          l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
4664        end if;
4665 
4666        -- build the amortization record
4667        l_amortization_rec.installment_number   := l_installment_number;  /* needed to calculate fees */
4668        l_amortization_rec.due_date             := l_payment_tbl(l_installment_number).period_due_date;
4669        l_amortization_rec.PERIOD_START_DATE    := l_payment_tbl(l_installment_number).period_begin_date;
4670        l_amortization_rec.PERIOD_END_DATE      := l_payment_tbl(l_installment_number).period_end_date;
4671        l_amortization_rec.principal_amount     := l_periodic_principal;  /* needed to calculate fees */
4672        l_amortization_rec.interest_amount      := l_periodic_interest;
4673        l_amortization_rec.UNPAID_PRIN          := l_unpaid_principal;
4674        l_amortization_rec.UNPAID_INT           := l_unpaid_interest;
4675        l_amortization_rec.INTEREST_RATE        := l_annualized_rate;
4676        l_amortization_rec.NORMAL_INT_AMOUNT    := l_norm_interest;
4677        l_amortization_rec.ADD_PRIN_INT_AMOUNT  := l_add_prin_interest;
4678        l_amortization_rec.ADD_INT_INT_AMOUNT   := l_add_int_interest;
4679        l_amortization_rec.PENAL_INT_AMOUNT     := l_penal_interest;
4680        l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
4681        l_amortization_rec.DISBURSEMENT_AMOUNT  := l_increased_amount;
4682        l_amortization_rec.FUNDED_AMOUNT        := l_end_funded_amount;
4683        l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := 0;
4684        l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
4685        l_amortization_rec.EARLY_PAY_CR_AMOUNT  := -l_early_pay_cr;
4686 
4687        if l_amortization_rec.FUNDED_AMOUNT is null then
4688             l_amortization_rec.FUNDED_AMOUNT := 0;
4689        end if;
4690 
4691        l_cap_int_detail_str := null;
4692        l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
4693        if p_loan_details.CAPITALIZE_INT = 'Y' then
4694             l_amortization_rec.begin_balance := l_begin_balance + l_prev_cap_int;
4695             if l_end_balance = 0 and l_amortization_rec.interest_amount > 0 then
4696                 l_amortization_rec.end_balance := l_end_balance;
4697                 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_prev_cap_int;
4698                 l_amortization_rec.CAP_INT_AMOUNT := 0;
4699                 l_prev_cap_int := 0;
4700                 l_amortization_rec.interest_amount := l_amortization_rec.interest_amount + l_amortization_rec.PREV_CAP_INT_AMOUNT;
4701             else
4702                 l_amortization_rec.end_balance := l_end_balance + l_prev_cap_int;
4703                 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
4704                 l_amortization_rec.CAP_INT_AMOUNT := l_prev_cap_int + l_amortization_rec.interest_amount;
4705                 if l_amortization_rec.CAP_INT_AMOUNT > 0 then
4706                     if l_prev_cap_int <> 0 then
4707                         l_cap_int_detail_str := 'Previously Capitalized Interest ' || l_prev_cap_int;
4708                     end if;
4709                     if l_norm_interest <> 0 then
4710                         if l_cap_int_detail_str is not null then
4711                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4712                         end if;
4713                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Normal Interest ' || l_norm_int_detail_str;
4714                     end if;
4715                     if l_add_prin_interest <> 0 then
4716                         if l_cap_int_detail_str is not null then
4717                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4718                         end if;
4719                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Prin ' || l_add_prin_int_detail_str;
4720                     end if;
4721                     if l_add_int_interest <> 0 then
4722                         if l_cap_int_detail_str is not null then
4723                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4724                         end if;
4725                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Interest ' || l_add_int_int_detail_str;
4726                     end if;
4727                     if l_penal_interest <> 0 then
4728                         if l_cap_int_detail_str is not null then
4729                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
4730                         end if;
4731                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Penal Interest ' || l_penal_interest || ' (' || l_penal_int_detail_str || ')';
4732                     end if;
4733                     if l_early_pay_cr <> 0 then
4734                         if l_cap_int_detail_str is not null then
4735                             l_cap_int_detail_str := l_cap_int_detail_str || ' -<br>';
4736                         end if;
4737                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Int Cr on Early Payment ' || l_early_pay_cr || ' (' || l_early_pay_cr_detail_str || ')';
4738                     end if;
4739                 end if;
4740                 l_prev_cap_int := l_amortization_rec.CAP_INT_AMOUNT;
4741                 if l_amortization_rec.NORMAL_INT_AMOUNT > 0 then
4742                     l_norm_int_detail_str := 'Interest amount is capitalized';
4743                 end if;
4744 
4745                 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_amortization_rec.interest_amount;
4746                 l_amortization_rec.interest_amount      := 0;
4747                 l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
4748                 l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
4749                 l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
4750                 l_amortization_rec.PENAL_INT_AMOUNT     := 0;
4751                 l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
4752 
4753                 l_add_prin_int_detail_str := null;
4754                 l_add_int_int_detail_str := null;
4755                 l_penal_prin_int_detail_str := null;
4756                 l_penal_int_int_detail_str := null;
4757                 l_penal_int_detail_str := null;
4758                 l_early_pay_cr_detail_str := null;
4759             end if;
4760        else
4761             l_amortization_rec.begin_balance := l_begin_balance;
4762             l_amortization_rec.end_balance := l_end_balance;
4763             l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
4764             l_amortization_rec.CAP_INT_AMOUNT := 0;
4765             l_prev_cap_int := 0;
4766        end if;
4767         l_amortization_rec.total := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
4768 
4769         l_fees_tbl.delete;
4770         l_fee_amount := 0;
4771         l_other_amount := 0;
4772 
4773         -- filling out basis table
4774         l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
4775         l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
4776         l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
4777         l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
4778         l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
4779         l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
4780         l_fee_basis_tbl(4).fee_basis_name   := 'OVERDUE_PRIN';
4781         l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
4782         l_fee_basis_tbl(5).fee_basis_name   := 'OVERDUE_PRIN_INT';
4783         l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
4784         l_fee_basis_tbl(6).fee_basis_name   := 'IND_DISB_AMT';
4785         l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
4786         l_fee_basis_tbl(7).fee_basis_name   := 'TOTAL_UNDISB_AMT';
4787         l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
4788         l_fee_basis_tbl(8).fee_basis_name   := 'OVERDUE_INT';
4789         l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
4790         l_fee_basis_tbl(9).fee_basis_name   := 'CURR_LOAN';
4791         l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
4792 
4793         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
4794         LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
4795                                     ,p_loan_id        => l_loan_id
4796                                     ,p_installment    => l_installment_number
4797                                     ,p_fee_basis_tbl  => l_fee_basis_tbl
4798                                     ,p_based_on_terms => p_based_on_terms
4799                                     ,p_phase          => 'TERM'
4800                                     ,x_fees_tbl       => l_fees_tbl
4801                                     ,x_return_status  => l_return_status
4802                                     ,x_msg_count      => l_msg_count
4803                                     ,x_msg_data       => l_msg_data);
4804 
4805         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
4806         if l_return_status <> 'S' then
4807             RAISE FND_API.G_EXC_ERROR;
4808         end if;
4809 
4810         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
4811 
4812         for k in 1..l_fees_tbl.count loop
4813             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
4814             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
4815             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
4816             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
4817             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
4818             if l_fees_tbl(k).FEE_CATEGORY = 'MEMO' then
4819                 l_other_amount := l_other_amount + l_fees_tbl(k).FEE_AMOUNT;
4820             else
4821                 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
4822             end if;
4823         end loop;
4824 
4825        l_amortization_rec.fee_amount           := l_fee_amount;
4826        l_amortization_rec.other_amount         := l_other_amount;
4827        l_amortization_rec.total                := l_amortization_rec.total + l_amortization_rec.fee_amount + l_amortization_rec.other_amount;
4828 
4829        -- running totals calculated here
4830        l_principal_cumulative := l_principal_cumulative + l_amortization_rec.principal_amount;
4831        l_interest_cumulative  := l_interest_cumulative + l_amortization_rec.interest_amount;
4832        l_fees_cumulative      := l_fees_cumulative + l_amortization_rec.fee_amount;
4833        l_other_cumulative     := l_other_cumulative + l_amortization_rec.other_amount;
4834 
4835        l_amortization_rec.interest_cumulative  := l_interest_cumulative;
4836        l_amortization_rec.principal_cumulative := l_principal_cumulative;
4837        l_amortization_rec.fees_cumulative      := l_fees_cumulative;
4838        l_amortization_rec.other_cumulative     := l_other_cumulative;
4839        l_amortization_rec.rate_id              := l_current_rate_id;
4840        l_amortization_rec.SOURCE               := 'PREDICTED';
4841 
4842        l_amortization_rec.NORMAL_INT_DETAILS   := l_norm_int_detail_str;
4843        l_amortization_rec.ADD_PRIN_INT_DETAILS := l_add_prin_int_detail_str;
4844        l_amortization_rec.ADD_INT_INT_DETAILS  := l_add_int_int_detail_str;
4845        l_amortization_rec.PENAL_INT_DETAILS    := l_penal_int_detail_str;
4846        l_amortization_rec.CAP_INT_DETAILS      := l_cap_int_detail_str;
4847        l_amortization_rec.EARLY_PAY_CR_DETAILS := l_early_pay_cr_detail_str;
4848 
4849        -- add the record to the amortization table
4850        l_amortization_tbl(i)                   := l_amortization_rec;
4851 
4852        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
4853        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INSTALLMENT ' || l_installment_number);
4854        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
4855        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD = ' || l_amortization_rec.PERIOD);
4856        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_START_DATE = ' || l_amortization_rec.PERIOD_START_DATE);
4857        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_END_DATE = ' || l_amortization_rec.PERIOD_END_DATE);
4858        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'due date = ' || l_amortization_rec.due_date);
4859        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_principal = ' || l_amortization_rec.principal_amount);
4860        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_interest = ' || l_amortization_rec.interest_amount);
4861        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fee_amount = ' || l_amortization_rec.fee_amount);
4862        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_amount = ' || l_amortization_rec.other_amount);
4863        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'total = ' || l_amortization_rec.total);
4864        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'begin_balance = ' || l_amortization_rec.begin_balance);
4865        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'end_balance = ' || l_amortization_rec.end_balance);
4866        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'interest_cumulative = ' || l_amortization_rec.interest_cumulative);
4867        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'principal_cumulative = ' || l_amortization_rec.principal_cumulative);
4868        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fees_cumulative = ' || l_amortization_rec.fees_cumulative);
4869        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_cumulative = ' || l_amortization_rec.other_cumulative);
4870        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'current_rate_id = ' || l_amortization_rec.rate_id );
4871        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_RATE = ' || l_amortization_rec.INTEREST_RATE );
4872        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_PRIN = ' || l_amortization_rec.UNPAID_PRIN );
4873        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_INT = ' || l_amortization_rec.UNPAID_INT );
4874        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
4875        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_AMOUNT = ' || l_amortization_rec.ADD_PRIN_INT_AMOUNT );
4876        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_AMOUNT );
4877        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_AMOUNT = ' || l_amortization_rec.PENAL_INT_AMOUNT );
4878        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FUNDED_AMOUNT = ' || l_amortization_rec.FUNDED_AMOUNT );
4879        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amortization_rec.NORMAL_INT_DETAILS );
4880        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_DETAILS = ' || l_amortization_rec.ADD_PRIN_INT_DETAILS );
4881        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_DETAILS_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_DETAILS );
4882        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_DETAILS = ' || l_amortization_rec.PENAL_INT_DETAILS );
4883        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amortization_rec.PREV_CAP_INT_AMOUNT );
4884        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amortization_rec.CURR_CAP_INT_AMOUNT );
4885        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amortization_rec.CAP_INT_AMOUNT );
4886        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amortization_rec.CAP_INT_DETAILS );
4887        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_AMOUNT = ' || l_amortization_rec.EARLY_PAY_CR_AMOUNT );
4888        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_DETAILS = ' || l_amortization_rec.EARLY_PAY_CR_DETAILS );
4889        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
4890 
4891        l_remaining_balance_theory :=  l_end_balance;
4892        l_sum_periodic_principal := l_sum_periodic_principal + l_periodic_principal;
4893 
4894        l_previous_interest_only_flag := l_interest_only_flag;
4895        l_previous_rate_id            := l_current_rate_id;
4896        l_previous_annualized         := l_annualized_rate;
4897        l_prev_payment_frequency      := l_payment_frequency;
4898 
4899     end loop;
4900 
4901     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT = ' || l_amortization_tbl.count);
4902     x_loan_amort_tbl := l_amortization_tbl;
4903 
4904     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
4905 
4906  Exception
4907     WHEN FND_API.G_EXC_ERROR THEN
4908          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
4909 
4910     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
4911          logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
4912 
4913     WHEN OTHERS THEN
4914          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
4915 
4916 end amortizeEPLoan;
4917 
4918 
4919 
4920 
4921 /*=========================================================================
4922 || PUBLIC PROCEDURE amortizeLoan
4923 ||
4924 || DESCRIPTION
4925 ||
4926 || Overview: procedure will run an amortization
4927 ||            this is the main calculation API for amortization
4928 ||            THIS API WILL BE CALLED FROM 2 PLACES PRIMARILY:
4929 ||           1. Amortization UI - when creating a loan
4930 ||           2. Billing Engine  - to generate installment bills
4931 ||
4932 || Parameter: p_loan_details  = details of the loan
4933 ||            p_rate_schedule = rate schedule for the loan
4934 ||            p_installment_number => billing will pass in an installment
4935 ||                                    number to generate a billt
4936 ||            x_loan_amort_tbl => table of amortization records
4937 ||
4938 || Source Tables:  NA
4939 ||
4940 || Target Tables:
4941 ||
4942 ||
4943 || KNOWN ISSUES
4944 ||
4945 || NOTES
4946 ||
4947 || MODIFICATION HISTORY
4948 || Date                  Author            Description of Changes
4949 || 12/12/2003 11:35AM     raverma           Created
4950 ||  2/26/2004             raverma           coded in multiple rates
4951 || 10/28/2004             raverma           added interest only flag
4952 || 06/20/2008             scherkas          Synch amortizeLoan procedure with LNS_FINANCIALS 115.112 version
4953  *=======================================================================*/
4954 procedure amortizeLoan(p_loan_details       in  LNS_FINANCIALS.LOAN_DETAILS_REC
4955                       ,p_rate_schedule      in  LNS_FINANCIALS.RATE_SCHEDULE_TBL
4956                       ,p_based_on_terms     in  varchar2
4957                       ,p_installment_number in  number
4958                       ,x_loan_amort_tbl     out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
4959 is
4960     l_return_status                  varchar2(1);
4961     l_msg_count                      NUMBER;
4962     l_msg_data                       VARCHAR2(32767);
4963     l_loan_id                        number;
4964     l_original_loan_amount           number;  -- loan amount
4965     l_balloon_amount                 number;
4966     l_amortized_amount               number;  -- amount of loan less balloon amount
4967     l_loan_term                      number;
4968     l_amortized_term                 number;
4969     l_amortized_term_period          varchar2(30);
4970     l_amortization_frequency         varchar2(30);
4971     l_first_payment_date             date;
4972     l_pay_in_arrears                 boolean;
4973     l_payment_frequency              varchar2(30);
4974     l_day_count_method               varchar2(30);
4975     l_interest_comp_freq             varchar2(30);
4976     l_reamortize_from_installment    number;
4977     l_reamortize_amount              number;
4978     l_annualized_rate                number;  -- annual rate on the loan
4979     l_raw_rate                       number;  --
4980     l_intervals_remaining            number;
4981     l_amortization_intervals_orig    number;
4982     l_amortization_intervals         number;  -- number of intervals to amortize over
4983     l_rate_details                   LNS_FINANCIALS.INTEREST_RATE_REC;
4984     l_current_rate_id                number;
4985     l_previous_rate_id               number;
4986     l_precision                      number;
4987     l_rate_type                      varchar2(30);
4988     l_open_rate_change_frequency	 varchar2(30);
4989     l_open_index_rate_id 			 number;
4990     l_open_ceiling_rate				 number;
4991     l_open_floor_rate 				 number;
4992     l_term_rate_change_frequency	 varchar2(30);
4993     l_term_index_rate_id 			 number;
4994     l_term_ceiling_rate				 number;
4995     l_term_floor_rate 				 number;
4996 
4997     l_period_start_Date              date;
4998     l_period_end_date                date;
4999     l_periodic_rate                  number;
5000     l_maturity_date                  date;
5001     l_amortized_maturity_date        date;
5002 
5003     l_amortization_rec               LNS_FINANCIALS.AMORTIZATION_REC;
5004     l_amortization_tbl               LNS_FINANCIALS.AMORTIZATION_TBL;
5005     l_rate_tbl                       LNS_FINANCIALS.RATE_SCHEDULE_TBL;
5006     l_payment_tbl                    LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
5007     l_amortized_payment_tbl          LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
5008     l_loan_start_date                date;
5009     l_num_pay_dates                  number;  -- number of dates on installment schedule
5010     l_periodic_payment               number;
5011     l_periodic_principal             number;
5012     l_periodic_interest              number;
5013     l_total_principal                number;
5014     l_payment_number                 number;
5015     l_fee_amount                     number;
5016     l_fee_amount1                    number;
5017     l_other_amount                   number;
5018     l_begin_balance                  number;
5019     l_end_balance                    number;
5020     l_unbilled_principal             number;
5021     l_unpaid_principal               number;
5022     l_unpaid_interest                number;
5023 
5024     l_remaining_balance_actual       number;
5025     l_remaining_balance_theory       number;
5026     l_total                          number;
5027     l_interest_cumulative            number;
5028     l_principal_cumulative           number;
5029     l_fees_cumulative                number;
5030     l_other_cumulative               number;
5031     i                                number;
5032     l_installment_number             number;
5033     l_billing                        boolean;  -- switch to notify if billing is calling API
5034     l_api_name                       varchar2(20);
5035     l_last_installment_billed        number;
5036     l_rate_to_calculate              number;
5037     l_previous_annualized            number;
5038     l_previous_interest_only_flag    varchar2(1);
5039     l_interest_only_flag             varchar2(1);
5040     l_calc_method                    varchar2(30);
5041     l_compound_freq                  varchar2(30);
5042     l_remaining_balance_actual1      number;
5043     l_ending_balance                 number;
5044     l_due_date                       date;
5045     l_begin                          number;
5046     l_installment_number1            number;
5047     l_norm_interest                  number;
5048     l_add_prin_interest              number;
5049     l_add_int_interest               number;
5050     l_add_start_date                 date;
5051     l_add_end_date                   date;
5052     l_penal_prin_interest            number;
5053     l_penal_int_interest             number;
5054     l_penal_interest                 number;
5055     l_first_installment_billed       number;
5056     l_extend_from_installment        number;
5057     l_remaining_balance              number;
5058     l_prev_grace_end_date            date;
5059     l_disb_header_id                 number;
5060     l_billed                         varchar2(1);
5061     n                                number;
5062     l_sum_periodic_principal         number;
5063     l_date1                          date;
5064     l_billed_principal               number;
5065     l_detail_int_calc_flag           boolean;
5066     l_increased_amount               number;
5067     l_increased_amount1              number;
5068     l_begin_funded_amount            number;
5069     l_end_funded_amount              number;
5070     l_increase_amount_instal         number;
5071     l_prev_increase_amount_instal    number;
5072     l_begin_funded_amount_new        number;
5073     l_fund_sched_count               number;
5074     l_wtd_balance                    number;
5075     l_balance1                       number;
5076     l_balance2                       number;
5077     l_remaining_balance_theory1      number;
5078     l_prev_cap_int                   number;
5079     l_early_pay_cr                   number;
5080     l_add_int_amount                 number;
5081     l_amortization_schedule_id       number;
5082     l_bill_on_appr_amounts           varchar2(1);
5083 
5084     l_norm_int_detail_str            varchar2(2000);
5085     l_add_prin_int_detail_str        varchar2(2000);
5086     l_add_int_int_detail_str         varchar2(2000);
5087     l_penal_prin_int_detail_str      varchar2(2000);
5088     l_penal_int_int_detail_str       varchar2(2000);
5089     l_penal_int_detail_str           varchar2(2000);
5090     l_cap_int_detail_str             varchar2(2000);
5091     l_early_pay_cr_detail_str        varchar2(2000);
5092 
5093     l_fees_tbl                       LNS_FEE_ENGINE.FEE_CALC_TBL;
5094     l_fee_basis_tbl                  LNS_FEE_ENGINE.FEE_BASIS_TBL;
5095     l_freq_schedule_tbl              LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
5096     l_FREQUENCY_REC                  LNS_FIN_UTILS.FREQUENCY_SCHEDULE;
5097     l_prev_payment_frequency         varchar2(30);
5098 
5099     -- get last bill date
5100     cursor c_get_last_bill_date(p_loan_id number, p_installment_number number)  is
5101         select ACTIVITY_DATE
5102         from LNS_PRIN_TRX_ACTIVITIES_V
5103         where loan_id = p_loan_id
5104         and PAYMENT_NUMBER = p_installment_number
5105         and PARENT_AMORTIZATION_ID is null
5106         and ACTIVITY_CODE in ('BILLING', 'START');
5107 
5108     -- get last billed payment info
5109     cursor c_get_last_payment(p_loan_id number, p_installment_number number)  is
5110         select (PRINCIPAL_AMOUNT + INTEREST_AMOUNT + nvl(CURR_CAP_INT_AMOUNT, 0)),
5111             nvl(FUNDED_AMOUNT, 0),
5112             nvl(CAP_INT_AMOUNT, 0),
5113             amortization_schedule_id
5114         from lns_amortization_scheds
5115         where loan_id = p_loan_id
5116         and PAYMENT_NUMBER > 0
5117         and PAYMENT_NUMBER = p_installment_number
5118         and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
5119         and PARENT_AMORTIZATION_ID is null
5120         and REAMORTIZE_TO_INSTALLMENT is null
5121         --and PRINCIPAL_AMOUNT > 0
5122         and nvl(PHASE, 'TERM') = 'TERM';
5123         --order by PAYMENT_NUMBER desc;
5124 
5125     -- get first billed installment number
5126     cursor c_first_billed_instal(p_loan_id number)  is
5127         select min(PAYMENT_NUMBER)
5128         from LNS_AMORTIZATION_SCHEDS
5129         where loan_id = p_loan_id
5130         and PAYMENT_NUMBER > 0
5131         and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
5132         and PARENT_AMORTIZATION_ID is null
5133         and nvl(PHASE, 'TERM') = 'TERM';
5134 
5135     cursor c_fund_sched_exist(p_loan_id number)  is
5136         select decode(loan.loan_class_code,
5137             'DIRECT', (select count(1) from lns_disb_headers where loan_id = p_loan_id and status is null and PAYMENT_REQUEST_DATE is not null),
5138             'ERS', (select count(1) from lns_loan_lines where loan_id = p_loan_id and (status is null or status = 'PENDING') and end_date is null))
5139         from lns_loan_headers_all loan
5140         where loan.loan_id = p_loan_id;
5141 
5142     -- get sum of all add int for last billed installment
5143     cursor c_add_int(p_loan_id number, p_amortization_schedule_id number)  is
5144         select nvl(sum(am_lines.amount), 0)
5145         from lns_amortization_lines am_lines,
5146             RA_CUSTOMER_TRX_LINES_ALL trx_lines
5147         where am_lines.loan_id = p_loan_id
5148         and am_lines.amortization_schedule_id = p_amortization_schedule_id
5149         and am_lines.line_type = 'INT'
5150         and am_lines.cust_trx_line_id = trx_lines.CUSTOMER_TRX_LINE_ID
5151         and trx_lines.description not like '%Normal Interest%';
5152 
5153     cursor c_get_bill_opt(p_loan_id number) is
5154         select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
5155         from lns_loan_headers_all
5156         where loan_id = p_loan_id;
5157 
5158 begin
5159 
5160     -- initialize all variables
5161     l_original_loan_amount          := 0;  -- loan amount
5162 	l_amortized_amount              := 0;
5163     l_previous_rate_id              := -1;
5164     l_previous_annualized           := -1;
5165     l_previous_interest_only_flag   := 'N';    -- default to regular interest + principal
5166     l_periodic_payment              := 0;
5167     l_periodic_principal            := 0;
5168     l_periodic_interest             := 0;
5169 	l_balloon_amount                := 0;
5170     l_total_principal               := 0;
5171     l_payment_number                := 0;
5172     l_fee_amount                    := 0;
5173     l_other_amount                  := 0;
5174     l_begin_balance                 := 0;
5175     l_unbilled_principal            := 0;
5176     l_billed_principal              := 0;
5177     l_unpaid_principal              := 0;
5178     l_remaining_balance_actual      := 0;
5179     l_remaining_balance_theory      := 0;
5180     l_total                         := 0;
5181     l_interest_cumulative           := 0;
5182     l_principal_cumulative          := 0;
5183     l_fees_cumulative               := 0;
5184     l_other_cumulative              := 0;
5185     i                               := 0;
5186     l_installment_number            := 1;  -- begin from #1 installment, NOT #0 installment
5187     l_rate_to_calculate             := 0;
5188     l_billing                       := false;  -- switch to notify if billing is calling API
5189     l_sum_periodic_principal        := 0;
5190     l_api_name                      := 'amortizeLoan MAIN';
5191 
5192     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
5193     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - based on TERMS====> ' || p_based_on_terms);
5194     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_installment_number = ' || p_installment_number);
5195 
5196     l_loan_term                     := p_loan_details.loan_term;
5197 	l_amortized_amount              := p_loan_details.amortized_amount;
5198     l_amortized_term                := p_loan_details.amortized_term;
5199     l_amortized_term_period         := p_loan_details.amortized_term_period;
5200     l_amortization_frequency        := p_loan_details.amortization_frequency;
5201 	l_balloon_amount                := p_loan_details.balloon_payment_amount;
5202     l_day_count_method              := p_loan_details.day_count_method;
5203     l_first_payment_date            := p_loan_details.first_payment_date;
5204     l_loan_id                       := p_loan_details.loan_id;
5205     l_last_installment_billed       := p_loan_details.last_installment_billed;
5206     l_loan_start_date               := p_loan_details.loan_start_date;
5207     l_maturity_date                 := p_loan_details.maturity_date;
5208     l_rate_type                     := p_loan_details.rate_type;
5209     l_open_rate_change_frequency	:= p_loan_details.open_rate_chg_freq;
5210     l_open_index_rate_id 			:= p_loan_details.open_index_rate_id;
5211     l_open_ceiling_rate				:= p_loan_details.open_ceiling_rate;
5212     l_open_floor_rate 				:= p_loan_details.open_floor_rate;
5213     l_original_loan_amount          := p_loan_details.requested_amount;
5214     l_pay_in_arrears                := p_loan_details.pay_in_arrears_boolean;
5215     l_payment_frequency             := p_loan_details.payment_frequency;
5216     l_precision                     := p_loan_details.currency_precision;
5217     l_reamortize_from_installment   := p_loan_details.reamortize_from_installment;
5218     l_reamortize_amount             := p_loan_details.reamortize_amount;
5219     l_remaining_balance_actual      := p_loan_details.remaining_balance;
5220     l_remaining_balance_actual1     := p_loan_details.remaining_balance;
5221     l_term_rate_change_frequency	:= p_loan_details.term_rate_chg_freq;
5222     l_term_index_rate_id 			:= p_loan_details.term_index_rate_id;
5223     l_term_ceiling_rate				:= p_loan_details.term_ceiling_rate;
5224     l_term_floor_rate 				:= p_loan_details.term_floor_rate;
5225     l_calc_method                   := p_loan_details.CALCULATION_METHOD;
5226     l_compound_freq                 := p_loan_details.INTEREST_COMPOUNDING_FREQ;
5227     l_extend_from_installment       := p_loan_details.EXTEND_FROM_INSTALLMENT;
5228 
5229     -- get the interest rate schedule
5230     l_rate_tbl := p_rate_schedule;
5231     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
5232 
5233     -- get payment schedule
5234     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
5235 
5236     l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
5237                                         P_LOAN_ID           => l_loan_id,
5238                                         P_PHASE             => 'TERM',
5239                                         P_COMPONENT         => 'PRIN_INT');
5240 
5241     l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
5242                              p_loan_start_date      => l_loan_start_date,
5243                              p_loan_maturity_date  => l_maturity_date,
5244                              p_freq_schedule_tbl => l_freq_schedule_tbl);
5245 /*
5246     l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
5247                                                        ,p_loan_maturity_date => l_maturity_date
5248                                                        ,p_first_pay_date     => l_first_payment_date
5249                                                        ,p_num_intervals      => null --l_intervals
5250                                                        ,p_interval_type      => l_payment_frequency
5251                                                        ,p_pay_in_arrears     => l_pay_in_arrears);
5252 */
5253     l_num_pay_dates := l_payment_tbl.count;
5254     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
5255 
5256     if l_loan_term <> l_amortized_term then
5257 
5258         -- get amortize maturity date
5259         l_amortized_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term         => l_amortized_term
5260                                                             ,p_term_period  => l_amortized_term_period
5261                                                             ,p_frequency    => l_payment_frequency
5262                                                             ,p_start_date   => l_loan_start_date);
5263         -- get amortize payment schedule
5264         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting amortize payment schedule');
5265 
5266         l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
5267                                             P_LOAN_ID           => l_loan_id,
5268                                             P_PHASE             => 'TERM',
5269                                             P_COMPONENT         => 'PRIN_INT');
5270 
5271         l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
5272                                 p_loan_start_date      => l_loan_start_date,
5273                                 p_loan_maturity_date  => l_amortized_maturity_date,
5274                                 p_freq_schedule_tbl => l_freq_schedule_tbl);
5275 /*
5276         l_amortized_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
5277                                                         ,p_loan_maturity_date => l_amortized_maturity_date
5278                                                         ,p_first_pay_date     => l_first_payment_date
5279                                                         ,p_num_intervals      => null --l_intervals
5280                                                         ,p_interval_type      => l_payment_frequency
5281                                                         ,p_pay_in_arrears     => l_pay_in_arrears);
5282 */
5283         l_amortization_intervals := l_amortized_payment_tbl.count;
5284     else
5285         l_amortization_intervals := l_num_pay_dates;
5286     end if;
5287     l_amortization_intervals_orig := l_amortization_intervals;
5288     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- amortize payment schedule count = ' || l_amortization_intervals);
5289 
5290     if p_based_on_terms <> 'CURRENT' then
5291         open c_fund_sched_exist(l_loan_id);
5292         fetch c_fund_sched_exist into l_fund_sched_count;
5293         close c_fund_sched_exist;
5294 
5295         if l_fund_sched_count = 0 then
5296             l_original_loan_amount := p_loan_details.requested_amount;
5297         else
5298             l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
5299         end if;
5300     else
5301         l_original_loan_amount := getFundedAmount(l_loan_id, l_loan_start_date, p_based_on_terms);
5302     end if;
5303 
5304     l_fees_tbl.delete;
5305     l_fee_amount := 0;
5306 
5307     -- filling out basis table
5308     l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
5309     l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
5310     l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
5311     l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
5312     l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
5313     l_fee_basis_tbl(3).fee_basis_amount := l_original_loan_amount;
5314     l_fee_basis_tbl(4).fee_basis_name   := 'TOTAL_UNDISB_AMT';
5315     l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_original_loan_amount;
5316 
5317     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
5318     LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
5319                                 ,p_loan_id        => l_loan_id
5320                                 ,p_installment    => 0
5321                                 ,p_fee_basis_tbl  => l_fee_basis_tbl
5322                                 ,p_based_on_terms => p_based_on_terms
5323                                 ,p_phase          => 'TERM'
5324                                 ,x_fees_tbl       => l_fees_tbl
5325                                 ,x_return_status  => l_return_status
5326                                 ,x_msg_count      => l_msg_count
5327                                 ,x_msg_data       => l_msg_data);
5328 
5329     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
5330     if l_return_status <> 'S' then
5331         RAISE FND_API.G_EXC_ERROR;
5332     end if;
5333 
5334     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
5335 
5336     for k in 1..l_fees_tbl.count loop
5337         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
5338         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
5339         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
5340         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
5341         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
5342         l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
5343     end loop;
5344     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
5345 
5346     if l_fee_amount > 0 then
5347         i := i + 1;
5348         l_amortization_rec.installment_number   := 0;
5349         l_amortization_rec.due_date             := l_loan_start_date;
5350         l_amortization_rec.PERIOD_START_DATE    := l_loan_start_date;
5351         l_amortization_rec.PERIOD_END_DATE      := l_loan_start_date;
5352         l_amortization_rec.principal_amount     := 0;
5353         l_amortization_rec.interest_amount      := 0;
5354         l_amortization_rec.fee_amount           := l_fee_amount;
5355         l_amortization_rec.other_amount         := 0;
5356         l_amortization_rec.begin_balance        := l_original_loan_amount;
5357         l_amortization_rec.end_balance          := l_original_loan_amount;
5358         l_amortization_rec.interest_cumulative  := 0;
5359         l_amortization_rec.principal_cumulative := 0;
5360         l_amortization_rec.fees_cumulative      := l_fee_amount;
5361         l_amortization_rec.other_cumulative     := 0;
5362         l_amortization_rec.rate_id              := 0;
5363         l_amortization_rec.SOURCE               := 'PREDICTED';
5364         l_amortization_rec.total                := l_fee_amount;
5365         l_amortization_rec.UNPAID_PRIN          := 0;
5366         l_amortization_rec.UNPAID_INT           := 0;
5367         l_amortization_rec.INTEREST_RATE        := l_rate_tbl(1).annual_rate;
5368         l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
5369         l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
5370         l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
5371         l_amortization_rec.PENAL_INT_AMOUNT     := 0;
5372         l_amortization_rec.FUNDED_AMOUNT        := l_original_loan_amount;
5373         l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
5374         l_amortization_rec.DISBURSEMENT_AMOUNT  := l_original_loan_amount;
5375         l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := 0;
5376         l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
5377         l_amortization_rec.PREV_CAP_INT_AMOUNT  := 0;
5378         l_amortization_rec.CAP_INT_AMOUNT       := 0;
5379         l_amortization_rec.CAP_INT_DETAILS      := null;
5380         l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
5381 
5382         -- add the record to the amortization table
5383         l_amortization_tbl(i)                   := l_amortization_rec;
5384     end if;
5385 
5386     -- go to the nth installment (Billing program doesnt need to go thru whole amortization)
5387     if p_installment_number is not null then
5388        -- we are billing
5389 
5390        l_billing        := true;
5391        if p_installment_number > 0 then
5392 
5393            if p_installment_number > l_num_pay_dates then
5394                 l_payment_number := l_num_pay_dates;
5395            else
5396                 l_payment_number := p_installment_number;
5397            end if;
5398 
5399        else
5400            l_payment_number := p_installment_number;
5401        end if;
5402 
5403     else -- we are not billing, go thru entire amortization
5404 
5405        l_payment_number := l_num_pay_dates;
5406 
5407     end if;
5408 
5409     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_number = ' || l_payment_number);
5410     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
5411 
5412     l_begin := 1;
5413 
5414     if p_based_on_terms = 'CURRENT' and l_last_installment_billed > 0 then
5415 
5416         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5417         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Querying INSTALLMENT ' || l_last_installment_billed  || '-----');
5418         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5419 
5420         l_periodic_payment := null;
5421         open c_get_last_payment(l_loan_id, l_last_installment_billed);
5422         fetch c_get_last_payment into l_periodic_payment, l_begin_funded_amount, l_prev_cap_int, l_amortization_schedule_id;
5423         close c_get_last_payment;
5424         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
5425         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
5426         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_amortization_schedule_id = ' || l_amortization_schedule_id);
5427 
5428         if p_loan_details.FLUCTUATE_EQ_PAY_AMOUNT = 'Y' then
5429             open c_add_int(l_loan_id, l_amortization_schedule_id);
5430             fetch c_add_int into l_add_int_amount;
5431             close c_add_int;
5432             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_amount = ' || l_add_int_amount);
5433             l_periodic_payment := l_periodic_payment - l_add_int_amount;
5434         end if;
5435 
5436         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic payment = ' || l_periodic_payment);
5437 
5438         if l_periodic_payment is not null then
5439 
5440             l_begin := l_last_installment_billed + 1;
5441 
5442             if l_rate_tbl.count = 1 then
5443                 l_previous_annualized := l_rate_tbl(1).annual_rate;
5444                 l_previous_interest_only_flag := l_rate_tbl(1).interest_only_flag;
5445             else
5446                 l_rate_details := lns_financials.getRateDetails(p_installment => l_last_installment_billed
5447                                                                 ,p_rate_tbl => l_rate_tbl);
5448                 l_previous_annualized := l_rate_details.annual_rate;
5449                 l_previous_interest_only_flag := l_rate_details.interest_only_flag;
5450             end if;
5451 
5452         end if;
5453 
5454     else
5455         l_remaining_balance_theory := l_original_loan_amount;
5456         l_begin_funded_amount := 0; --l_original_loan_amount;
5457         l_end_funded_amount := l_original_loan_amount;
5458         l_prev_cap_int := 0;
5459 
5460         open c_get_bill_opt(l_loan_id);
5461         fetch c_get_bill_opt into l_bill_on_appr_amounts;
5462         close c_get_bill_opt;
5463         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
5464     end if;
5465 
5466     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin = ' || l_begin);
5467     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_loan_details.REAMORTIZE_ON_FUNDING = ' || p_loan_details.REAMORTIZE_ON_FUNDING);
5468     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
5469 
5470     l_increase_amount_instal := -1;
5471 
5472     if l_begin = 1 then
5473         l_prev_payment_frequency := '';
5474     else
5475         LNS_FIN_UTILS.fetchPayFreqRecByDate(
5476             p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
5477             p_DATE => l_payment_tbl(l_begin-1).PERIOD_DUE_DATE,
5478             x_FREQUENCY_REC	=> l_FREQUENCY_REC);
5479         l_prev_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
5480     end if;
5481 
5482     -- loop to build the amortization schedule
5483     for l_installment_number in l_begin..l_payment_number
5484     loop
5485 
5486        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5487        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ----- Calculating INSTALLMENT ' || l_installment_number || ' -----');
5488        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
5489 
5490        i := i + 1;
5491        l_periodic_interest      := 0;
5492        l_periodic_principal     := 0;
5493        l_fee_amount             := 0;
5494        l_other_amount           := 0;
5495        l_unpaid_principal       := 0;
5496        l_unpaid_interest        := 0;
5497        l_intervals_remaining    := l_num_pay_dates - l_installment_number + 1;
5498        l_detail_int_calc_flag   := false;
5499        l_increased_amount       := 0;
5500        l_increased_amount1      := 0;
5501        l_prev_increase_amount_instal := l_increase_amount_instal;
5502 
5503        if l_fund_sched_count > 0 or p_based_on_terms = 'CURRENT' then
5504 
5505             if (l_last_installment_billed >= 0) and (l_last_installment_billed + 1 = l_installment_number) then
5506 
5507                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 = l_installment_number');
5508 
5509                 l_principal_cumulative := 0;
5510                 l_interest_cumulative  := 0;
5511                 l_fees_cumulative      := 0;
5512                 l_other_cumulative     := 0;
5513                 l_sum_periodic_principal := 0;
5514                 l_billed_principal     := p_loan_details.billed_principal;
5515                 l_unbilled_principal   := p_loan_details.unbilled_principal;
5516                 l_unpaid_principal     := p_loan_details.unpaid_principal;
5517                 l_unpaid_interest      := p_loan_details.UNPAID_INTEREST;
5518 
5519                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
5520                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
5521                     l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
5522                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
5523 
5524                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
5525                     l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
5526                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
5527 
5528                     if l_end_funded_amount > l_begin_funded_amount then
5529                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
5530 
5531                         if l_end_funded_amount = l_begin_funded_amount_new then
5532                             l_increase_amount_instal := l_installment_number;
5533                         else
5534                             if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
5535                                 l_increase_amount_instal := l_installment_number + 1;
5536                             elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
5537                                 l_increase_amount_instal := l_installment_number;
5538                             end if;
5539                         end if;
5540 
5541                     elsif l_begin_funded_amount_new > l_begin_funded_amount then
5542                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new > l_begin_funded_amount');
5543                         l_increase_amount_instal := l_installment_number;
5544                     end if;
5545 
5546                     l_detail_int_calc_flag := true;
5547 
5548                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
5549                     l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
5550                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
5551 
5552                     l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
5553                     l_begin_funded_amount := l_begin_funded_amount_new;
5554                     l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
5555                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
5556                     l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal;
5557                 else
5558                     l_remaining_balance_theory := 0;
5559                 end if;
5560 
5561             else
5562 
5563                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed + 1 < l_installment_number');
5564                 if p_loan_details.loan_status <> 'PAIDOFF' and p_loan_details.loan_status <> 'CANCELLED' then
5565                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1));
5566                     l_begin_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE-1), p_based_on_terms);
5567                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount = ' || l_begin_funded_amount);
5568 
5569                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE);
5570                     l_begin_funded_amount_new := getFundedAmount(l_loan_id, l_payment_tbl(l_installment_number).PERIOD_BEGIN_DATE, p_based_on_terms);
5571                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_begin_funded_amount_new = ' || l_begin_funded_amount_new);
5572 
5573                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Getting funded amount for ' || (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1));
5574                     l_end_funded_amount := getFundedAmount(l_loan_id, (l_payment_tbl(l_installment_number).PERIOD_END_DATE-1), p_based_on_terms);
5575                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount = ' || l_end_funded_amount);
5576 
5577                     if l_end_funded_amount > l_begin_funded_amount then
5578                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_funded_amount > l_begin_funded_amount');
5579                         l_detail_int_calc_flag := true;
5580 
5581                         if l_end_funded_amount = l_begin_funded_amount_new then
5582                             l_increase_amount_instal := l_installment_number;
5583                         else
5584                             if p_loan_details.REAMORTIZE_ON_FUNDING = 'REST' then
5585                                 l_increase_amount_instal := l_installment_number + 1;
5586                             elsif p_loan_details.REAMORTIZE_ON_FUNDING = 'IMMEDIATELY' then
5587                                 l_increase_amount_instal := l_installment_number;
5588                             end if;
5589                         end if;
5590 
5591                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_billed_principal = ' || l_billed_principal);
5592                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_sum_periodic_principal = ' || l_sum_periodic_principal);
5593 
5594                         l_increased_amount := l_end_funded_amount - l_begin_funded_amount;
5595                         l_begin_funded_amount := l_begin_funded_amount_new;
5596                         l_increased_amount1 := l_end_funded_amount - l_begin_funded_amount;
5597                         l_remaining_balance_theory := l_begin_funded_amount - l_billed_principal - l_sum_periodic_principal;
5598                     end if;
5599                 else
5600                     l_remaining_balance_theory := 0;
5601                 end if;
5602 
5603             end if;
5604 
5605        elsif l_installment_number = 1 and l_fund_sched_count = 0 and p_based_on_terms <> 'CURRENT' then
5606             l_increased_amount := l_original_loan_amount;
5607        end if;
5608 
5609        if p_loan_details.REAMORTIZE_ON_FUNDING = 'NO' then
5610             l_increase_amount_instal := -1;
5611        end if;
5612 
5613        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
5614 
5615        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': getting rate details');
5616        l_rate_details := getRateDetails(p_installment => l_installment_number
5617                                        ,p_rate_tbl    => l_rate_tbl);
5618 
5619        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
5620        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
5621        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
5622 
5623         -- get the rate details only need to get it once if a single interest rate exists
5624         l_current_rate_id          := l_rate_details.rate_id;
5625         l_annualized_rate          := l_rate_details.annual_rate;
5626         l_interest_only_flag       := l_rate_details.interest_only_flag;
5627 
5628         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_rate_id = ' || l_previous_rate_id);
5629         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_current_rate_id = ' || l_current_rate_id);
5630         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_annualized = ' || l_previous_annualized);
5631         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_annualized_rate = ' || l_annualized_rate);
5632         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_previous_interest_only_flag = ' || l_previous_interest_only_flag);
5633         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_interest_only_flag = ' || l_interest_only_flag);
5634         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_last_installment_billed = ' || l_last_installment_billed);
5635         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_extend_from_installment = ' || l_extend_from_installment);
5636         if l_detail_int_calc_flag then
5637             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = true');
5638         else
5639             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_detail_int_calc_flag = false');
5640         end if;
5641         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount = ' || l_increased_amount);
5642         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increased_amount1 = ' || l_increased_amount1);
5643         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_increase_amount_instal = ' || l_increase_amount_instal);
5644 
5645         -- getting current frequency record
5646         LNS_FIN_UTILS.fetchPayFreqRecByDate(
5647             p_FREQUENCY_SCHEDULE => l_freq_schedule_tbl,
5648             p_DATE => l_payment_tbl(l_installment_number).PERIOD_DUE_DATE,
5649             x_FREQUENCY_REC	=> l_FREQUENCY_REC);
5650         l_payment_frequency := l_FREQUENCY_REC.FREQUENCY;
5651 
5652         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_payment_frequency = ' || l_prev_payment_frequency);
5653         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payment_frequency = ' || l_payment_frequency);
5654 
5655         -- conditions to recalculate payment
5656         -- 1. 1-st installment
5657         -- 2. previous interest rate <> current interest rate
5658         -- 3. reamortization from installment = current installment
5659         -- 4. emerging from interest only period
5660         -- 5. reamortize because loan term has been extended
5661         -- 6. funded amount has increased since last installment
5662 
5663         if ((l_installment_number = 1) OR
5664             (l_annualized_rate <> l_previous_annualized) OR
5665             (l_reamortize_from_installment >= 0 and (l_last_installment_billed + 1 = l_installment_number)) OR
5666             (l_previous_interest_only_flag = 'Y' and  l_interest_only_flag = 'N') OR
5667             (l_extend_from_installment is not null and (l_extend_from_installment + 1 >= l_installment_number)) OR
5668             (l_prev_increase_amount_instal = l_installment_number or l_increase_amount_instal = l_installment_number) OR
5669             (l_payment_frequency <> l_prev_payment_frequency))
5670         then
5671 
5672             -- we need to recalculate the payment_amount
5673             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': RE-calculating periodic payment');
5674             l_amortization_intervals      := l_amortization_intervals_orig - l_installment_number + 1;
5675 
5676             if (l_calc_method = 'SIMPLE') then
5677 
5678                 l_rate_to_calculate := lns_financials.getPeriodicRate(
5679                                             p_payment_freq      => l_payment_frequency
5680                                             ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5681                                             ,p_period_end_date   => l_maturity_date
5682                                             ,p_annualized_rate   => l_annualized_rate
5683                                             ,p_days_count_method => l_day_count_method
5684                                             ,p_target            => 'PAYMENT');
5685 
5686             elsif (l_calc_method = 'COMPOUND') then
5687 
5688                 l_rate_to_calculate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5689                                     ,p_payment_freq => l_payment_frequency
5690                                     ,p_annualized_rate => l_annualized_rate
5691                                     ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5692                                     ,p_period_end_date => l_maturity_date
5693                                     ,p_days_count_method => l_day_count_method
5694                                     ,p_target => 'PAYMENT');
5695 
5696             end if;
5697 
5698             -- we need to calculate payment ONCE per interest rate change
5699             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_rate_to_calculate = ' || l_rate_to_calculate);
5700             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_amortization_intervals = ' || l_amortization_intervals);
5701 
5702             l_remaining_balance := l_remaining_balance_theory + l_increased_amount1;
5703 
5704             if l_rate_details.rate_id = l_rate_tbl(1).rate_id then
5705                 l_periodic_payment := lns_financials.calculatePayment(p_loan_amount   => l_remaining_balance
5706                                                             ,p_periodic_rate => l_rate_to_calculate
5707                                                             ,p_num_intervals => l_amortization_intervals
5708                                                             ,p_ending_balance=> l_balloon_amount
5709                                                             ,p_pay_in_arrears=> l_pay_in_arrears);
5710             else
5711                 l_periodic_payment := lns_financials.calculatePayment(p_loan_amount   => l_remaining_balance
5712                                                             ,p_periodic_rate => l_rate_to_calculate
5713                                                             ,p_num_intervals => l_amortization_intervals
5714                                                             ,p_ending_balance=> l_balloon_amount
5715                                                             ,p_pay_in_arrears=> true);
5716             end if;
5717 
5718             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': NEW periodic payment = ' || l_periodic_payment);
5719 
5720         else
5721             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': KEEPING OLD periodic payment = ' || l_periodic_payment);
5722         end if;
5723 
5724         l_norm_interest := 0;
5725         l_add_prin_interest := 0;
5726         l_add_int_interest := 0;
5727         l_penal_prin_interest := 0;
5728         l_penal_int_interest := 0;
5729         l_penal_interest := 0;
5730         l_early_pay_cr := 0;
5731         l_norm_int_detail_str := null;
5732         l_add_prin_int_detail_str := null;
5733         l_add_int_int_detail_str := null;
5734         l_penal_prin_int_detail_str := null;
5735         l_penal_int_int_detail_str := null;
5736         l_penal_int_detail_str := null;
5737         l_early_pay_cr_detail_str := null;
5738 
5739         -- now we will caculate the interest due for this period
5740        if (p_based_on_terms = 'CURRENT' and l_detail_int_calc_flag = true) then
5741 
5742             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
5743             LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => l_loan_id,
5744                                 p_calc_method => l_calc_method,
5745                                 p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5746                                 p_period_end_date => l_payment_tbl(l_installment_number).period_end_date,
5747                                 p_interest_rate => l_annualized_rate,
5748                                 p_day_count_method => l_day_count_method,
5749                                 p_payment_freq => l_payment_frequency,
5750                                 p_compound_freq => l_compound_freq,
5751                                 p_adj_amount => l_sum_periodic_principal,
5752                                 p_CAP_AMOUNT => l_prev_cap_int,
5753                                 x_norm_interest => l_norm_interest,
5754                                 x_norm_int_details => l_norm_int_detail_str);
5755 
5756             l_norm_interest  := round(l_norm_interest, l_precision);
5757 
5758             if (l_installment_number-1) >= 0 and l_last_installment_billed + 1 = l_installment_number then
5759 
5760                 -- get additional interest start date
5761                 open c_get_last_bill_date(l_loan_id, (l_installment_number-1));
5762                 fetch c_get_last_bill_date into l_add_start_date;
5763                 close c_get_last_bill_date;
5764 
5765                 -- get additional interest end date
5766                 if trunc(sysdate) > trunc(l_payment_tbl(l_installment_number).period_end_date) then
5767                     l_add_end_date := l_payment_tbl(l_installment_number).period_end_date;
5768                 else
5769                     l_add_end_date := sysdate;
5770                 end if;
5771 
5772                 if (l_installment_number-1) > 0 then
5773                     l_prev_grace_end_date := l_payment_tbl(l_installment_number-1).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS;
5774                 else
5775                     l_prev_grace_end_date := l_payment_tbl(l_installment_number).period_begin_date;
5776                 end if;
5777 
5778                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
5779                 -- calculate additional interest on unpaid principal
5780                 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
5781                                     p_calc_method => l_calc_method,
5782                                     p_period_start_date => l_add_start_date,
5783                                     p_period_end_date => l_add_end_date,
5784                                     p_interest_rate => l_annualized_rate,
5785                                     p_day_count_method => l_day_count_method,
5786                                     p_payment_freq => l_payment_frequency,
5787                                     p_compound_freq => l_compound_freq,
5788                                     p_prev_grace_end_date => l_prev_grace_end_date,
5789                                     p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
5790                                     p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5791                                     p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
5792                                     p_target => 'UNPAID_PRIN',
5793                                     x_add_interest => l_add_prin_interest,
5794                                     x_penal_interest => l_penal_prin_interest,
5795                                     x_add_int_details => l_add_prin_int_detail_str,
5796                                     x_penal_int_details => l_penal_prin_int_detail_str);
5797                 l_add_prin_interest  := round(l_add_prin_interest, l_precision);
5798 
5799                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
5800                 -- calculate additional interest on unpaid interest
5801                 LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => l_loan_id,
5802                                     p_calc_method => l_calc_method,
5803                                     p_period_start_date => l_add_start_date,
5804                                     p_period_end_date => l_add_end_date,
5805                                     p_interest_rate => l_annualized_rate,
5806                                     p_day_count_method => l_day_count_method,
5807                                     p_payment_freq => l_payment_frequency,
5808                                     p_compound_freq => l_compound_freq,
5809                                     p_prev_grace_end_date => l_prev_grace_end_date,
5810                                     p_penal_int_rate => p_loan_details.PENAL_INT_RATE,
5811                                     p_grace_start_date => l_payment_tbl(l_installment_number).period_begin_date,
5812                                     p_grace_end_date => (l_payment_tbl(l_installment_number).period_begin_date + p_loan_details.PENAL_INT_GRACE_DAYS),
5813                                     p_target => 'UNPAID_INT',
5814                                     x_add_interest => l_add_int_interest,
5815                                     x_penal_interest => l_penal_int_interest,
5816                                     x_add_int_details => l_add_int_int_detail_str,
5817                                     x_penal_int_details => l_penal_int_int_detail_str);
5818                 l_add_int_interest  := round(l_add_int_interest, l_precision);
5819 
5820                 if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
5821                     l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
5822                 else
5823                     l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
5824                 end if;
5825 
5826                 -- calculate interest credit on early payment
5827                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
5828                 LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => l_loan_id,
5829                                     p_calc_method => l_calc_method,
5830                                     p_installment => l_installment_number,
5831                                     p_interest_rate => l_previous_annualized,
5832                                     p_day_count_method => l_day_count_method,
5833                                     p_payment_freq => l_payment_frequency,
5834                                     p_compound_freq => l_compound_freq,
5835                                     x_early_pay_cr => l_early_pay_cr,
5836                                     x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
5837 
5838             end if;
5839 
5840        elsif (p_based_on_terms <> 'CURRENT' and l_detail_int_calc_flag = true and l_bill_on_appr_amounts = 'N') then
5841 
5842             if (l_calc_method = 'SIMPLE') then
5843 
5844                 l_periodic_rate := lns_financials.getPeriodicRate(
5845                                             p_payment_freq      => l_payment_frequency
5846                                             ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5847                                             ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
5848                                             ,p_annualized_rate   => l_annualized_rate
5849                                             ,p_days_count_method => l_day_count_method
5850                                             ,p_target            => 'INTEREST');
5851 
5852             elsif (l_calc_method = 'COMPOUND') then
5853 
5854                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5855                                 ,p_payment_freq => l_payment_frequency
5856                                 ,p_annualized_rate => l_annualized_rate
5857                                 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5858                                 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5859                                 ,p_days_count_method => l_day_count_method
5860                                 ,p_target => 'INTEREST');
5861 
5862             end if;
5863 
5864             lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
5865                                             ,p_from_date        => l_payment_tbl(l_installment_number).period_begin_date
5866                                             ,p_to_date          => l_payment_tbl(l_installment_number).period_end_date
5867                                             ,p_calc_method      => 'TARGET'
5868                                             ,p_phase            => 'TERM'
5869                                             ,p_day_count_method => l_day_count_method
5870                                             ,p_adj_amount       => l_sum_periodic_principal
5871                                             ,x_wtd_balance      => l_wtd_balance
5872                                             ,x_begin_balance    => l_balance1
5873                                             ,x_end_balance      => l_balance2);
5874 
5875             l_wtd_balance := l_wtd_balance + l_prev_cap_int;
5876             l_norm_interest := lns_financials.calculateInterest(p_amount => l_wtd_balance
5877                                                                 ,p_periodic_rate => l_periodic_rate
5878                                                                 ,p_compounding_period => null);
5879             l_norm_interest := round(l_norm_interest, l_precision);
5880 
5881             l_norm_int_detail_str := l_norm_interest || ' (' ||
5882                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
5883                 ' * Balance ' || l_wtd_balance ||
5884                 ' * Rate ' || l_annualized_rate || '%)';
5885             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
5886 
5887        else
5888 
5889             l_remaining_balance_theory1 := l_remaining_balance_theory + l_prev_cap_int;
5890             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_remaining_balance_theory1);
5891 
5892             if (l_calc_method = 'SIMPLE') then
5893 
5894                 l_periodic_rate := lns_financials.getPeriodicRate(
5895                                         p_payment_freq      => l_payment_frequency
5896                                         ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5897                                         ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
5898                                         ,p_annualized_rate   => l_annualized_rate
5899                                         ,p_days_count_method => l_day_count_method
5900                                         ,p_target            => 'INTEREST');
5901 
5902             elsif (l_calc_method = 'COMPOUND') then
5903 
5904                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
5905                                 ,p_payment_freq => l_payment_frequency
5906                                 ,p_annualized_rate => l_annualized_rate
5907                                 ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
5908                                 ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
5909                                 ,p_days_count_method => l_day_count_method
5910                                 ,p_target => 'INTEREST');
5911 
5912             end if;
5913 
5914             l_norm_interest := lns_financials.calculateInterest(p_amount             => l_remaining_balance_theory1
5915                                                                 ,p_periodic_rate      => l_periodic_rate
5916                                                                 ,p_compounding_period => null);
5917 
5918             l_norm_interest := round(l_norm_interest, l_precision);
5919 
5920             l_norm_int_detail_str := l_norm_interest || ' (' ||
5921                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
5922                 ' * Balance ' || l_remaining_balance_theory1 ||
5923                 ' * Rate ' || l_annualized_rate || '%)';
5924             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
5925 
5926        end if;
5927 
5928        l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_precision);
5929        l_periodic_interest := round(l_norm_interest + l_add_prin_interest + l_add_int_interest + l_penal_interest - l_early_pay_cr, l_precision);
5930 
5931        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_payment = ' || l_periodic_payment);
5932        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
5933        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_penal_interest = ' || l_penal_interest);
5934        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_intervals_remaining = ' || l_intervals_remaining);
5935        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled_principal = ' || l_unbilled_principal);
5936 
5937        -- check to see if we are in an interest only period
5938        -- if this is the case then the periodic_principal = 0
5939        -- there is a chance that the loan negatively amortizes
5940        if l_interest_only_flag <> 'Y' or l_intervals_remaining = 1 then
5941 
5942            logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calculating principal due');
5943 
5944            if p_loan_details.FLUCTUATE_EQ_PAY_AMOUNT = 'N' then   -- Include additional interest into Equal Payment
5945                 l_periodic_principal := l_periodic_payment - l_periodic_interest;
5946            else  -- DONT Include additional interest into Equal Payment
5947                 l_periodic_principal := l_periodic_payment - l_norm_interest;
5948            end if;
5949 
5950            l_periodic_principal := round(l_periodic_principal, l_precision);
5951            logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal = ' || l_periodic_principal);
5952 
5953            -- this is temporary according to not letting amortizations go negative
5954            if l_periodic_principal < 0 then
5955               logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': DISALLOW NEGATIVE AMORTIZATION');
5956               l_periodic_principal := 0;
5957            end if;
5958 
5959            -- make sure the final installment gets the remaining balance on the loan irregardless
5960            if (l_remaining_balance_theory + l_increased_amount1) < l_periodic_principal then
5961               l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
5962               logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
5963            else
5964                if l_intervals_remaining = 1 then
5965                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATING LAST INSTALLMENT PRINCIPAL');
5966                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_unbilled principal = ' || l_unbilled_principal);
5967                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
5968                     if p_based_on_terms = 'CURRENT' and l_unbilled_principal > 0 then
5969                         l_periodic_principal := l_unbilled_principal;
5970                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_unbilled_principal');
5971                     else
5972                         l_periodic_principal := l_remaining_balance_theory + l_increased_amount1;
5973                         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_principal := l_remaining_balance_theory');
5974                     end if;
5975                end if;
5976            end if;
5977 
5978        else
5979            -- we are in an interest only period
5980            l_periodic_principal := 0;
5981 
5982        end if;
5983 
5984        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_remaining_balance_theory = ' || l_remaining_balance_theory);
5985        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': principal = ' || l_periodic_principal);
5986 
5987        -- calculate balances
5988        l_begin_balance        := l_remaining_balance_theory;
5989        l_end_balance          := l_remaining_balance_theory - l_periodic_principal + l_increased_amount1;
5990 
5991        -- check to see if this loan has been billed
5992        if l_unbilled_principal > 0 then
5993          l_unbilled_principal := l_unbilled_principal - l_periodic_principal;
5994        end if;
5995 
5996        -- build the amortization record
5997        l_amortization_rec.installment_number   := l_installment_number;  /* needed to calculate fees */
5998        l_amortization_rec.due_date             := l_payment_tbl(l_installment_number).period_due_date;
5999        l_amortization_rec.PERIOD_START_DATE    := l_payment_tbl(l_installment_number).period_begin_date;
6000        l_amortization_rec.PERIOD_END_DATE      := l_payment_tbl(l_installment_number).period_end_date;
6001        l_amortization_rec.principal_amount     := l_periodic_principal;  /* needed to calculate fees */
6002        l_amortization_rec.interest_amount      := l_periodic_interest;
6003        l_amortization_rec.rate_id              := l_current_rate_id;
6004        l_amortization_rec.rate_unadj           := l_annualized_rate;
6005        l_amortization_rec.RATE_CHANGE_FREQ     := p_loan_details.TERM_RATE_CHG_FREQ;
6006        l_amortization_rec.UNPAID_PRIN          := l_unpaid_principal;
6007        l_amortization_rec.UNPAID_INT           := l_unpaid_interest;
6008        l_amortization_rec.INTEREST_RATE        := l_annualized_rate;
6009        l_amortization_rec.NORMAL_INT_AMOUNT    := l_norm_interest;
6010        l_amortization_rec.ADD_PRIN_INT_AMOUNT  := l_add_prin_interest;
6011        l_amortization_rec.ADD_INT_INT_AMOUNT   := l_add_int_interest;
6012        l_amortization_rec.PENAL_INT_AMOUNT     := l_penal_interest;
6013        l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
6014        l_amortization_rec.DISBURSEMENT_AMOUNT  := l_increased_amount;
6015        l_amortization_rec.FUNDED_AMOUNT        := l_end_funded_amount;
6016        l_amortization_rec.PREV_DEFERRED_INT_AMOUNT  := 0;
6017        l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
6018        l_amortization_rec.EARLY_PAY_CR_AMOUNT  := -l_early_pay_cr;
6019 
6020        if l_amortization_rec.FUNDED_AMOUNT is null then
6021             l_amortization_rec.FUNDED_AMOUNT := 0;
6022        end if;
6023 
6024        l_cap_int_detail_str := null;
6025        l_amortization_rec.CURR_CAP_INT_AMOUNT := 0;
6026        if p_loan_details.CAPITALIZE_INT = 'Y' then
6027             l_amortization_rec.begin_balance := l_begin_balance + l_prev_cap_int;
6028             if l_end_balance = 0 and l_amortization_rec.interest_amount > 0 then
6029                 l_amortization_rec.end_balance := l_end_balance;
6030                 l_amortization_rec.PREV_CAP_INT_AMOUNT := l_prev_cap_int;
6031                 l_amortization_rec.CAP_INT_AMOUNT := 0;
6032                 l_prev_cap_int := 0;
6033                 l_amortization_rec.interest_amount := l_amortization_rec.interest_amount + l_amortization_rec.PREV_CAP_INT_AMOUNT;
6034             else
6035                 l_amortization_rec.end_balance := l_end_balance + l_prev_cap_int;
6036                 l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
6037                 l_amortization_rec.CAP_INT_AMOUNT := l_prev_cap_int + l_amortization_rec.interest_amount;
6038                 if l_amortization_rec.CAP_INT_AMOUNT > 0 then
6039                     if l_prev_cap_int <> 0 then
6040                         l_cap_int_detail_str := 'Previously Capitalized Interest ' || l_prev_cap_int;
6041                     end if;
6042                     if l_norm_interest <> 0 then
6043                         if l_cap_int_detail_str is not null then
6044                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6045                         end if;
6046                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Normal Interest ' || l_norm_int_detail_str;
6047                     end if;
6048                     if l_add_prin_interest <> 0 then
6049                         if l_cap_int_detail_str is not null then
6050                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6051                         end if;
6052                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Prin ' || l_add_prin_int_detail_str;
6053                     end if;
6054                     if l_add_int_interest <> 0 then
6055                         if l_cap_int_detail_str is not null then
6056                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6057                         end if;
6058                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Add Int on Unpaid Interest ' || l_add_int_int_detail_str;
6059                     end if;
6060                     if l_penal_interest <> 0 then
6061                         if l_cap_int_detail_str is not null then
6062                             l_cap_int_detail_str := l_cap_int_detail_str || ' +<br>';
6063                         end if;
6064                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Penal Interest ' || l_penal_interest || ' (' || l_penal_int_detail_str || ')';
6065                     end if;
6066                     if l_early_pay_cr <> 0 then
6067                         if l_cap_int_detail_str is not null then
6068                             l_cap_int_detail_str := l_cap_int_detail_str || ' -<br>';
6069                         end if;
6070                         l_cap_int_detail_str := l_cap_int_detail_str || 'Current Int Cr on Early Payment ' || l_early_pay_cr || ' (' || l_early_pay_cr_detail_str || ')';
6071                     end if;
6072                 end if;
6073                 l_prev_cap_int := l_amortization_rec.CAP_INT_AMOUNT;
6074                 if l_amortization_rec.NORMAL_INT_AMOUNT > 0 then
6075                     l_norm_int_detail_str := 'Interest amount is capitalized';
6076                 end if;
6077 
6078                 l_amortization_rec.CURR_CAP_INT_AMOUNT := l_amortization_rec.interest_amount;
6079                 l_amortization_rec.interest_amount      := 0;
6080                 l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
6081                 l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
6082                 l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
6083                 l_amortization_rec.PENAL_INT_AMOUNT     := 0;
6084                 l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
6085 
6086                 l_add_prin_int_detail_str := null;
6087                 l_add_int_int_detail_str := null;
6088                 l_penal_prin_int_detail_str := null;
6089                 l_penal_int_int_detail_str := null;
6090                 l_penal_int_detail_str := null;
6091                 l_early_pay_cr_detail_str := null;
6092             end if;
6093        else
6094             l_amortization_rec.begin_balance := l_begin_balance;
6095             l_amortization_rec.end_balance := l_end_balance;
6096             l_amortization_rec.PREV_CAP_INT_AMOUNT := 0;
6097             l_amortization_rec.CAP_INT_AMOUNT := 0;
6098             l_prev_cap_int := 0;
6099        end if;
6100         l_amortization_rec.total := l_amortization_rec.principal_amount + l_amortization_rec.interest_amount;
6101 
6102         l_fees_tbl.delete;
6103         l_fee_amount := 0;
6104         l_other_amount := 0;
6105 
6106         -- filling out basis table
6107         l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
6108         l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
6109         l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
6110         l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
6111         l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
6112         l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
6113         l_fee_basis_tbl(4).fee_basis_name   := 'OVERDUE_PRIN';
6114         l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
6115         l_fee_basis_tbl(5).fee_basis_name   := 'OVERDUE_PRIN_INT';
6116         l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
6117         l_fee_basis_tbl(6).fee_basis_name   := 'IND_DISB_AMT';
6118         l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
6119         l_fee_basis_tbl(7).fee_basis_name   := 'TOTAL_UNDISB_AMT';
6120         l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
6121         l_fee_basis_tbl(8).fee_basis_name   := 'OVERDUE_INT';
6122         l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
6123         l_fee_basis_tbl(9).fee_basis_name   := 'CURR_LOAN';
6124         l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
6125 
6126         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
6127         LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
6128                                     ,p_loan_id        => l_loan_id
6129                                     ,p_installment    => l_installment_number
6130                                     ,p_fee_basis_tbl  => l_fee_basis_tbl
6131                                     ,p_based_on_terms => p_based_on_terms
6132                                     ,p_phase          => 'TERM'
6133                                     ,x_fees_tbl       => l_fees_tbl
6134                                     ,x_return_status  => l_return_status
6135                                     ,x_msg_count      => l_msg_count
6136                                     ,x_msg_data       => l_msg_data);
6137 
6138         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
6139         if l_return_status <> 'S' then
6140             RAISE FND_API.G_EXC_ERROR;
6141         end if;
6142 
6143         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
6144 
6145         for k in 1..l_fees_tbl.count loop
6146             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
6147             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
6148             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
6149             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
6150             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
6151             if l_fees_tbl(k).FEE_CATEGORY = 'MEMO' then
6152                 l_other_amount := l_other_amount + l_fees_tbl(k).FEE_AMOUNT;
6153             else
6154                 l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
6155             end if;
6156         end loop;
6157 
6158        l_amortization_rec.fee_amount           := l_fee_amount;
6159        l_amortization_rec.other_amount         := l_other_amount;
6160        l_amortization_rec.total                := l_amortization_rec.total + l_amortization_rec.fee_amount + l_amortization_rec.other_amount;
6161 
6162        -- running totals calculated here
6163        l_principal_cumulative := l_principal_cumulative + l_amortization_rec.principal_amount;
6164        l_interest_cumulative  := l_interest_cumulative + l_amortization_rec.interest_amount;
6165        l_fees_cumulative      := l_fees_cumulative + l_amortization_rec.fee_amount;
6166        l_other_cumulative     := l_other_cumulative + l_amortization_rec.other_amount;
6167 
6168        l_amortization_rec.interest_cumulative  := l_interest_cumulative;
6169        l_amortization_rec.principal_cumulative := l_principal_cumulative;
6170        l_amortization_rec.fees_cumulative      := l_fees_cumulative;
6171        l_amortization_rec.other_cumulative     := l_other_cumulative;
6172        l_amortization_rec.rate_id              := l_current_rate_id;
6173        l_amortization_rec.SOURCE               := 'PREDICTED';
6174 
6175        l_amortization_rec.NORMAL_INT_DETAILS   := l_norm_int_detail_str;
6176        l_amortization_rec.ADD_PRIN_INT_DETAILS := l_add_prin_int_detail_str;
6177        l_amortization_rec.ADD_INT_INT_DETAILS  := l_add_int_int_detail_str;
6178        l_amortization_rec.PENAL_INT_DETAILS    := l_penal_int_detail_str;
6179        l_amortization_rec.CAP_INT_DETAILS      := l_cap_int_detail_str;
6180        l_amortization_rec.EARLY_PAY_CR_DETAILS := l_early_pay_cr_detail_str;
6181 
6182        -- add the record to the amortization table
6183        l_amortization_tbl(i)                   := l_amortization_rec;
6184 
6185        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
6186        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INSTALLMENT ' || l_installment_number);
6187        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
6188        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD = ' || l_amortization_rec.PERIOD);
6189        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_START_DATE = ' || l_amortization_rec.PERIOD_START_DATE);
6190        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PERIOD_END_DATE = ' || l_amortization_rec.PERIOD_END_DATE);
6191        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'due date = ' || l_amortization_rec.due_date);
6192        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_principal = ' || l_amortization_rec.principal_amount);
6193        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_interest = ' || l_amortization_rec.interest_amount);
6194        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fee_amount = ' || l_amortization_rec.fee_amount);
6195        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_amount = ' || l_amortization_rec.other_amount);
6196        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'total = ' || l_amortization_rec.total);
6197        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'begin_balance = ' || l_amortization_rec.begin_balance);
6198        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'end_balance = ' || l_amortization_rec.end_balance);
6199        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'interest_cumulative = ' || l_amortization_rec.interest_cumulative);
6200        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'principal_cumulative = ' || l_amortization_rec.principal_cumulative);
6201        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'fees_cumulative = ' || l_amortization_rec.fees_cumulative);
6202        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'other_cumulative = ' || l_amortization_rec.other_cumulative);
6203        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'current_rate_id = ' || l_amortization_rec.rate_id );
6204        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_RATE = ' || l_amortization_rec.INTEREST_RATE );
6205        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_PRIN = ' || l_amortization_rec.UNPAID_PRIN );
6206        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'UNPAID_INT = ' || l_amortization_rec.UNPAID_INT );
6207        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
6208        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_AMOUNT = ' || l_amortization_rec.ADD_PRIN_INT_AMOUNT );
6209        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_AMOUNT );
6210        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_AMOUNT = ' || l_amortization_rec.PENAL_INT_AMOUNT );
6211        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FUNDED_AMOUNT = ' || l_amortization_rec.FUNDED_AMOUNT );
6212        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amortization_rec.NORMAL_INT_DETAILS );
6213        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_PRIN_INT_DETAILS = ' || l_amortization_rec.ADD_PRIN_INT_DETAILS );
6214        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ADD_INT_INT_DETAILS_AMOUNT = ' || l_amortization_rec.ADD_INT_INT_DETAILS );
6215        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PENAL_INT_DETAILS = ' || l_amortization_rec.PENAL_INT_DETAILS );
6216        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amortization_rec.PREV_CAP_INT_AMOUNT );
6217        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amortization_rec.CURR_CAP_INT_AMOUNT );
6218        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amortization_rec.CAP_INT_AMOUNT );
6219        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amortization_rec.CAP_INT_DETAILS );
6220        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_AMOUNT = ' || l_amortization_rec.EARLY_PAY_CR_AMOUNT );
6221        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'EARLY_PAY_CR_DETAILS = ' || l_amortization_rec.EARLY_PAY_CR_DETAILS );
6222        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '********************************************');
6223 
6224        l_remaining_balance_theory :=  l_end_balance;
6225        l_sum_periodic_principal := l_sum_periodic_principal + l_periodic_principal;
6226 
6227        l_previous_interest_only_flag := l_interest_only_flag;
6228        l_previous_rate_id            := l_current_rate_id;
6229        l_previous_annualized         := l_annualized_rate;
6230        l_prev_payment_frequency      := l_payment_frequency;
6231 
6232     end loop;
6233 
6234     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT = ' || l_amortization_tbl.count);
6235     x_loan_amort_tbl := l_amortization_tbl;
6236 
6237     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6238 
6239  Exception
6240     WHEN FND_API.G_EXC_ERROR THEN
6241          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6242 
6243     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6244          logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
6245 
6246     WHEN OTHERS THEN
6247          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6248 
6249 end amortizeLoan;
6250 
6251 /*=========================================================================
6252 || PUBLIC PROCEDURE amortizeLoan
6253 ||
6254 || DESCRIPTION
6255 ||
6256 || Overview:  amortizes a loan
6257 ||            this api assumes the loan information is in the
6258 ||            Loans DataModel
6259 ||
6260 || Parameter: p_loan_id  => Loan ID
6261 ||
6262 || Source Tables: NA
6263 ||
6264 || Target Tables: NA
6265 ||
6266 || Return value: x_loan_amort_tbl table of amortization_records
6267 ||
6268 || KNOWN ISSUES
6269 ||
6270 || NOTES
6271 ||
6272 || MODIFICATION HISTORY
6273 || Date                 Author            Description of Changes
6274 || 12/09/2003 1:51PM    raverma           Created
6275 || 04/07/2004           raverma           alter so we dont need to loop thru
6276 ||                                        whole amortization
6277  *=======================================================================*/
6278 procedure amortizeLoan (p_loan_Id            in number
6279                        ,p_based_on_terms     in varchar2
6280                        ,p_installment_number in number
6281                        ,x_loan_amort_tbl     out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
6282 
6283 is
6284     l_loan_details                   LOAN_DETAILS_REC;
6285     l_amortization_tbl               amortization_tbl;
6286     l_rate_tbl                       RATE_SCHEDULE_TBL;
6287     l_api_name                       varchar2(20);
6288 begin
6289 
6290      l_api_name  := 'amortizeLoan';
6291      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6292      l_loan_details  := lns_financials.getLoanDetails(p_loan_Id         => p_loan_id
6293                                                      ,p_based_on_terms  => p_based_on_terms
6294 									                 ,p_phase           => 'TERM');
6295 
6296      l_rate_tbl := lns_financials.getRateSchedule(p_loan_id, 'TERM');
6297 
6298      if (l_loan_details.PAYMENT_CALC_METHOD = 'EQUAL_PRINCIPAL') then
6299 
6300         lns_financials.amortizeEPLoan(p_loan_details       => l_loan_details
6301                                     ,p_rate_schedule      => l_rate_tbl
6302                                     ,p_based_on_terms     => p_based_on_terms
6303                                     ,p_installment_number => p_installment_number
6304                                     ,x_loan_amort_tbl     => l_amortization_tbl);
6305 
6306      elsif (l_loan_details.PAYMENT_CALC_METHOD = 'SEPARATE_SCHEDULES') then
6307 
6308         lns_financials.amortizeSIPLoan(p_loan_details       => l_loan_details
6309                                     ,p_rate_schedule      => l_rate_tbl
6310                                     ,p_based_on_terms     => p_based_on_terms
6311                                     ,p_installment_number => p_installment_number
6312                                     ,x_loan_amort_tbl     => l_amortization_tbl);
6313 
6314      elsif (l_loan_details.PAYMENT_CALC_METHOD = 'EQUAL_PAYMENT') then
6315 
6316         lns_financials.amortizeLoan(p_loan_details       => l_loan_details
6317                                     ,p_rate_schedule      => l_rate_tbl
6318                                     ,p_based_on_terms     => p_based_on_terms
6319                                     ,p_installment_number => p_installment_number
6320                                     ,x_loan_amort_tbl     => l_amortization_tbl);
6321 
6322      end if;
6323 
6324      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' Tbl count is ' || l_amortization_tbl.count);
6325 
6326      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6327      x_loan_amort_tbl := l_amortization_tbl;
6328 Exception
6329     When others then
6330         null;
6331 
6332 end amortizeLoan;
6333 
6334 /*=========================================================================
6335 || PUBLIC PROCEDURE loanProjection
6336 ||
6337 || DESCRIPTION
6338 ||
6339 || Overview: procedure will project an open ended loan
6340 ||           1. Amortization UI - when creating a loan
6341 ||           2. Billing Engine  - to generate bills
6342 ||
6343 || Parameter: p_loan_details  = details of the loan
6344 ||            p_rate_schedule = rate schedule for the loan
6345 ||            x_loan_amort_tbl => table of loan records
6346 ||
6347 || Source Tables:  NA
6348 ||
6349 || Target Tables:
6350 ||
6351 ||
6352 || KNOWN ISSUES
6353 ||         Currently only support single rate
6354 || NOTES
6355 ||
6356 || MODIFICATION HISTORY
6357 || Date                  Author            Description of Changes
6358 || 07/20/2005 11:35AM     raverma           Created
6359  *=======================================================================*/
6360 procedure loanProjection(p_loan_details       in  LNS_FINANCIALS.LOAN_DETAILS_REC
6361                         ,p_based_on_terms     in  varchar2
6362                         ,p_rate_schedule      in  LNS_FINANCIALS.RATE_SCHEDULE_TBL
6363                         ,x_loan_amort_tbl     out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
6364 is
6365     l_return_status                  varchar2(1);
6366     l_msg_count                      NUMBER;
6367     l_msg_data                       VARCHAR2(32767);
6368     -- loan_details
6369     l_loan_id                        number;
6370     l_original_loan_amount           number;  -- loan amount
6371     l_first_payment_date             date;
6372     l_pay_in_arrears                 boolean;
6373     l_payment_frequency              varchar2(30);
6374     l_day_count_method               varchar2(30);
6375     l_intervals_original             number;
6376     l_intervals                      number;
6377     l_intervals_remaining            number;
6378     l_rate_details                   LNS_FINANCIALS.INTEREST_RATE_REC;
6379     l_precision                      number;
6380 
6381     l_period_start_Date              date;
6382     l_period_end_date                date;
6383     l_periodic_rate                  number;
6384     l_maturity_date                  date;
6385 
6386     l_amortization_rec               LNS_FINANCIALS.AMORTIZATION_REC;
6387     l_amortization_tbl               LNS_FINANCIALS.AMORTIZATION_TBL;
6388     l_rate_tbl                       LNS_FINANCIALS.RATE_SCHEDULE_TBL;
6389     l_payment_tbl                    LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
6390     l_loan_start_date                date;
6391     l_num_pay_dates                  number;  -- number of dates on installment schedule
6392     l_periodic_payment               number;
6393     l_periodic_principal             number;
6394     l_periodic_interest              number;
6395     l_total_principal                number;
6396     l_payment_number                 number;
6397     l_fee_amount                     number;
6398     l_begin_balance                  number;
6399     l_end_balance                    number;
6400     l_unbilled_principal             number;
6401     l_unpaid_principal               number;
6402     --l_open_rate_type                 varchar2(30);
6403     l_open_rate_change_frequency     varchar2(30);
6404     l_open_index_rate_id             number;
6405     l_open_index_date                date;
6406     l_open_ceiling_rate              number;
6407     l_open_floor_rate                number;
6408     l_unpaid_interest                number;
6409 
6410     l_wtd_balance                    number;
6411     l_total                          number;
6412     l_interest_cumulative            number;
6413     l_principal_cumulative           number;
6414     l_fees_cumulative                number;
6415     i                                number;  -- for installments
6416 	k                                number;  -- for disbursements
6417     l_installment_number             number;
6418     l_api_name                       varchar2(20);
6419     l_last_installment_billed        number;
6420     l_rate_to_calculate              number;
6421     l_disb_header_id                 number;
6422     l_disb_amount                    number;
6423     l_total_disbursed	             number;
6424     l_calc_method                    varchar2(30);
6425     l_compound_freq                  varchar2(30);
6426     l_annualized_rate                number;
6427     l_billed                         varchar2(1);
6428     n                                number;
6429     l_norm_int_detail_str            varchar2(2000);
6430     l_prev_end_balance               number;
6431 
6432     l_fees_tbl                       LNS_FEE_ENGINE.FEE_CALC_TBL;
6433     l_fee_basis_tbl                  LNS_FEE_ENGINE.FEE_BASIS_TBL;
6434     l_freq_schedule_tbl              LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
6435 
6436     cursor c_total_disbursed(p_loan_id number, p_from_date date, p_to_date date) is
6437         select nvl(sum(header_amount), 0)
6438         from lns_disb_headers
6439         where loan_id = p_loan_id
6440         and trunc(payment_request_date) >= p_from_date
6441         and trunc(payment_request_date) < p_to_date;
6442 
6443 begin
6444 
6445     -- initialize all variables
6446     l_original_loan_amount           := 0;  -- loan amount
6447     l_periodic_payment               := 0;
6448     l_periodic_principal             := 0;
6449     l_periodic_interest              := 0;
6450     l_total_principal                := 0;
6451     l_payment_number                 := 0;
6452     l_fee_amount                     := 0;
6453     l_begin_balance                  := 0;
6454     l_unbilled_principal             := 0;
6455     l_unpaid_principal               := 0;
6456     l_total                          := 0;
6457     l_interest_cumulative            := 0;
6458     l_principal_cumulative           := 0;
6459     l_fees_cumulative                := 0;
6460     i                                := 0;
6461     l_installment_number             := 1;  -- begin from #1 installment, NOT #0 installment
6462     l_rate_to_calculate              := 0;
6463 	l_total_disbursed				 := 0;
6464     l_api_name                       := 'loanProjection';
6465 
6466     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6467 
6468     l_payment_frequency             := p_loan_details.payment_frequency;
6469     l_first_payment_date            := p_loan_details.first_payment_date;
6470     l_original_loan_amount          := p_loan_details.requested_amount; --funded_amount;
6471     l_maturity_date                 := p_loan_details.maturity_date;
6472     l_intervals                     := p_loan_details.number_installments;
6473     l_last_installment_billed       := p_loan_details.last_installment_billed;
6474     l_day_count_method              := p_loan_details.day_count_method;
6475     l_loan_start_date               := p_loan_details.loan_start_date;
6476     l_pay_in_arrears                := p_loan_details.pay_in_arrears_boolean;
6477     l_precision                     := p_loan_details.currency_precision;
6478     l_loan_id                       := p_loan_details.loan_id;
6479     -- use the projected rate which should be the last calculated rate on the loan
6480     l_periodic_rate                 := p_loan_details.OPEN_PROJECTED_INTEREST_RATE;
6481     l_calc_method                   := p_loan_details.CALCULATION_METHOD;
6482     l_compound_freq                 := p_loan_details.INTEREST_COMPOUNDING_FREQ;
6483     l_unpaid_principal              := p_loan_details.unpaid_principal;
6484     l_unpaid_interest               := p_loan_details.UNPAID_INTEREST;
6485 
6486     -- get the interest rate schedule
6487     l_rate_tbl := p_rate_schedule;
6488     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- rate schedule count = ' || l_rate_tbl.count);
6489 
6490     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- p_based_on_terms = ' || p_based_on_terms);
6491 
6492     -- get payment schedule
6493     -- this will return the acutal dates that payments will be due on
6494     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- getting payment schedule');
6495 
6496     l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
6497                                         P_LOAN_ID           => l_loan_id,
6498                                         P_PHASE             => 'OPEN',
6499                                         P_COMPONENT         => 'PRIN_INT');
6500 
6501     l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
6502                             p_loan_start_date      => l_loan_start_date,
6503                             p_loan_maturity_date  => l_maturity_date,
6504                             p_freq_schedule_tbl => l_freq_schedule_tbl);
6505 /*
6506     l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => l_loan_start_date
6507                                                        ,p_loan_maturity_date => l_maturity_date
6508                                                        ,p_first_pay_date     => l_first_payment_date
6509                                                        ,p_num_intervals      => l_intervals
6510                                                        ,p_interval_type      => l_payment_frequency
6511                                                        ,p_pay_in_arrears     => l_pay_in_arrears);
6512 */
6513     l_num_pay_dates := l_payment_tbl.count;
6514     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '- payment schedule count = ' || l_num_pay_dates);
6515 
6516     begin
6517         if p_based_on_terms = 'CURRENT' then
6518 
6519             lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
6520                                             ,p_from_date        => l_loan_start_date
6521                                             ,p_to_date          => l_loan_start_date
6522                                             ,p_calc_method      => 'ACTUAL'
6523                                             ,p_phase            => 'OPEN'
6524                                             ,p_day_count_method => l_day_count_method
6525                                             ,p_adj_amount       => 0
6526                                             ,x_wtd_balance      => l_wtd_balance
6527                                             ,x_begin_balance    => l_begin_balance
6528                                             ,x_end_balance      => l_end_balance);
6529 
6530         else
6531 
6532             lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
6533                                             ,p_from_date        => l_loan_start_date
6534                                             ,p_to_date          => l_loan_start_date
6535                                             ,p_calc_method      => 'TARGET'
6536                                             ,p_phase            => 'OPEN'
6537                                             ,p_day_count_method => l_day_count_method
6538                                             ,p_adj_amount       => 0
6539                                             ,x_wtd_balance      => l_wtd_balance
6540                                             ,x_begin_balance    => l_begin_balance
6541                                             ,x_end_balance      => l_end_balance);
6542 
6543         end if;
6544     exception
6545         when others then
6546         FND_MESSAGE.SET_NAME('LNS', 'LNS_COMPUTE_BALANCE_ERROR');
6547         FND_MSG_PUB.ADD;
6548         LogMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
6549         RAISE FND_API.G_EXC_ERROR;
6550     end;
6551 
6552     l_fees_tbl.delete;
6553     l_fee_amount := 0;
6554 
6555     -- filling out basis table
6556     l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
6557     l_fee_basis_tbl(1).fee_basis_amount := p_loan_details.remaining_balance;
6558     l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
6559     l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
6560     l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
6561     l_fee_basis_tbl(3).fee_basis_amount := l_end_balance;
6562     l_fee_basis_tbl(4).fee_basis_name   := 'TOTAL_UNDISB_AMT';
6563     l_fee_basis_tbl(4).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_end_balance;
6564 
6565     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for 0-th installment...');
6566     LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
6567                                 ,p_loan_id        => l_loan_id
6568                                 ,p_installment    => 0
6569                                 ,p_fee_basis_tbl  => l_fee_basis_tbl
6570                                 ,p_based_on_terms => p_based_on_terms
6571                                 ,p_phase          => 'OPEN'
6572                                 ,x_fees_tbl       => l_fees_tbl
6573                                 ,x_return_status  => l_return_status
6574                                 ,x_msg_count      => l_msg_count
6575                                 ,x_msg_data       => l_msg_data);
6576 
6577     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
6578     if l_return_status <> 'S' then
6579         RAISE FND_API.G_EXC_ERROR;
6580     end if;
6581 
6582     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
6583 
6584     for k in 1..l_fees_tbl.count loop
6585         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
6586         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
6587         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
6588         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
6589         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
6590         l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
6591     end loop;
6592     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for 0-th installment = ' || l_fee_amount);
6593 
6594     if l_fee_amount > 0 then
6595 
6596         i := i + 1;
6597         l_amortization_rec.installment_number   := 0;
6598         l_amortization_rec.due_date             := l_loan_start_date;
6599         l_amortization_rec.PERIOD_START_DATE    := l_loan_start_date;
6600         l_amortization_rec.PERIOD_END_DATE      := l_loan_start_date;
6601         l_amortization_rec.principal_amount     := 0;
6602         l_amortization_rec.interest_amount      := 0;
6603         l_amortization_rec.fee_amount           := l_fee_amount;
6604         l_amortization_rec.other_amount         := 0;
6605         l_amortization_rec.begin_balance        := l_begin_balance;
6606         l_amortization_rec.end_balance          := l_end_balance;
6607         l_amortization_rec.interest_cumulative  := 0;
6608         l_amortization_rec.principal_cumulative := 0;
6609         l_amortization_rec.fees_cumulative      := l_fee_amount;
6610         l_amortization_rec.other_cumulative     := 0;
6611         l_amortization_rec.rate_id              := 0;
6612         l_amortization_rec.SOURCE               := 'PREDICTED';
6613         -- add the record to the amortization table
6614         l_amortization_rec.total                := l_fee_amount;
6615         l_amortization_rec.UNPAID_PRIN          := 0;
6616         l_amortization_rec.UNPAID_INT           := 0;
6617         l_amortization_rec.INTEREST_RATE        := l_rate_tbl(1).annual_rate;
6618         l_amortization_rec.NORMAL_INT_AMOUNT    := 0;
6619         l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
6620         l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
6621         l_amortization_rec.PENAL_INT_AMOUNT     := 0;
6622         l_amortization_rec.NORMAL_INT_DETAILS   := null;
6623         l_amortization_rec.ADD_PRIN_INT_DETAILS := null;
6624         l_amortization_rec.ADD_INT_INT_DETAILS  := null;
6625         l_amortization_rec.PENAL_INT_DETAILS    := null;
6626         l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_loan_start_date, 1);
6627         l_amortization_rec.DISBURSEMENT_AMOUNT  := l_end_balance;
6628         l_amortization_rec.FUNDED_AMOUNT        := l_end_balance;
6629         l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
6630         l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
6631         l_amortization_rec.PREV_CAP_INT_AMOUNT  := 0;
6632         l_amortization_rec.CURR_CAP_INT_AMOUNT  := 0;
6633         l_amortization_rec.CAP_INT_AMOUNT       := 0;
6634         l_amortization_rec.CAP_INT_DETAILS      := null;
6635         l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
6636 
6637         l_amortization_tbl(i)                   := l_amortization_rec;
6638     end if;
6639 
6640     l_prev_end_balance := 0;
6641     -- loop to build the amortization schedule
6642     for l_installment_number in 1..l_num_pay_dates
6643     loop
6644 
6645        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' -----CALCULATING -----> installment #' || l_installment_number);
6646        i := i + 1;
6647        l_periodic_interest      := 0;
6648        l_fee_amount             := 0;
6649        l_intervals_remaining    := l_num_pay_dates - l_installment_number + 1;
6650        l_norm_int_detail_str    := null;
6651 
6652        -- get the weighted balance for the period
6653        begin
6654             if p_based_on_terms = 'CURRENT' then
6655 
6656                 lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
6657                                                 ,p_from_date        => l_payment_tbl(l_installment_number).period_begin_date
6658                                                 ,p_to_date          => l_payment_tbl(l_installment_number).period_end_date
6659                                                 ,p_calc_method      => 'ACTUAL'
6660                                                 ,p_phase            => 'OPEN'
6661                                                 ,p_day_count_method => l_day_count_method
6662                                                 ,p_adj_amount       => 0
6663                                                 ,x_wtd_balance      => l_wtd_balance
6664                                                 ,x_begin_balance    => l_begin_balance
6665                                                 ,x_end_balance      => l_end_balance);
6666 
6667             else
6668 
6669                 lns_financials.getWeightedBalance(p_loan_id         => l_loan_id
6670                                                 ,p_from_date       => l_payment_tbl(l_installment_number).period_begin_date
6671                                                 ,p_to_date         => l_payment_tbl(l_installment_number).period_end_date
6672                                                 ,p_calc_method     => 'TARGET'
6673                                                 ,p_phase            => 'OPEN'
6674                                                 ,p_day_count_method => l_day_count_method
6675                                                 ,p_adj_amount       => 0
6676                                                 ,x_wtd_balance      => l_wtd_balance
6677                                                 ,x_begin_balance    => l_begin_balance
6678                                                 ,x_end_balance      => l_end_balance);
6679 
6680             end if;
6681        exception
6682             when others then
6683             FND_MESSAGE.SET_NAME('LNS', 'LNS_COMPUTE_BALANCE_ERROR');
6684             FND_MSG_PUB.ADD;
6685             LogMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
6686             RAISE FND_API.G_EXC_ERROR;
6687        end;
6688 
6689        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - l_wtd_balance = ' || l_wtd_balance);
6690 
6691        -- now we will caculate the interest due for this period
6692        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest is based upon an amount of ' || l_wtd_balance);
6693 
6694        l_rate_details := getRateDetails(p_installment => l_installment_number
6695                                        ,p_rate_tbl    => l_rate_tbl);
6696 
6697        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate annual rate = ' || l_rate_details.annual_rate);
6698        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate spread = ' || l_rate_details.spread);
6699        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate id = ' || l_rate_details.rate_id);
6700 
6701        l_annualized_rate          := l_rate_details.annual_rate;
6702 
6703        -- recalculate periodic rate for each period if day counting methodolgy varies
6704        if (l_calc_method = 'SIMPLE') then
6705 
6706             l_periodic_rate := lns_financials.getPeriodicRate(
6707                                     p_payment_freq      => l_payment_frequency
6708                                     ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
6709                                     ,p_period_end_date   => l_payment_tbl(l_installment_number).period_end_date
6710                                     ,p_annualized_rate   => l_annualized_rate
6711                                     ,p_days_count_method => l_day_count_method
6712                                     ,p_target            => 'INTEREST');
6713 
6714        elsif (l_calc_method = 'COMPOUND') then
6715 
6716             l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => l_compound_freq
6717                             ,p_payment_freq => l_payment_frequency
6718                             ,p_annualized_rate => l_annualized_rate --p_loan_details.OPEN_PROJECTED_INTEREST_RATE
6719                             ,p_period_start_date => l_payment_tbl(l_installment_number).period_begin_date
6720                             ,p_period_end_date => l_payment_tbl(l_installment_number).period_end_date
6721                             ,p_days_count_method => l_day_count_method
6722                             ,p_target => 'INTEREST');
6723 
6724        end if;
6725        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate rate = ' || l_periodic_rate);
6726 
6727        -- if we are going to compound, then based on compounding the amount should be passed to calculateInterest call here.
6728        -- how do we determine what the amount to compound on
6729        -- for example: compound daily at .5% over 30 day period
6730        l_periodic_interest := lns_financials.calculateInterest(p_amount             => l_wtd_balance
6731                                                             ,p_periodic_rate      => l_periodic_rate
6732                                                             ,p_compounding_period => null);
6733 
6734        l_periodic_interest  := round(l_periodic_interest, l_precision);
6735        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_interest = ' || l_periodic_interest);
6736 
6737        l_norm_int_detail_str :=
6738             'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1) ||
6739             ' * Balance ' || l_wtd_balance ||
6740             ' * Rate ' || l_annualized_rate || '%';
6741        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
6742 
6743         --mark
6744        if l_installment_number = p_loan_details.number_installments and
6745            (p_loan_details.OPEN_TO_TERM_FLAG = 'N' OR p_loan_details.SECONDARY_STATUS = 'REMAINING_DISB_CANCELLED') then
6746             l_periodic_principal := p_loan_details.funded_amount;
6747        else
6748             l_periodic_principal := 0;
6749        end if;
6750 
6751        -- rest of the record can be built after fees are calculated
6752        l_amortization_rec.installment_number   := l_installment_number;
6753        l_amortization_rec.due_date             := l_payment_tbl(l_installment_number).period_due_date;
6754        l_amortization_rec.PERIOD_START_DATE    := l_payment_tbl(l_installment_number).period_begin_date;
6755        l_amortization_rec.PERIOD_END_DATE      := l_payment_tbl(l_installment_number).period_end_date;
6756        l_amortization_rec.principal_amount     := l_periodic_principal;
6757        l_amortization_rec.interest_amount      := l_periodic_interest;
6758        l_amortization_rec.begin_balance        := l_begin_balance;
6759        l_amortization_rec.end_balance          := l_end_balance;
6760        l_amortization_rec.other_amount         := 0;
6761        l_amortization_rec.UNPAID_PRIN          := l_unpaid_principal;
6762        l_amortization_rec.UNPAID_INT           := l_unpaid_interest;
6763        l_amortization_rec.INTEREST_RATE        := l_annualized_rate; --p_loan_details.OPEN_PROJECTED_INTEREST_RATE;
6764        l_amortization_rec.NORMAL_INT_AMOUNT    := l_periodic_interest;
6765        l_amortization_rec.ADD_PRIN_INT_AMOUNT  := 0;
6766        l_amortization_rec.ADD_INT_INT_AMOUNT   := 0;
6767        l_amortization_rec.PENAL_INT_AMOUNT     := 0;
6768        l_amortization_rec.NORMAL_INT_DETAILS   := l_norm_int_detail_str;
6769        l_amortization_rec.ADD_PRIN_INT_DETAILS := null;
6770        l_amortization_rec.ADD_INT_INT_DETAILS  := null;
6771        l_amortization_rec.PENAL_INT_DETAILS    := null;
6772        l_amortization_rec.PERIOD               := FND_DATE.DATE_TO_DISPLAYDATE(l_payment_tbl(l_installment_number).period_begin_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_payment_tbl(l_installment_number).period_end_date-1), 1);
6773        l_amortization_rec.DISBURSEMENT_AMOUNT  := l_end_balance - l_prev_end_balance;
6774        l_amortization_rec.FUNDED_AMOUNT        := l_end_balance;
6775        l_amortization_rec.PREV_DEFERRED_INT_AMOUNT := 0;
6776        l_amortization_rec.DEFERRED_INT_AMOUNT  := 0;
6777        l_amortization_rec.PREV_CAP_INT_AMOUNT  := 0;
6778        l_amortization_rec.CURR_CAP_INT_AMOUNT  := 0;
6779        l_amortization_rec.CAP_INT_AMOUNT       := 0;
6780        l_amortization_rec.CAP_INT_DETAILS      := null;
6781        l_amortization_rec.EARLY_PAY_CR_AMOUNT  := 0;
6782 
6783        if l_amortization_rec.FUNDED_AMOUNT is null then
6784             l_amortization_rec.FUNDED_AMOUNT := 0;
6785        end if;
6786 
6787         l_fees_tbl.delete;
6788         l_fee_amount := 0;
6789 
6790         -- filling out basis table
6791         l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
6792         l_fee_basis_tbl(1).fee_basis_amount := l_amortization_rec.begin_balance + l_amortization_rec.UNPAID_PRIN;
6793         l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
6794         l_fee_basis_tbl(2).fee_basis_amount := p_loan_details.requested_amount;
6795         l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
6796         l_fee_basis_tbl(3).fee_basis_amount := l_amortization_rec.FUNDED_AMOUNT;
6797         l_fee_basis_tbl(4).fee_basis_name   := 'OVERDUE_PRIN';
6798         l_fee_basis_tbl(4).fee_basis_amount := l_amortization_rec.UNPAID_PRIN;
6799         l_fee_basis_tbl(5).fee_basis_name   := 'OVERDUE_PRIN_INT';
6800         l_fee_basis_tbl(5).fee_basis_amount := l_amortization_rec.UNPAID_PRIN + l_amortization_rec.UNPAID_INT;
6801         l_fee_basis_tbl(6).fee_basis_name   := 'IND_DISB_AMT';
6802         l_fee_basis_tbl(6).fee_basis_amount := l_amortization_rec.DISBURSEMENT_AMOUNT;
6803         l_fee_basis_tbl(7).fee_basis_name   := 'TOTAL_UNDISB_AMT';
6804         l_fee_basis_tbl(7).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT - l_amortization_rec.FUNDED_AMOUNT;
6805         l_fee_basis_tbl(8).fee_basis_name   := 'OVERDUE_INT';
6806         l_fee_basis_tbl(8).fee_basis_amount := l_amortization_rec.UNPAID_INT;
6807         l_fee_basis_tbl(9).fee_basis_name   := 'CURR_LOAN';
6808         l_fee_basis_tbl(9).fee_basis_amount := p_loan_details.requested_amount + p_loan_details.ADD_REQUESTED_AMOUNT;
6809 
6810         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calling LNS_FEE_ENGINE.getFeeDetails for this installment...');
6811         LNS_FEE_ENGINE.getFeeDetails(p_init_msg_list  => FND_API.G_FALSE
6812                                     ,p_loan_id        => l_loan_id
6813                                     ,p_installment    => l_installment_number
6814                                     ,p_fee_basis_tbl  => l_fee_basis_tbl
6815                                     ,p_based_on_terms => p_based_on_terms
6816                                     ,p_phase          => 'OPEN'
6817                                     ,x_fees_tbl       => l_fees_tbl
6818                                     ,x_return_status  => l_return_status
6819                                     ,x_msg_count      => l_msg_count
6820                                     ,x_msg_data       => l_msg_data);
6821 
6822         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_return_status = ' || l_return_status);
6823         if l_return_status <> 'S' then
6824             RAISE FND_API.G_EXC_ERROR;
6825         end if;
6826 
6827         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_fees_tbl.count = ' || l_fees_tbl.count);
6828 
6829         for k in 1..l_fees_tbl.count loop
6830             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Fee ' || k);
6831             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_ID = ' || l_fees_tbl(k).FEE_ID);
6832             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_NAME = ' || l_fees_tbl(k).FEE_NAME);
6833             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_CATEGORY = ' || l_fees_tbl(k).FEE_CATEGORY);
6834             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FEE_AMOUNT = ' || l_fees_tbl(k).FEE_AMOUNT);
6835             l_fee_amount := l_fee_amount + l_fees_tbl(k).FEE_AMOUNT;
6836         end loop;
6837         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total fee amount for this installment = ' || l_fee_amount);
6838 
6839        l_total                                 := l_fee_amount + l_periodic_principal + l_periodic_interest;
6840        l_amortization_rec.total                := l_total;
6841        l_amortization_rec.fee_amount           := l_fee_amount;
6842        l_prev_end_balance                      := l_end_balance;
6843 
6844        -- running totals calculated here
6845        --l_principal_cumulative := l_principal_cumulative + l_periodic_principal;
6846        l_interest_cumulative  := l_interest_cumulative + l_periodic_interest;
6847        l_fees_cumulative      := l_fees_cumulative + l_fee_amount;
6848 
6849        l_amortization_rec.interest_cumulative  := l_interest_cumulative;
6850        l_amortization_rec.principal_cumulative := l_principal_cumulative;
6851        l_amortization_rec.fees_cumulative      := l_fees_cumulative;
6852        l_amortization_rec.SOURCE               := 'PREDICTED';
6853 
6854        -- add the record to the amortization table
6855        l_amortization_tbl(i)                   := l_amortization_rec;
6856 
6857        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: due date ' || l_amortization_rec.due_date);
6858        --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_principal ' || l_amortization_rec.principal_amount);
6859        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: periodic_interest  ' || l_amortization_rec.interest_amount);
6860        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fee_amount is ' || l_amortization_rec.fee_amount);
6861        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: total is ' || l_amortization_rec.fee_amount);
6862        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: begin_balance is ' || l_amortization_rec.begin_balance);
6863        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: end_balance is ' || l_amortization_rec.end_balance);
6864        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: interest_cumulative is ' || l_amortization_rec.interest_cumulative);
6865        --logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: principal_cumulative is ' || l_amortization_rec.principal_cumulative);
6866        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization rec: fees_cumulative is ' || l_amortization_rec.fees_cumulative);
6867        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amortization_rec.NORMAL_INT_AMOUNT );
6868 
6869     end loop;
6870     --printAmortizationTable(p_amort_tbl => l_amortization_tbl);
6871 
6872     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - AMORTIZATION TABLE COUNT = ' || l_amortization_tbl.count);
6873     x_loan_amort_tbl := l_amortization_tbl;
6874 
6875     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
6876 
6877  Exception
6878     WHEN FND_API.G_EXC_ERROR THEN
6879          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6880 
6881     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6882          logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
6883 
6884     WHEN OTHERS THEN
6885          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
6886 
6887 end loanProjection;
6888 
6889 /*=========================================================================
6890 || PUBLIC PROCEDURE runLoanProjection
6891 ||
6892 || DESCRIPTION
6893 ||
6894 || Overview: procedure will run a loan projection ||
6895 || Parameter:  loan_id
6896 ||
6897 || Source Tables:  LNS_LOAN_HEADERS, LNS_TERMS, LNS_RATE_SCHEDULES,
6898 ||                 LNS_DISB_HEADERS, LNS_DISB_LINES
6899 ||
6900 || Target Tables: None
6901 ||
6902 || Return value: x_amort_tbl is table of amortization records
6903 ||
6904 || KNOWN ISSUES
6905 ||
6906 || NOTES
6907 ||
6908 || MODIFICATION HISTORY
6909 || Date                  Author            Description of Changes
6910 || 07/18/2005 11:35AM    raverma           Created
6911 || 08/29/2005            raverma           throw error if invalid dates
6912  *=======================================================================*/
6913 procedure runOpenProjection(p_init_msg_list  IN VARCHAR2
6914                            ,p_loan_ID        IN NUMBER
6915                            ,p_based_on_terms IN VARCHAR2
6916                            ,x_amort_tbl      OUT NOCOPY LNS_FINANCIALS.AMORTIZATION_TBL
6917                            ,x_return_status  OUT NOCOPY VARCHAR2
6918                            ,x_msg_count      OUT NOCOPY NUMBER
6919                            ,x_msg_data       OUT NOCOPY VARCHAR2)
6920 is
6921 
6922     l_api_name                varchar2(25);
6923     l_api_version_number      number;
6924     l_return_status           VARCHAR2(1);
6925     l_msg_count               NUMBER;
6926     l_msg_data                VARCHAR2(32767);
6927 
6928     l_amort_tbl               LNS_FINANCIALS.AMORTIZATION_TBL;
6929     l_amort_tbl2              LNS_FINANCIALS.AMORTIZATION_TBL;
6930     l_total_amortization      LNS_FINANCIALS.AMORTIZATION_REC;
6931     b_showActual              boolean := false;
6932     l_last_installment_billed number;
6933 
6934     l_num_records             number;
6935     i                         number;
6936     m                         number;
6937     l_records_to_copy         number;
6938     l_num_installments        number;
6939     l_num_rows                number;
6940     l_manual_fee_amount       number;
6941     l_records_to_destroy      number;
6942     l_start_date              number;
6943     l_funded_amount           number;
6944     l_loan_details            LNS_FINANCIALS.LOAN_DETAILS_REC;
6945     l_rate_tbl			      LNS_FINANCIALS.RATE_SCHEDULE_TBL;
6946     l_disb_amount	          number;
6947     l_invalid_disb			  number;
6948 
6949     cursor c_disbursements(p_loan_id number) is
6950 		 select nvl(sum(header_amount), 0)
6951 			 from lns_disb_headers
6952 			where loan_id = p_loan_id;
6953 
6954 BEGIN
6955         -- Standard Start of API savepoint
6956         SAVEPOINT runLoanProjection_PVT;
6957         l_api_name                := 'runLoanProjection';
6958         i                         := 0;
6959         l_manual_fee_amount       := 0;
6960 
6961         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
6962 
6963         -- Initialize message list IF p_init_msg_list is set to TRUE.
6964         IF FND_API.to_Boolean( p_init_msg_list ) THEN
6965             FND_MSG_PUB.initialize;
6966         END IF;
6967 
6968         -- Initialize API return status to SUCCESS
6969         x_return_status := FND_API.G_RET_STS_SUCCESS;
6970 
6971         --
6972         -- Api body
6973         -- ----------------------------------------------------------------
6974         -- validate loan_id
6975         lns_utility_pub.validate_any_id(p_api_version    =>  1.0
6976                                        ,p_init_msg_list  =>  p_init_msg_list
6977                                        ,x_msg_count      =>  l_msg_count
6978                                        ,x_msg_data       =>  l_msg_data
6979                                        ,x_return_status  =>  l_return_status
6980                                        ,p_col_id         =>  p_loan_id
6981                                        ,p_col_name       =>  'LOAN_ID'
6982                                        ,p_table_name     =>  'LNS_LOAN_HEADERS_ALL');
6983 
6984         if l_return_status <> FND_API.G_RET_STS_SUCCESS then
6985             FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
6986             FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
6987             FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
6988             FND_MSG_PUB.ADD;
6989             RAISE FND_API.G_EXC_ERROR;
6990         end if;
6991 
6992         -- check if disbursements exist and is amount > 0 as per karthik instructions
6993         open  c_disbursements(p_loan_id);
6994         fetch c_disbursements into l_disb_amount;
6995         close c_disbursements;
6996 
6997         if l_invalid_disb > 0 then
6998             FND_MESSAGE.SET_NAME('LNS', 'LNS_DISB_REQ_DATE_ERR');
6999             FND_MSG_PUB.ADD;
7000             RAISE FND_API.G_EXC_ERROR;
7001         end if;
7002 
7003         if l_disb_amount > 0 then
7004             l_rate_tbl      := lns_financials.getRateSchedule(p_loan_id, 'OPEN');
7005 	        l_loan_details  := lns_financials.getLoanDetails(p_loan_Id            => p_loan_id
7006 	                                                        ,p_based_on_terms     => p_based_on_terms
7007 															,p_phase              => 'OPEN');
7008 
7009 	        -- call projection API
7010 	        lns_financials.loanProjection(p_loan_details     => l_loan_details
7011                                           ,p_based_on_terms  => p_based_on_terms
7012 					  			          ,p_rate_schedule    => l_rate_tbl
7013 					 			          ,x_loan_amort_tbl   => l_amort_tbl);
7014 
7015 	        -- delete predicted records based on ORIGINAL amortization
7016             if p_based_on_terms = 'CURRENT' and
7017                 l_loan_details.LOAN_STATUS NOT IN ('INCOMPLETE','DELETED','REJECTED','PENDING','APPROVED')
7018             then
7019 	            l_num_records := l_amort_tbl.count;
7020 	            logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - amortization returns # records '|| l_num_records);
7021 	            l_last_installment_billed := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER_EXT_3(p_loan_id, 'OPEN');
7022 	            logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - last installment billed '|| l_last_installment_billed);
7023 
7024 	            -- copy the records not billed to a temp collection
7025 	            m := 0;
7026 	            for i in 1..l_num_records
7027 	            loop
7028 	                logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - copying record ' || i);
7029 	                if l_amort_tbl(i).installment_number > l_last_installment_billed then
7030 	                    m := m + 1;
7031 	                    l_amort_tbl2(m) := l_amort_tbl(i);
7032 	                end if;
7033 	            end loop;
7034 
7035 	            -- copy back to original table
7036 	            l_amort_tbl.delete;
7037 	            m := 0;
7038 	            for i in 1..l_amort_tbl2.count
7039 	            loop
7040 	                logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - re-copying record ' || i);
7041 	                    m := m + 1;
7042 	                    l_amort_tbl(m) := l_amort_tbl2(i);
7043 	            end loop;
7044 	        end if;
7045 		end if; -- disb amount > 0
7046         x_amort_tbl := l_amort_tbl;
7047         --
7048         -- End of API body
7049         --
7050 
7051         FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
7052 
7053         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7054 
7055     EXCEPTION
7056         WHEN FND_API.G_EXC_ERROR THEN
7057               ROLLBACK TO runLoanProjection_PVT;
7058               x_return_status := FND_API.G_RET_STS_ERROR;
7059               x_msg_count := l_msg_count;
7060               x_msg_data  := l_msg_data;
7061               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7062               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7063 
7064          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
7065               ROLLBACK TO runLoanProjection_PVT;
7066               x_return_status := FND_API.G_RET_STS_ERROR;
7067               x_msg_count := l_msg_count;
7068               x_msg_data  := l_msg_data;
7069               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7070               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7071 
7072         WHEN OTHERS THEN
7073               ROLLBACK TO runLoanProjection_PVT;
7074               x_return_status := FND_API.G_RET_STS_ERROR;
7075               x_msg_count := l_msg_count;
7076               x_msg_data  := l_msg_data;
7077               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
7078               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7079 
7080 END runOpenProjection;
7081 
7082 ---------------------------------------------------------------------------
7083 --- rate routines
7084 ---------------------------------------------------------------------------
7085 /*=========================================================================
7086 || PUBLIC PROCEDURE getRateSchedule - R12
7087 ||
7088 || DESCRIPTION
7089 ||
7090 || Overview:  this api is used to get the rate schedule for a loan
7091 ||
7092 || Parameter:  loan_id,
7093 ||             p_phase  'OPEN' or 'TERM'
7094 ||
7095 || Source Tables:  LNS_RATE_SCHEDULES, LNS_TERMS, LNS_LOAN_HEADER_ALL
7096 ||
7097 || Target Tables:  NA
7098 ||
7099 || Return value: rate_schedule_tbl which is defined as
7100 ||  TYPE INTEREST_RATE_REC IS RECORD(
7101 ||    BEGIN_DATE   DATE,
7102 ||    END_DATE     DATE,
7103 ||    ANNUAL_RATE  NUMBER);
7104 ||  TYPE RATE_SCHEDULE_TBL IS TABLE OF INTEREST_RATE_REC INDEX BY BINARY_INTEGER;
7105 ||
7106 || KNOWN ISSUES
7107 ||
7108 || NOTES
7109 ||      NOTE: INSTALLMENT_NUMBER WILL NOT GET YOU THE GIVEN INSTALLMENT
7110 ||            NUMBER CORRESPONDING ON THE LOAN AMORTIZATION SCHEDULE
7111 ||
7112 || MODIFICATION HISTORY
7113 || Date                  Author            Description of Changes
7114 || 07/18/2005 6:42PM     raverma           Created
7115  *=======================================================================*/
7116 function getRateSchedule(p_loan_id in number
7117                         ,p_phase   in varchar2) return LNS_FINANCIALS.RATE_SCHEDULE_TBL
7118 is
7119 
7120     l_rate_tbl           LNS_FINANCIALS.RATE_SCHEDULE_TBL;
7121     l_rate_id            number;
7122     l_annual_rate        number;
7123     l_spread             number;
7124     l_start_date         date;
7125     l_begin_installment  number;
7126     l_end_installment    number;
7127     l_interest_only_flag varchar2(1);
7128     l_floating_flag      varchar2(1);
7129     l_end_date           date;
7130     i                    number;
7131     l_api_name           varchar2(20);
7132 
7133     cursor c_rate_schedule (p_loan_id number, p_phase varchar2)
7134     is
7135     select rate_id
7136           ,current_interest_rate
7137           ,nvl(spread, 0)
7138           ,trunc(start_date_active)
7139           ,trunc(end_date_active)
7140           ,begin_installment_number
7141           ,end_installment_number
7142           ,nvl(interest_only_flag, 'N')
7143           ,nvl(floating_flag, 'N')
7144       from lns_loan_headers_all h,
7145            lns_terms t,
7146            lns_rate_schedules rs
7147      where h.loan_id = p_loan_id
7148        and h.loan_id = t.loan_id
7149        and t.term_id = rs.term_id
7150        and rs.end_date_active is null
7151        and nvl(phase, 'TERM') = p_phase
7152   order by begin_installment_number
7153           ,start_date_active;
7154 
7155 begin
7156 
7157         i          := 0;
7158         l_api_name := 'getRateSchedule';
7159         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7160 
7161         Begin
7162             OPEN c_rate_schedule(p_loan_id, p_phase);
7163             LOOP
7164                 i := i + 1;
7165             FETCH c_rate_schedule INTO
7166                 l_rate_id
7167                ,l_annual_rate
7168                ,l_spread
7169                ,l_start_date
7170                ,l_end_date
7171                ,l_begin_installment
7172                ,l_end_installment
7173                ,l_interest_only_flag
7174                ,l_floating_flag;
7175             EXIT WHEN c_rate_schedule%NOTFOUND;
7176                 l_rate_tbl(i).rate_id                  := l_rate_id;
7177                 l_rate_tbl(i).annual_rate              := l_annual_rate;
7178                 l_rate_tbl(i).spread                   := l_spread;
7179                 l_rate_tbl(i).begin_date               := l_start_date;
7180                 l_rate_tbl(i).end_date                 := l_end_date;
7181                 l_rate_tbl(i).begin_installment_number := l_begin_installment;
7182                 l_rate_tbl(i).end_installment_number   := l_end_installment;
7183                 l_rate_tbl(i).interest_only_flag       := l_interest_only_flag;
7184                 l_rate_tbl(i).FLOATING_FLAG            := l_floating_flag;
7185             END LOOP;
7186         Exception
7187             When No_Data_Found then
7188              FND_MESSAGE.Set_Name('LNS', 'LNS_NO_RATES');
7189              FND_MSG_PUB.Add;
7190              RAISE FND_API.G_EXC_ERROR;
7191         End;
7192 
7193         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7194 
7195         return l_rate_tbl;
7196 
7197  Exception
7198     WHEN FND_API.G_EXC_ERROR THEN
7199          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7200 
7201     WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
7202          logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, sqlerrm);
7203 
7204     WHEN OTHERS THEN
7205          logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
7206 
7207 end getRateSchedule;
7208 
7209 /*=========================================================================
7210 || PUBLIC PROCEDURE getWeightedRate
7211 ||
7212 || DESCRIPTION
7213 ||
7214 || Overview:  Calculates the weighted average interest rate for a period
7215 ||            of time for a table of rates
7216 ||
7217 || Parameter: p_start_date => date to begin periodic rate  (last interest accrual date for loan payoff)
7218 ||            p_end_date   => date to end periodic rate
7219 ||            p_rate_tbl   => table of rate schedules
7220 ||
7221 || Source Tables:  NA
7222 ||
7223 || Target Tables:  NA
7224 ||
7225 || Return value:  Annualized Rate weighted by rates
7226 ||
7227 || KNOWN ISSUES
7228 ||             rounding? only works to the daily level
7229 ||             days count method is unclear? (see function intervalsInPeriod)
7230 ||             any dates left out will be assumed to be interest rate of 0
7231 ||
7232 || there are 9 scenarios possible:
7233 ||
7234 || P_Start_Date                           p_End_date
7235 ||        +------------------------------------+  (time line to get periodic rate)
7236 ||
7237 || Scen 1: (rate tbl matches exactly)
7238 ||        +------------------------------------+  (time line to get periodic rate)
7239 ||        +------------------------------------+  (rate table time line)
7240 ||
7241 || Scen 2: (rate tbl further than end date)
7242 ||        +------------------------------------+  (time line to get periodic rate)
7243 ||        +------------------------------------------+ (rate table time line)
7244 ||
7245 || Scen 3: (rate tbl shorter than end date)
7246 ||        +------------------------------------+  (time line to get periodic rate)
7247 ||        +-------------------------------+       (rate table time line)
7248 ||
7249 || Scen 4: (rate tbl before start date)
7250 ||        +------------------------------------+  (time line to get periodic rate)
7251 ||    +----------------------------------------+  (rate table time line)
7252 ||
7253 || Scen 5: (rate tbl before start date)
7254 ||        +------------------------------------+  (time line to get periodic rate)
7255 ||    +----------------------------------------+  (rate table time line)
7256 ||
7257 || Scen 6: (rate tbl after start date)
7258 ||        +------------------------------------+  (time line to get periodic rate)
7259 ||             +-------------------------------+  (rate table time line)
7260 ||
7261 || Scen 7: (rate tbl is shorter than period)
7262 ||        +------------------------------------+  (time line to get periodic rate)
7263 ||            +-------------------------+         (rate table time line)
7264 ||
7265 || Scen 8: (rate tbl is longer than period)
7266 ||        +------------------------------------+  (time line to get periodic rate)
7267 ||    +-------------------------------------------------------+ (rate table time line)
7268 ||
7269 || Scen 9: (rate tbl is not contiguous)
7270 ||        +------------------------------------+  (time line to get periodic rate)
7271 ||           +--+  +---+     +------+   +-----+   (rate table time line)
7272 ||
7273 ||
7274 ||   only scenarios 3, 6, 7, 9 do we have periods to assume that rate is = 0
7275 ||   in all other scenarios the rate table covers the period of time allotted
7276 ||
7277 ||   also, it is assumed that the rate table is a contiguous period of time
7278 ||
7279 || NOTES
7280 ||
7281 ||      there are implicit assumptions that CANNOT be made when calculating
7282 ||       wtd avg interest for a given period.
7283 ||      for example, you cannot simply put in a
7284 ||         [ (# days @ rate 1 X rate 1) +
7285 ||           (# days @ rate 2 X rate 2) +
7286 ||           (# days @ rate 3 X rate 3) +  ]
7287 ||         / total # days in rate schedule
7288 ||        because we may have p_start_date > rate 1 start date and
7289 ||                            p_end_date < rate 3 end date
7290 ||
7291 ||
7292 || MODIFICATION HISTORY
7293 || Date                  Author            Description of Changes
7294 || 2/09/2003 1:51PM     raverma           Created
7295 ||
7296  *=======================================================================*/
7297 function getWeightedRate(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC
7298                         ,p_start_date in date
7299                         ,p_end_date   in date
7300                         ,p_rate_tbl   in LNS_FINANCIALS.RATE_SCHEDULE_TBL) return number
7301 is
7302     l_api_name          varchar2(25);
7303     l_rate_details      LNS_FINANCIALS.INTEREST_RATE_REC;
7304     l_pay_dates         LNS_FINANCIALS.DATE_TBL;
7305     l_days_at_rate      number;
7306     l_weighted_rate     number;
7307     l_running_weight    number;
7308     l_total_days        number;
7309     l_num_pay_dates     number;
7310     l_period_start_date date;
7311     l_period_end_date   date;
7312     --l_pay_in_arrears    boolean;
7313     l_payment_tbl       LNS_FIN_UTILS.PAYMENT_SCHEDULE_TBL;
7314     l_exit_loop         boolean;
7315     l_freq_schedule_tbl         LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
7316     l_int_freq_schedule_tbl     LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
7317     l_prin_freq_schedule_tbl    LNS_FIN_UTILS.FREQUENCY_SCHEDULE_TBL;
7318 
7319 begin
7320 
7321     l_api_name       := 'getWeightedRate';
7322     l_days_at_rate   := 0;
7323     l_weighted_rate  := 0;
7324     l_running_weight := 0;
7325     l_total_days     := 0;
7326     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7327     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' start date ' || p_start_date);
7328     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' end date ' || p_end_date);
7329     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate table count ' || p_rate_tbl.count);
7330 
7331     if p_loan_details.custom_schedule = 'N' then
7332 
7333         if p_loan_details.PAYMENT_CALC_METHOD = 'SEPARATE_SCHEDULES' then
7334 
7335             l_int_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
7336                                                 P_LOAN_ID           => p_loan_details.LOAN_ID,
7337                                                 P_PHASE             => 'TERM',
7338                                                 P_COMPONENT         => 'INT');
7339 
7340             l_prin_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
7341                                                 P_LOAN_ID           => p_loan_details.LOAN_ID,
7342                                                 P_PHASE             => 'TERM',
7343                                                 P_COMPONENT         => 'PRIN');
7344 
7345             l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
7346                                     p_loan_start_date      => p_loan_details.loan_start_date,
7347                                     p_loan_maturity_date  => p_loan_details.maturity_date,
7348                                     p_prin_freq_schedule_tbl => l_prin_freq_schedule_tbl,
7349                                     p_int_freq_schedule_tbl => l_int_freq_schedule_tbl);
7350 /*
7351             l_payment_tbl := LNS_FIN_UTILS.buildSIPPaymentSchedule(
7352                                     p_loan_start_date      => p_loan_details.loan_start_date
7353                                     ,p_loan_maturity_date  => p_loan_details.maturity_date
7354                                     ,p_int_first_pay_date  => p_loan_details.first_payment_date
7355                                     ,p_int_num_intervals   => p_loan_details.number_installments
7356                                     ,p_int_interval_type   => p_loan_details.payment_frequency
7357                                     ,p_int_pay_in_arrears  => p_loan_details.pay_in_arrears_boolean
7358                                     ,p_prin_first_pay_date => p_loan_details.PRIN_FIRST_PAY_DATE
7359                                     ,p_prin_num_intervals  => p_loan_details.PRIN_NUMBER_INSTALLMENTS
7360                                     ,p_prin_interval_type  => p_loan_details.PRIN_PAYMENT_FREQUENCY
7361                                     ,p_prin_pay_in_arrears => p_loan_details.PRIN_PAY_IN_ARREARS_BOOL);
7362 */
7363         else
7364 
7365             l_freq_schedule_tbl := LNS_FIN_UTILS.fetchFreqSchedule(
7366                                                 P_LOAN_ID           => p_loan_details.LOAN_ID,
7367                                                 P_PHASE             => 'TERM',
7368                                                 P_COMPONENT         => 'PRIN_INT');
7369 
7370             l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(
7371                                     p_loan_start_date      => p_loan_details.loan_start_date,
7372                                     p_loan_maturity_date  => p_loan_details.maturity_date,
7373                                     p_freq_schedule_tbl => l_freq_schedule_tbl);
7374 /*
7375             l_payment_tbl := LNS_FIN_UTILS.buildPaymentSchedule(p_loan_start_date    => p_loan_details.loan_start_date
7376                                                                 ,p_loan_maturity_date => p_loan_details.maturity_date
7377                                                                 ,p_first_pay_date     => p_loan_details.first_payment_date
7378                                                                 ,p_num_intervals      => p_loan_details.number_installments
7379                                                                 ,p_interval_type      => p_loan_details.payment_frequency
7380                                                                 ,p_pay_in_arrears     => p_loan_details.pay_in_arrears_boolean);
7381 */
7382         end if;
7383 
7384     else
7385 
7386         -- build custom payment schedule
7387         l_payment_tbl := LNS_CUSTOM_PUB.buildCustomPaySchedule(p_loan_details.LOAN_ID);
7388 
7389     end if;
7390 
7391     l_num_pay_dates := l_payment_tbl.count;
7392     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' num pay dates is ' || l_num_pay_dates);
7393 --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' num installments is ' || p_loan_details.number_installments);
7394 
7395 --    for k in 1..p_loan_details.number_installments
7396     for k in 1..l_num_pay_dates
7397     loop
7398 
7399         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Period: ' || k);
7400         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' period start is ' || l_payment_tbl(k).period_begin_date);
7401         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' period end is ' || l_payment_tbl(k).period_end_date);
7402        -- check to see if this period is covered in the time
7403 
7404        l_exit_loop := false;
7405        l_period_start_date := null;
7406        if p_start_date >= l_payment_tbl(k).period_begin_date and
7407           p_start_date < l_payment_tbl(k).period_end_date then
7408             l_period_start_date := p_start_date;
7409        elsif p_start_date < l_payment_tbl(k).period_begin_date and
7410           p_start_date < l_payment_tbl(k).period_end_date then
7411             l_period_start_date := l_payment_tbl(k).period_begin_date;
7412        end if;
7413 
7414        l_period_end_date := null;
7415        if p_end_date >= l_payment_tbl(k).period_begin_date and
7416           p_end_date <= l_payment_tbl(k).period_end_date then
7417             l_period_end_date := p_end_date;
7418             l_exit_loop := true;
7419        elsif p_end_date >= l_payment_tbl(k).period_begin_date and
7420           p_end_date > l_payment_tbl(k).period_end_date then
7421             if k = l_num_pay_dates then
7422                 l_period_end_date := p_end_date;
7423                 l_exit_loop := true;
7424             else
7425                 l_period_end_date := l_payment_tbl(k).period_end_date;
7426             end if;
7427        end if;
7428 
7429        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_period_start_date: ' || l_period_start_date);
7430        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_period_end_date: ' || l_period_end_date);
7431 
7432        if l_period_start_date is not null and l_period_end_date is not null then
7433 
7434           l_days_at_rate := LNS_FIN_UTILS.getDayCount(p_start_date       => l_period_start_date
7435                                                      ,p_end_date         => l_period_end_date
7436                                                      ,p_day_count_method => p_loan_details.day_count_method);
7437           l_rate_details := getRateDetails(p_installment => k
7438                                           ,p_rate_tbl    => p_rate_tbl);
7439 
7440           l_total_days     := l_total_days + l_days_at_rate;
7441           l_running_weight := l_running_weight + (l_rate_details.annual_rate  * l_days_at_rate);
7442 
7443        end if;
7444 
7445        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_days_at_rate: ' || l_days_at_rate);
7446        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_rate: ' || l_rate_details.annual_rate);
7447        logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_running_weight: ' || l_running_weight);
7448 
7449        if l_exit_loop then
7450            logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' Exiting loop');
7451            exit;
7452        end if;
7453 
7454     end loop;
7455 
7456     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' total days is ' || l_total_days);
7457 
7458     if l_total_days = 0 then
7459         l_total_days := 1;
7460     end if;
7461 
7462     l_weighted_rate := l_running_weight / l_total_days;
7463     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' l_weighted_rate ' || l_weighted_rate);
7464 
7465     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7466 
7467     return l_weighted_rate;
7468 
7469 end getWeightedRate;
7470 
7471 
7472 /*=========================================================================
7473 || PUBLIC PROCEDURE getRateDetails
7474 ||
7475 || DESCRIPTION
7476 ||
7477 || Overview:  return a interest_rate_record for a given installment
7478 ||
7479 ||
7480 || Parameter:  p_installment => installment to get rate details
7481 ||             p_rate_tbl    => table of interest rates
7482 ||
7483 ||
7484 || Return value: NA
7485 ||
7486 || Source Tables: NA
7487 ||
7488 || Target Tables:  NA
7489 ||
7490 || KNOWN ISSUES
7491 ||      if no rates can be found in set of give dates a rate of 0 is returned
7492 ||
7493 || NOTES
7494 ||
7495 || MODIFICATION HISTORY
7496 || Date                  Author            Description of Changes
7497 || 2/24/2003 4:28PM     raverma           Created
7498  *=======================================================================*/
7499 function getRateDetails(p_installment IN NUMBER
7500                        ,p_rate_tbl    IN LNS_FINANCIALS.RATE_SCHEDULE_TBL) return LNS_FINANCIALS.INTEREST_RATE_REC
7501 is
7502   x          number;
7503   l_rate     number;
7504   l_rate_rec LNS_FINANCIALS.INTEREST_RATE_REC;
7505   l_api_name varchar2(25);
7506 
7507 begin
7508 
7509     l_rate     := 0;
7510     l_api_name := 'getRateDetails2';
7511     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7512     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - installment ' || p_installment);
7513 
7514     x := 1;
7515     Begin
7516        LOOP
7517             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - match row ' || x);
7518             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate ' || p_rate_tbl(x).annual_rate);
7519             l_rate := p_rate_tbl(x).annual_rate;
7520             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - rate 1');
7521             l_rate_rec := p_rate_tbl(x);
7522           EXIT WHEN p_installment >= p_rate_tbl(x).begin_installment_number and
7523                     p_installment <= p_rate_tbl(x).end_installment_number;
7524           x := x + 1;
7525        END LOOP;
7526     Exception
7527        When No_Data_found then
7528            -- when there is not a rate for this period it is assumed to be zero (see scenarios 3, 6, 8 in comments on getWeightedRate)
7529            --l_rate := 0;
7530            logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - no rate found for period');
7531        when others then
7532            l_rate := 0;
7533 
7534     End;
7535 
7536     if l_rate = 0 then
7537        l_rate_rec.annual_rate := 0;
7538     end if;
7539 
7540     --logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7541     return l_rate_rec;
7542 
7543 end getRateDetails;
7544 
7545 
7546 /*=========================================================================
7547  | PUBLIC PROCEDURE getRateDetails
7548 ||
7549 || DESCRIPTION
7550 ||
7551 || Overview:  return a interest_rate_record for a given date
7552 ||
7553 ||
7554 || Parameter:  p_date => to get rate details
7555 ||             p_rate_tbl => table of interest rates
7556 ||
7557 ||
7558 || Return value: NA
7559 ||
7560 || Source Tables: NA
7561 ||
7562 || Target Tables:  NA
7563 ||
7564 || KNOWN ISSUES
7565 ||      if no rates can be found in set of give dates a rate of 0 is returned
7566 ||
7567 || NOTES
7568 ||
7569 || MODIFICATION HISTORY
7570 || Date                  Author            Description of Changes
7571 || 2/24/2003 4:28PM     raverma           Created
7572 ||
7573  *=======================================================================*/
7574 function getRateDetails(p_date in date
7575                        ,p_rate_tbl in LNS_FINANCIALS.RATE_SCHEDULE_TBL) return LNS_FINANCIALS.INTEREST_RATE_REC
7576 is
7577   x          number;
7578   l_rate     number;
7579   l_rate_rec LNS_FINANCIALS.INTEREST_RATE_REC;
7580   l_api_name varchar2(25);
7581 
7582 begin
7583 
7584     l_rate     := 0;
7585     l_api_name := 'getRateDetails';
7586 --        logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7587 
7588     x := 1;
7589     Begin
7590        LOOP
7591              l_rate := p_rate_tbl(x).annual_rate;
7592              l_rate_rec := p_rate_tbl(x);
7593           EXIT WHEN p_date >= p_rate_tbl(x).begin_date and p_date <= p_rate_tbl(x).end_date;
7594 
7595           x := x + 1;
7596        END LOOP;
7597     Exception
7598        When No_Data_found then
7599            -- when there is not a rate for this period it is assumed to be zero (see scenarios 3, 6, 8 in comments on getWeightedRate)
7600            l_rate := 0;
7601            logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' - no rate found for period');
7602        when others then
7603            l_rate := 0;
7604 
7605     End;
7606 
7607     if l_rate = 0 then
7608        l_rate_rec.annual_rate := 0;
7609     end if;
7610 
7611 --        logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
7612 
7613     return l_rate_rec;
7614 
7615 end getRateDetails;
7616 
7617 /*=========================================================================
7618 || PUBLIC PROCEDURE getLoanDetails
7619 ||
7620 || DESCRIPTION
7621 ||
7622 || Overview:  return a rec_type of loan details
7623 ||
7624 || Parameter:  loan_id
7625 ||
7626 || Return value: table of dates
7627 ||
7628 || Source Tables: LNS_LOAN_HEADER, LNS_TERMS, LNS_AMORTIZATION_SCHEDS
7629 ||
7630 || Target Tables: NA
7631 ||
7632 || KNOWN ISSUES
7633 ||
7634 || NOTES
7635 ||
7636 || MODIFICATION HISTORY
7637 || Date                  Author            Description of Changes
7638 || 1/15/2004 4:28PM     raverma           Created
7639 || 2/26/2004            raverma           add loan_maturity_Date
7640 || 3/12/2004            raverma           added reamortization information
7641 || 4/15/2004            raverma           added loan_status
7642 || 8/02/2004            raverma           added logic to calculate num_amortization_intervals based on
7643 ||                                        theoretical amortization_maturity_date
7644 || 01/19/2007           scherkas          Fixed bug 5842639
7645  *=======================================================================*/
7646 function getLoanDetails(p_loan_id        in number
7647                        ,p_based_on_terms in varchar2
7648 					   ,p_phase          in varchar2) return LNS_FINANCIALS.LOAN_DETAILS_REC
7649 
7650 is
7651 
7652 
7653     -- get the loan details assumes there is only ONE ROW in terms (TERM PHASE)
7654     CURSOR c_loan_details(p_Loan_id NUMBER, p_based_on_terms varchar2, p_phase varchar2) IS
7655     SELECT h.loan_id
7656         ,decode(p_phase, 'TERM', h.loan_term, 'OPEN', h.open_loan_term, h.loan_term) TERM
7657         ,decode(p_phase, 'TERM', h.loan_term_period, 'OPEN', h.open_loan_term_period, h.loan_term_period) TERM_PERIOD
7658         ,decode(p_phase, 'TERM', decode(h.balloon_payment_type, 'TERM', h.amortized_term, 'AMOUNT', h.loan_term, h.amortized_term), 'OPEN', h.open_loan_term) AMORT_TERM
7659         ,decode(p_phase, 'TERM', decode(h.balloon_payment_type, 'TERM', h.amortized_term_period, 'AMOUNT', h.loan_term_period, h.amortized_term_period), 'OPEN', h.open_loan_term_period) AMORT_TERM_PERIOD
7660 		,decode(h.balloon_payment_type, 'TERM', 0, 'AMOUNT', h.balloon_payment_amount, 0) BALLOON_PAYMENT_AMT
7661         ,decode(p_phase, 'TERM', t.amortization_frequency, 'OPEN', t.loan_payment_frequency) AMORT_FREQ
7662         ,decode(p_phase, 'TERM', t.loan_payment_frequency, 'OPEN', t.open_payment_frequency, t.loan_payment_frequency) PAY_FREQ
7663         ,decode(p_phase, 'TERM', trunc(h.loan_start_date), 'OPEN' , trunc(h.open_loan_start_date), trunc(h.loan_start_date)) START_DATE
7664         ,decode(p_phase, 'TERM', trunc(t.first_payment_date), 'OPEN' , trunc(t.open_first_payment_date), trunc(t.first_payment_date)) FIRST_PAY_DATE
7665 		,h.requested_amount REQUEST_AMOUNT
7666 		,h.funded_amount FUNDED_AMOUNT
7667         ,lns_financials.getRemainingBalance(p_loan_id) BALANCE
7668         --,decode(p_based_on_terms, 'CURRENT', lns_financials.getRemainingBalance(p_loan_id), 'ORIGINAL', h.requested_amount) BALANCE -- see bug #3881401
7669         ,decode(p_phase, 'TERM', trunc(h.loan_maturity_date), 'OPEN', trunc(h.open_maturity_date), trunc(h.loan_maturity_date)) MATURITY_DATE
7670         ,NVL(t.reamortize_over_payment, 'N')
7671         ,NVL(t.reamortize_under_payment, 'N')
7672         ,NVL(t.reamortize_with_interest, 'N')
7673         ,LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id, p_phase) LAST_PAY_NUM
7674         --,decode(p_based_on_terms, 'CURRENT', LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id),'ORIGINAL', 1) LAST_PAY_NUM
7675         ,decode(nvl(t.day_count_method, 'PERIODIC30_360'), 'PERIODIC30_360', '30/360', t.day_count_method) DAY_COUNT
7676         ,decode(p_phase, 'TERM', decode(trunc(t.first_payment_date) - trunc(h.loan_start_date), 0, 'N', 'Y')
7677 				       , 'OPEN', decode(trunc(t.open_first_payment_date) - trunc(h.open_loan_start_date), 0, 'N', 'Y')
7678                        , decode(trunc(t.first_payment_date) - trunc(h.loan_start_date), 0, 'N', 'Y')) ARREARS
7679 		,nvl(h.custom_payments_flag, 'N')   CUSTOM
7680         ,h.loan_status                      LOAN_STATUS
7681         ,h.loan_currency                    CURRENCY
7682         ,curr.precision                     PRECISION
7683         ,h.OPEN_TO_TERM_FLAG                OPEN_TO_TERM_FLAG
7684         ,h.OPEN_TO_TERM_EVENT               OPEN_TO_TERM_EVENT
7685         ,h.MULTIPLE_FUNDING_FLAG            MULTIPLE_FUNDING_FLAG
7686         ,h.SECONDARY_STATUS                 SECONDARY_STATUS
7687         ,t.RATE_TYPE                        RATE_TYPE
7688         ,t.CEILING_RATE                     TERM_CEILING_RATE
7689         ,t.FLOOR_RATE                       TERM_FLOOR_RATE
7690         ,t.PERCENT_INCREASE                 TERM_PERCENT_INCREASE
7691         ,t.PERCENT_INCREASE_LIFE            TERM_PERCENT_INCREASE_LIFE
7692         ,t.FIRST_PERCENT_INCREASE           TERM_FIRST_PERCENT_INCREASE
7693         ,t.OPEN_PERCENT_INCREASE            OPEN_PERCENT_INCREASE
7694         ,t.OPEN_PERCENT_INCREASE_LIFE       OPEN_PERCENT_INCREASE_LIFE
7695         ,t.OPEN_FIRST_PERCENT_INCREASE      OPEN_FIRST_PERCENT_INCREASE
7696         ,t.OPEN_CEILING_RATE                OPEN_CEILING_RATE
7697         ,t.OPEN_FLOOR_RATE                  OPEN_FLOOR_RATE
7698         ,t.OPEN_PROJECTED_RATE              OPEN_PROJECTED_RATE
7699         ,t.TERM_PROJECTED_RATE              TERM_PROJECTED_RATE
7700         ,t.rate_change_frequency            TERM_RATE_CHG_FREQ
7701         ,t.rate_change_frequency            OPEN_RATE_CHG_FREQ
7702         ,t.INDEX_RATE_ID                    OPEN_INDEX_RATE_ID
7703         ,t.INDEX_RATE_ID                    TERM_INDEX_RATE_ID
7704         ,t.OPEN_INDEX_DATE                  OPEN_INDEX_DATE
7705         ,t.TERM_INDEX_DATE                  TERM_INDEX_DATE
7706         ,decode(p_phase, 'TERM', t.TERM_PROJECTED_RATE, t.OPEN_PROJECTED_RATE) INITIAL_INTEREST_RATE
7707         ,nvl(lns_fin_utils.getActiveRate(h.loan_id), decode(p_phase, 'TERM', t.TERM_PROJECTED_RATE, t.OPEN_PROJECTED_RATE))            LAST_INTEREST_RATE
7708         ,nvl(t.FIRST_RATE_CHANGE_DATE, t.NEXT_RATE_CHANGE_DATE) FIRST_RATE_CHANGE_DATE
7709         ,t.NEXT_RATE_CHANGE_DATE             NEXT_RATE_CHANGE_DATE
7710         ,t.CALCULATION_METHOD
7711         ,t.INTEREST_COMPOUNDING_FREQ
7712         ,decode(p_phase, 'TERM', decode(p_based_on_terms,
7713             'CURRENT', decode(nvl(h.custom_payments_flag, 'N'), 'Y', nvl(t.PAYMENT_CALC_METHOD, 'CUSTOM'),
7714                                                                 'N', nvl(t.PAYMENT_CALC_METHOD, 'EQUAL_PAYMENT')),
7715             decode(nvl(h.custom_payments_flag, 'N'), 'Y', nvl(t.ORIG_PAY_CALC_METHOD, 'CUSTOM'),
7716                                                      'N', nvl(t.PAYMENT_CALC_METHOD, 'EQUAL_PAYMENT'))
7717          ), null)
7718         ,t.ORIG_PAY_CALC_METHOD
7719         ,decode(p_phase, 'TERM', trunc(nvl(t.prin_first_pay_date, t.first_payment_date)), 'OPEN', null, trunc(nvl(t.prin_first_pay_date, t.first_payment_date)))
7720         ,nvl(t.prin_payment_frequency, t.loan_payment_frequency)
7721         ,decode(trunc(nvl(t.prin_first_pay_date, t.first_payment_date)) - trunc(h.loan_start_date), 0, 'N', 'Y')  -- calculate in advance or arrears for principal
7722         ,nvl(t.PENAL_INT_RATE, 0)
7723         ,nvl(t.PENAL_INT_GRACE_DAYS, 0)
7724         ,nvl(h.CURRENT_PHASE, 'TERM')
7725         ,nvl(t.REAMORTIZE_ON_FUNDING, 'REST')
7726         ,nvl(h.ADD_REQUESTED_AMOUNT, 0)
7727         ,nvl(t.CALC_ADD_INT_UNPAID_PRIN, 'N')
7728         ,nvl(t.CALC_ADD_INT_UNPAID_INT, 'N')
7729         ,nvl(t.CAPITALIZE_INT, 'N')
7730         ,nvl(t.FLUCTUATE_EQ_PAY_AMOUNT, 'N')
7731     FROM lns_loan_headers_all h
7732         ,lns_terms t
7733         ,fnd_currencies  curr
7734     WHERE h.loan_id = p_loan_id
7735 		 AND t.loan_id = h.loan_id
7736 	   AND curr.currency_code = h.loan_currency;
7737 
7738   -- get reamortization information
7739   -- this is temporary place on LNS_AMORTIZATION_SCHEDS
7740   -- we should move this to LNS_TERMS when we have terms realignment
7741 	-- bug# 5664316 - we only store ONE reamortization row
7742     CURSOR c_reamortization(p_Loan_id NUMBER) IS
7743     SELECT nvl(reamortization_amount, 0)
7744         ,nvl(reamortize_from_installment, 0)
7745         ,nvl(reamortize_to_installment, 0)
7746     FROM lns_loan_headers_all lnh,
7747          lns_amortization_scheds amort1
7748     WHERE lnh.loan_id = amort1.loan_id(+)
7749      AND lnh.loan_id = p_loan_id
7750      AND amort1.reamortization_amount > 0;
7751 
7752     -- cursor to get the balance information for the loan
7753     -- changes as per scherkas 11-16-2005
7754     cursor c_balanceInfo(p_loan_id NUMBER, p_phase varchar2) IS
7755     select  nvl(sum(amort.PRINCIPAL_AMOUNT),0)                       -- billed principal
7756           ,nvl(sum(amort.PRINCIPAL_REMAINING),0)  -- unpaid principal
7757           ,nvl(sum(amort.INTEREST_REMAINING),0)  -- unpaid interest
7758     from LNS_AM_SCHEDS_V amort
7759     where amort.Loan_id = p_loan_id
7760       and amort.REVERSED_CODE = 'N'
7761       and amort.phase = p_phase;
7762 
7763     -- this cursor will get the last time the loan interest was accrued
7764     -- fix for bug 7423644: removed condition interest_trx_id is not null
7765     cursor c_last_interest_accrual(p_loan_id NUMBER) is
7766     select decode(LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(lnh.loan_id),
7767           0,
7768           decode(lnh.current_phase, 'TERM', lnh.loan_start_date, 'OPEN', lnh.open_loan_start_date),
7769           (select max(due_date)
7770             from lns_amortization_scheds
7771             where reversed_flag = 'N'
7772               and loan_id = lnh.loan_id
7773               and phase = lnh.current_phase))
7774     from lns_loan_headers lnh
7775     where lnh.loan_id = p_loan_id;
7776 
7777     -- this cursor is to get the last activity date on the loan
7778     -- payoff processing will use this date
7779     cursor c_last_loan_activity(p_loan_id number) is
7780     select max(activity_date)
7781       from LNS_REC_ACT_CASH_CM_V
7782      where activity_code = 'PMT'
7783        and loan_id = p_loan_id;
7784 
7785    -- begin fix for bug 6724561
7786    -- cursor to get latest extended from installment - last billed installment from the last approved loan extension
7787    cursor c_ext_from_install(p_loan_id NUMBER) IS
7788     select LAST_BILLED_INSTALLMENT
7789     from LNS_LOAN_EXTENSIONS
7790     where loan_id = p_loan_id
7791         and STATUS = 'APPROVED'
7792     order by LOAN_EXT_ID desc;
7793     -- end fix for bug 6724561
7794 
7795    -- begin fix for bug 6724522
7796    -- cursor to get original loan term if loan has been extended
7797    cursor c_orig_loan_term(p_loan_id NUMBER) IS
7798     select OLD_TERM,
7799         OLD_TERM_PERIOD,
7800         OLD_BALLOON_TYPE,
7801         OLD_BALLOON_AMOUNT,
7802         OLD_AMORT_TERM,
7803         OLD_MATURITY_DATE,
7804         OLD_INSTALLMENTS
7805     from LNS_LOAN_EXTENSIONS
7806     where loan_id = p_loan_id
7807         and STATUS = 'APPROVED'
7808     order by LOAN_EXT_ID;
7809 
7810     l_orig_loan_term        number;
7811     l_orig_loan_period      varchar2(30);
7812     l_orig_balloon_type     varchar2(30);
7813     l_orig_balloon_amount   number;
7814     l_orig_amort_term       number;
7815     l_orig_maturity_date    date;
7816     l_orig_num_install      number;
7817    -- end fix for bug 6724522
7818 
7819     l_billed_principal  number;
7820     l_amortized_to_Date date;
7821     --l_pay_in_arrears    boolean;
7822     l_loan_Details      LNS_FINANCIALS.LOAN_DETAILS_REC;
7823     l_amortize_dates    LNS_FIN_UTILS.DATE_TBL;
7824     l_loan_id           number;
7825     l_api_name          varchar2(25);
7826 
7827 begin
7828 
7829     l_api_name         := 'getLoanDetails';
7830     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
7831 
7832     --l_loan_id := p_loan_id;
7833     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_loan_id:         ' || p_loan_id);
7834     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_based_on_terms:  ' || p_based_on_terms);
7835     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' p_phase:           ' || p_phase);
7836 
7837     OPEN c_loan_details(p_loan_id, p_based_on_terms, p_phase);
7838     FETCH c_loan_details INTO
7839         l_loan_details.loan_id
7840         ,l_loan_Details.loan_term
7841         ,l_loan_Details.loan_term_period
7842         ,l_loan_Details.amortized_term
7843         ,l_loan_Details.amortized_term_period
7844         ,l_loan_details.balloon_payment_amount
7845         ,l_loan_Details.amortization_frequency
7846         ,l_loan_Details.payment_frequency
7847         ,l_loan_Details.loan_start_date
7848         ,l_loan_Details.first_payment_date
7849         ,l_loan_Details.requested_amount
7850         ,l_loan_details.funded_amount
7851         ,l_loan_details.remaining_balance
7852         ,l_loan_details.maturity_Date
7853         ,l_loan_details.reamortize_overpay
7854         ,l_loan_details.reamortize_underpay
7855         ,l_loan_details.reamortize_with_interest
7856         ,l_loan_details.last_installment_billed
7857         ,l_loan_details.day_count_method
7858         ,l_loan_details.pay_in_arrears
7859         ,l_loan_details.custom_schedule
7860         ,l_loan_details.loan_status
7861         ,l_loan_details.loan_currency
7862         ,l_loan_details.currency_precision
7863         ,l_loan_details.OPEN_TO_TERM_FLAG
7864         ,l_loan_details.OPEN_TO_TERM_EVENT
7865         ,l_loan_details.MULTIPLE_FUNDING_FLAG
7866         ,l_loan_details.SECONDARY_STATUS
7867         ,l_loan_details.RATE_TYPE                    -- fixed or variable
7868         ,l_loan_details.TERM_CEILING_RATE            -- term ceiling rate
7869         ,l_loan_details.TERM_FLOOR_RATE              -- term floor rate
7870         ,l_loan_details.TERM_ADJ_PERCENT_INCREASE    -- term percentage increase btwn adjustments
7871         ,l_loan_details.TERM_LIFE_PERCENT_INCREASE   -- term lifetime max adjustment for interest
7872         ,l_loan_details.TERM_FIRST_PERCENT_INCREASE  -- term first percentage increase
7873         ,l_loan_details.OPEN_ADJ_PERCENT_INCREASE    -- open percentage increase btwn adjustments
7874         ,l_loan_details.OPEN_LIFE_PERCENT_INCREASE   -- open lifetime max adjustment for interest
7875         ,l_loan_details.OPEN_FIRST_PERCENT_INCREASE  -- open first percentage increase
7876         ,l_loan_details.OPEN_CEILING_RATE            -- open ceiling rate
7877         ,l_loan_details.OPEN_FLOOR_RATE              -- open floor rate
7878         ,l_loan_details.OPEN_PROJECTED_INTEREST_RATE -- open projected interest rate
7879         ,l_loan_details.TERM_PROJECTED_INTEREST_RATE -- term projected interest rate
7880         ,l_loan_details.OPEN_RATE_CHG_FREQ
7881         ,l_loan_details.TERM_RATE_CHG_FREQ
7882         ,l_loan_details.OPEN_INDEX_RATE_ID
7883         ,l_loan_details.TERM_INDEX_RATE_ID
7884         ,l_loan_details.OPEN_INDEX_DATE
7885         ,l_loan_details.TERM_INDEX_DATE
7886         ,l_loan_details.INITIAL_INTEREST_RATE        -- current phase only
7887         ,l_loan_details.LAST_INTEREST_RATE           -- current phase only
7888         ,l_loan_details.FIRST_RATE_CHANGE_DATE       -- current phase only
7889         ,l_loan_details.NEXT_RATE_CHANGE_DATE        -- current phase only
7890         ,l_loan_details.CALCULATION_METHOD
7891         ,l_loan_details.INTEREST_COMPOUNDING_FREQ
7892         ,l_loan_details.PAYMENT_CALC_METHOD
7893         ,l_loan_details.ORIG_PAY_CALC_METHOD
7894         ,l_loan_details.prin_first_pay_date
7895         ,l_loan_details.prin_payment_frequency
7896         ,l_loan_details.PRIN_PAY_IN_ARREARS
7897         ,l_loan_details.PENAL_INT_RATE
7898         ,l_loan_details.PENAL_INT_GRACE_DAYS
7899         ,l_loan_details.LOAN_PHASE
7900         ,l_loan_details.REAMORTIZE_ON_FUNDING
7901         ,l_loan_details.ADD_REQUESTED_AMOUNT
7902         ,l_loan_details.CALC_ADD_INT_UNPAID_PRIN
7903         ,l_loan_details.CALC_ADD_INT_UNPAID_INT
7904         ,l_loan_details.CAPITALIZE_INT
7905         ,l_loan_details.FLUCTUATE_EQ_PAY_AMOUNT
7906         ;
7907     close c_loan_details;
7908 
7909     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate_type ' || l_loan_details.rate_type);
7910     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_ceiling_rate ' || l_loan_details.open_ceiling_rate);
7911     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': open_floor_rate ' || l_loan_details.open_floor_rate);
7912 
7913     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': balloon_payment_amount' || l_loan_details.balloon_payment_amount);
7914 
7915     -- begin fix for bug 6724522
7916     -- replacing loan terms with original data for p_based_on_terms <> 'CURRENT'
7917     if p_based_on_terms <> 'CURRENT' then
7918         open c_orig_loan_term(p_loan_id);
7919         fetch c_orig_loan_term into
7920             l_orig_loan_term,
7921             l_orig_loan_period,
7922             l_orig_balloon_type,
7923             l_orig_balloon_amount,
7924             l_orig_amort_term,
7925             l_orig_maturity_date,
7926             l_orig_num_install;
7927         close c_orig_loan_term;
7928 
7929         if l_orig_loan_term is not null and
7930            l_orig_loan_period is not null and
7931            l_orig_balloon_type is not null and
7932            l_orig_balloon_amount is not null and
7933            l_orig_amort_term is not null and
7934            l_orig_maturity_date is not null and
7935            l_orig_num_install is not null
7936         then
7937             l_loan_Details.loan_term := l_orig_loan_term;
7938             l_loan_Details.loan_term_period := l_orig_loan_period;
7939             l_loan_Details.amortized_term_period := l_orig_loan_period;
7940             l_loan_Details.maturity_Date := l_orig_maturity_date;
7941             l_loan_Details.ORIG_NUMBER_INSTALLMENTS := l_orig_num_install;
7942 
7943             if l_orig_balloon_type = 'TERM' then
7944                 l_loan_details.balloon_payment_amount := 0;
7945                 l_loan_Details.amortized_term := l_orig_amort_term;
7946             elsif l_orig_balloon_type = 'AMOUNT' then
7947                 l_loan_details.balloon_payment_amount := l_orig_balloon_amount;
7948                 l_loan_Details.amortized_term := l_orig_loan_term;
7949             end if;
7950         end if;
7951     end if;
7952     -- end fix for bug 6724522
7953 
7954     -- begin fix for bug 6724561
7955     -- get latest extended from installment
7956     if p_based_on_terms = 'CURRENT' then
7957         open c_ext_from_install(p_loan_id);
7958         fetch c_ext_from_install into l_loan_Details.extend_from_installment;
7959         close c_ext_from_install;
7960     end if;
7961     -- end fix for bug 6724561
7962 
7963     -- adding balloon amount
7964 	l_loan_details.amortized_amount := l_loan_details.requested_amount - l_loan_details.balloon_payment_amount;
7965 
7966     open c_last_interest_accrual(p_loan_id);
7967     fetch c_last_interest_accrual into l_loan_details.last_interest_accrual;
7968     close c_last_interest_accrual;
7969 
7970     if l_loan_details.pay_in_arrears = 'Y' then
7971        l_loan_details.pay_in_arrears_boolean := true;
7972     else
7973        l_loan_details.pay_in_arrears_boolean := false;
7974     end if;
7975 
7976     if l_loan_details.PRIN_PAY_IN_ARREARS = 'Y' then
7977        l_loan_details.PRIN_PAY_IN_ARREARS_BOOL := true;
7978     else
7979        l_loan_details.PRIN_PAY_IN_ARREARS_BOOL := false;
7980     end if;
7981 
7982     if p_based_on_terms = 'CURRENT' then
7983         -- get reamortization information
7984         Begin
7985             -- bug# 5664316 make sure we catch no data found on EACH cursor: reamortization, activity, balanceInfo
7986             open c_reamortization(p_loan_id);
7987             fetch c_reamortization into
7988                     l_loan_details.reamortize_amount
7989                 ,l_loan_details.reamortize_from_installment
7990                 ,l_loan_details.reamortize_to_installment;
7991             close c_reamortization;
7992         Exception
7993             when no_data_found then
7994             l_loan_details.reamortize_amount           := 0;
7995             l_loan_details.reamortize_from_installment := null;
7996             l_loan_details.reamortize_to_installment   := 0;
7997         End;
7998 
7999         Begin
8000             open c_last_loan_activity(p_loan_id);
8001             fetch c_last_loan_activity into
8002                     l_loan_details.last_activity_date;
8003             close c_last_loan_activity;
8004         Exception
8005             when no_data_found then
8006             l_loan_details.last_activity_date          := null;
8007         End;
8008 
8009         Begin
8010 
8011             -- get balance information
8012             open c_balanceInfo(p_loan_id, p_phase);
8013             fetch c_balanceInfo into
8014                 l_billed_principal
8015                 ,l_loan_details.unpaid_principal
8016                 ,l_loan_details.UNPAID_INTEREST;
8017             close c_balanceInfo;
8018 
8019             l_loan_details.billed_principal := l_billed_principal;
8020             l_loan_details.unbilled_principal := l_loan_details.funded_amount - l_billed_principal;
8021             if l_loan_details.LOAN_PHASE = 'TERM' and l_loan_details.loan_status = 'CANCELLED' then
8022                 l_loan_details.unpaid_principal := 0;
8023                 l_loan_details.UNPAID_INTEREST := 0;
8024             end if;
8025 
8026         Exception
8027             when no_data_found then
8028                 l_loan_details.unpaid_principal            := 0;
8029                 l_loan_details.billed_principal            := 0;
8030                 l_loan_details.unbilled_principal          := l_loan_details.funded_amount;
8031                 l_loan_details.UNPAID_INTEREST             := 0;
8032         End;
8033 
8034     else
8035         l_loan_details.reamortize_amount           := 0;
8036         l_loan_details.reamortize_from_installment := null;
8037         l_loan_details.reamortize_to_installment   := 0;
8038         l_loan_details.last_activity_date          := null;
8039         l_loan_details.unpaid_principal            := 0;
8040         l_loan_details.billed_principal            := 0;
8041         l_loan_details.unbilled_principal          := l_loan_details.funded_amount;
8042         l_loan_details.UNPAID_INTEREST             := 0;
8043     end if;
8044 
8045     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '<---------- BEGIN LOAN DETAILS ------------->');
8046 
8047     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortized_term: ' || l_loan_details.amortized_term);
8048     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortized_term_period:  ' || l_loan_details.amortized_term_period);
8049     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': amortization_frequency:  ' || l_loan_details.amortization_frequency);
8050     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': first_payment_date:  ' || l_loan_details.first_payment_date);
8051     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_start_date: ' || l_loan_details.loan_start_date);
8052     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': funded_amount: ' || l_loan_details.funded_amount);
8053     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': remaining_balance: ' || l_loan_details.remaining_balance);
8054     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': reamortize_amount: ' || l_loan_details.reamortize_amount);
8055     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': reamortize_from_installment: ' || l_loan_details.reamortize_from_installment);
8056     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': day_count_method: ' || l_loan_details.day_count_method);
8057     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': last_installment_billed: ' || l_loan_details.last_installment_billed);
8058     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': PAYMENT_CALC_METHOD: ' || l_loan_details.PAYMENT_CALC_METHOD);
8059     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CALCULATION_METHOD: ' || l_loan_details.CALCULATION_METHOD);
8060     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': INTEREST_COMPOUNDING_FREQ: ' || l_loan_details.INTEREST_COMPOUNDING_FREQ);
8061     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prin_first_pay_date: ' || l_loan_details.prin_first_pay_date);
8062     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prin_payment_frequency: ' || l_loan_details.prin_payment_frequency);
8063     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': unbilled_principal  ' || l_loan_details.unbilled_principal);
8064     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': unpaid_principal  ' || l_loan_details.unpaid_principal);
8065     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': UNPAID_INTEREST  ' || l_loan_details.UNPAID_INTEREST);
8066     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': extend_from_installment  ' || l_loan_Details.extend_from_installment);
8067     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ORIG_PAY_CALC_METHOD  ' || l_loan_Details.ORIG_PAY_CALC_METHOD);
8068     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': CAPITALIZE_INT  ' || l_loan_Details.CAPITALIZE_INT);
8069     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': FLUCTUATE_EQ_PAY_AMOUNT  ' || l_loan_Details.FLUCTUATE_EQ_PAY_AMOUNT);
8070 
8071     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '<---------- END LOAN DETAILS --------------->');
8072     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8073 
8074     return l_loan_details;
8075 
8076 Exception
8077     When No_Data_Found then
8078         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - LOAN ID: ' || l_loan_id || ' not found');
8079         FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_LOAN_ID');
8080         FND_MSG_PUB.Add;
8081         RAISE FND_API.G_EXC_ERROR;
8082 
8083     When Others then
8084         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || 'Err: ' || sqlerrm);
8085         RAISE FND_API.G_EXC_ERROR;
8086 
8087 end getLoanDetails;
8088 
8089 
8090 /*=========================================================================
8091 || PUBLIC PROCEDURE shiftLoan
8092 ||
8093 || DESCRIPTION
8094 ||
8095 || Overview: will shift a loans OPEN phase  and/or TERM phase
8096 ||           where appropriate
8097 ||          1. determine if any disbursements are past the open maturity date
8098 ||          2. if so, get the next available maturity date,
8099 ||             -- this should increment by amortization frequency
8100 ||          3. update the term/term period - in terms of payment frequency,
8101 ||             -- the term will change to X MONTHS if TERM was > MONTHS
8102 ||
8103 || Parameter: p_loan_id  = loan_id
8104 ||
8105 || Source Tables:  LNS_LOAN_HEADERS_ALL, LNS_DISB_HEADERS
8106 ||                 LNS_TERMS
8107 ||
8108 || Target Tables: LNS_LOAN_HEADERS_ALL, LNS_TERMS
8109 ||
8110 || Return value:  Standard Oracle API
8111 ||
8112 || MODIFICATION HISTORY
8113 || Date                    Author           Description of Changes
8114 || 02/14/2005 11:35AM     raverma           Created
8115  *=======================================================================*/
8116 procedure shiftLoan(p_loan_id        in number
8117                    ,p_init_msg_list  IN VARCHAR2
8118                    ,p_commit         IN VARCHAR2
8119                    ,x_return_status  OUT NOCOPY VARCHAR2
8120                    ,x_msg_count      OUT NOCOPY NUMBER
8121                    ,x_msg_data       OUT NOCOPY VARCHAR2)
8122 
8123 is
8124 
8125     l_api_name              varchar2(25);
8126     l_move_maturity_date    number;
8127     i                       number;
8128     l_old_maturity_date     date;
8129     l_new_maturity_date     date;
8130     l_max_pay_request_date  date;
8131     l_payment_frequency     varchar2(30);
8132     l_new_frequency         varchar2(30);
8133     l_custom_payments_flag  varchar2(1);
8134     l_current_phase         varchar2(30);
8135     l_term                  number;
8136     l_term_period           varchar2(30);
8137     l_temp                  varchar2(30);
8138     l_term_phase_exists     varchar2(1);
8139     l_term_id               number;
8140     l_initial_months        number;
8141 
8142     l_return_status         VARCHAR2(1);
8143     l_msg_count             NUMBER;
8144     l_msg_data              VARCHAR2(32767);
8145     l_loan_details          LOAN_DETAILS_REC;
8146     l_loan_header_rec       LNS_LOAN_HEADER_PUB.loan_header_rec_type;
8147     l_term_rec              LNS_TERMS_PUB.loan_term_rec_type;
8148     l_version_number        number;
8149     l_terms_version_number  number;
8150     l_dates_shifted_flag    varchar2(1) := 'N';
8151 
8152 
8153     CURSOR move_maturity_date_cur(P_LOAN_ID number) IS
8154     select
8155       CASE
8156     WHEN (nvl(loan.CURRENT_PHASE, 'TERM') = 'OPEN') THEN
8157           sign(trunc(loan.OPEN_MATURITY_DATE) - (select trunc(max(PAYMENT_REQUEST_DATE)) from LNS_DISB_HEADERS where LOAN_ID = loan.LOAN_ID))
8158     WHEN (nvl(loan.CURRENT_PHASE, 'TERM') = 'TERM' and loan.MULTIPLE_FUNDING_FLAG = 'N') THEN
8159          sign(trunc(loan.LOAN_MATURITY_DATE) - (select trunc(max(PAYMENT_REQUEST_DATE)) from LNS_DISB_HEADERS where LOAN_ID = loan.LOAN_ID))
8160     ELSE
8161     1
8162     END
8163     from lns_loan_headers loan
8164     where loan.LOAN_ID = p_loan_id;
8165 
8166 
8167     cursor c_loan_info (p_loan_id number) is
8168     select  t.open_payment_frequency
8169            ,decode(h.current_phase, 'OPEN', h.open_maturity_date, h.loan_maturity_date)
8170            ,nvl(h.custom_payments_flag, 'N')
8171            ,h.open_to_term_flag
8172            ,decode(h.current_phase, 'OPEN', h.open_loan_term, h.loan_term)
8173            ,decode(h.current_phase, 'OPEN', h.open_loan_term_period, h.loan_term_period)
8174            ,h.OBJECT_VERSION_NUMBER
8175            ,t.object_VERSION_NUMBER
8176            ,t.term_id
8177            ,h.current_phase
8178       from  lns_terms  t
8179            ,lns_loan_headers  h
8180      where h.loan_id = p_loan_id
8181        and h.loan_id = t.loan_id;
8182 
8183     cursor c_max_pay_req_date(p_loan_id number) is
8184     select max(payment_request_date)
8185       from lns_disb_headers
8186       where loan_id = p_loan_id;
8187 
8188 begin
8189     -- Standard Start of API savepoint
8190     SAVEPOINT shiftLoan;
8191     l_api_name           := 'shiftLoan';
8192     i := 0;
8193 
8194     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8195     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
8196 
8197     -- Initialize API return status to SUCCESS
8198     x_return_status := FND_API.G_RET_STS_SUCCESS;
8199 
8200     --
8201     -- Api body
8202     -- -----------------------------------------------------------------
8203     open move_maturity_date_cur(P_LOAN_ID);
8204     fetch move_maturity_date_cur into l_move_maturity_date;
8205     close move_maturity_date_cur;
8206 
8207     if l_move_maturity_date = -1 then
8208 
8209       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - we need to move the loan');
8210 
8211       -- get the final payment request date
8212       open c_max_pay_req_date(p_loan_id);
8213       fetch c_max_pay_req_date into l_max_pay_request_date;
8214       close c_max_pay_req_date;
8215       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_max_pay_request_date' || l_max_pay_request_date);
8216 
8217       -- get loan info
8218       open c_loan_info(p_loan_id);
8219       fetch c_loan_info into
8220           l_payment_frequency
8221          ,l_old_maturity_date
8222          ,l_custom_payments_flag
8223          ,l_term_phase_exists
8224          ,l_term
8225          ,l_term_period
8226          ,l_version_number
8227          ,l_terms_version_number
8228          ,l_term_id
8229          ,l_current_phase;
8230       close c_loan_info;
8231 
8232       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_payment_frequency ' || l_payment_frequency);
8233       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_old_maturity_date ' || l_old_maturity_date );
8234       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_custom_payments_flag ' || l_custom_payments_flag);
8235       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_phase_exists ' || l_term_phase_exists );
8236       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term ' || l_term);
8237       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_period ' || l_term_period );
8238       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_version_number ' || l_version_number );
8239       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_terms_version_number ' || l_terms_version_number );
8240       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_term_id ' || l_term_id );
8241 
8242       if l_custom_payments_flag <> 'Y' then
8243           -- we will be converting the term of the loan if frequency > MONTHLY
8244           if l_payment_frequency <> 'SEMI-MONTHLY' AND l_payment_frequency <> 'WEEKLY' AND l_payment_frequency <> 'BIWEEKLY' then
8245              l_new_frequency := 'MONTHS';
8246              l_initial_months := lns_fin_utils.convertPeriod(p_term         => l_term
8247                                                             ,p_term_period  => l_term_period);
8248           else
8249              --weeks or semi-months
8250              if substr(l_payment_frequency, length(l_payment_frequency) - 1, 2) = 'LY' then
8251                  l_temp := substr(l_payment_frequency, 1, length(l_payment_frequency) - 2) || 'S';
8252              else
8253                  l_temp := l_payment_frequency;
8254              end if;
8255              l_new_frequency := l_temp;
8256              l_initial_months := l_term;
8257           end if;
8258           l_new_maturity_Date := l_old_maturity_date;
8259 
8260           loop
8261             -- i will be the number of "TERMS" to add the LNS_LOAN_HEADERS.TERM
8262             i := i + 1;
8263             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - i ' || l_new_maturity_date);
8264             l_new_maturity_date := lns_fin_utils.getNextDate(p_date          => l_new_maturity_date
8265                                                             ,p_interval_type => l_new_frequency
8266                                                             ,p_direction     => 1);
8267             exit when l_new_maturity_date >= l_max_pay_request_date;
8268           end loop;
8269 
8270           logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NEW MATURITY DATE' || l_new_maturity_date );
8271 
8272           --now we move the loan dates
8273           if (l_current_phase = 'OPEN' and l_term_phase_exists = 'Y') then
8274              logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting new term dates');
8275 
8276 	     -- Bug#6169438, Added new parameter l_dates_shifted_flag
8277              shiftLoanDates(p_loan_id        => p_loan_id
8278                            ,p_new_start_date => l_new_maturity_date
8279                            ,p_phase          => 'TERM'
8280                            ,x_loan_details   => l_loan_details
8281                            ,x_dates_shifted_flag => l_dates_shifted_flag
8282                            ,x_return_status  => l_return_status
8283                            ,x_msg_count      => l_msg_count
8284                            ,x_msg_data       => l_msg_data);
8285              logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM start date is ' || l_loan_details.loan_start_date);
8286              logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM first payment date is ' || l_loan_details.first_payment_Date);
8287              logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM principal first payment date is ' || l_loan_details.PRIN_FIRST_PAY_DATE);
8288              logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' new TERM maturity date is ' || l_loan_details.maturity_date);
8289 
8290              -- items to update for term phase
8291              l_term_rec.term_id                   := l_term_id;
8292              l_term_rec.FIRST_PAYMENT_DATE        := l_loan_details.first_payment_Date;
8293              l_term_rec.PRIN_FIRST_PAY_DATE       := l_loan_details.PRIN_FIRST_PAY_DATE;
8294              l_term_rec.NEXT_PAYMENT_DUE_DATE     := l_loan_details.first_payment_Date;
8295              l_loan_header_rec.loan_maturity_date := l_loan_details.maturity_date;
8296              l_loan_header_rec.loan_start_date    := l_loan_details.loan_start_date;
8297              lns_terms_pub.update_term(p_object_version_number => l_terms_version_number
8298                                       ,p_init_msg_list         => fnd_api.g_false
8299                                       ,p_loan_term_rec         => l_term_rec
8300                                       ,x_return_status         => l_return_status
8301                                       ,x_msg_count             => l_msg_count
8302                                       ,x_msg_data              => l_msg_data);
8303           end if;
8304 
8305           if l_current_phase = 'OPEN' then
8306               -- update items for loan header table
8307               l_loan_header_rec.loan_id               := p_loan_id;
8308               l_loan_header_rec.open_maturity_date    := l_new_maturity_date;
8309               l_loan_header_rec.open_loan_term        := l_initial_months + i;
8310               l_loan_header_rec.open_loan_term_period := l_new_frequency;
8311 
8312               lns_loan_header_pub.update_loan(p_object_version_number => l_version_number
8313                                              ,p_loan_header_rec       => l_loan_header_rec
8314                                              ,p_init_msg_list         => fnd_api.g_false
8315                                              ,x_return_status         => l_return_status
8316                                              ,x_msg_count             => l_msg_count
8317                                              ,x_msg_data              => l_msg_data);
8318           elsif l_current_phase = 'TERM' then
8319 
8320               l_loan_header_rec.loan_id               := p_loan_id;
8321               l_loan_header_rec.loan_maturity_date    := l_new_maturity_date;
8322               l_loan_header_rec.loan_term             := l_initial_months + i;
8323               l_loan_header_rec.loan_term_period      := l_new_frequency;
8324 
8325               lns_loan_header_pub.update_loan(p_object_version_number => l_version_number
8326                                              ,p_loan_header_rec       => l_loan_header_rec
8327                                              ,p_init_msg_list         => fnd_api.g_false
8328                                              ,x_return_status         => l_return_status
8329                                              ,x_msg_count             => l_msg_count
8330                                              ,x_msg_data              => l_msg_data);
8331 
8332           end if; -- open phase
8333       end if; -- custom payments
8334 
8335     else
8336       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NOTHING TO MOVE');
8337     end if;
8338 
8339     --
8340     -- End of API body
8341     --  ----------------------------------------------------------------
8342     --
8343     -- Standard check for p_commit
8344     IF FND_API.to_Boolean(p_commit) THEN
8345         COMMIT WORK;
8346     END IF;
8347 
8348 
8349     FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
8350 
8351     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8352 
8353    EXCEPTION
8354         WHEN FND_API.G_EXC_ERROR THEN
8355               ROLLBACK TO shiftLoan;
8356               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8357               x_return_status := FND_API.G_RET_STS_ERROR;
8358               x_msg_count := l_msg_count;
8359               x_msg_data  := l_msg_data;
8360               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8361 
8362          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8363               ROLLBACK TO shiftLoan;
8364               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8365               x_return_status := FND_API.G_RET_STS_ERROR;
8366               x_msg_count := l_msg_count;
8367               x_msg_data  := l_msg_data;
8368               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8369 
8370         WHEN OTHERS THEN
8371               ROLLBACK TO shiftLoan;
8372               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8373               x_return_status := FND_API.G_RET_STS_ERROR;
8374               x_msg_count := l_msg_count;
8375               x_msg_data  := l_msg_data;
8376               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8377 
8378 end shiftLoan;
8379 
8380 /*=========================================================================
8381 || PUBLIC PROCEDURE shiftLoanDates
8382 ||
8383 || DESCRIPTION
8384 ||
8385 || Overview: procedure will return a new loan details record with
8386 ||           shifted dates
8387 ||
8388 || Parameter: p_loan_id  = loan_id
8389 ||            p_new_start_Date = new start date of loan
8390 ||
8391 || Source Tables:  NA
8392 ||
8393 || Target Tables:
8394 ||
8395 || Return value: x_loan_Details
8396 ||               detail record of the loan with the new dates
8397 ||
8398 || KNOWN ISSUES
8399 ||
8400 || NOTES
8401 ||
8402 || MODIFICATION HISTORY
8403 || Date                  Author            Description of Changes
8404 || 11/29/2004 11:35AM     raverma           Created
8405 || 7/29/2005             raverma            added p_phase
8406 || 14-JUL-2007		 mbolli		    Bug#6169438 - Added new OUT parameter x_dates_shifted_flag
8407  *====================================================================================================*/
8408 procedure shiftLoanDates(p_loan_id        in number
8409                         ,p_new_start_date in date
8410 						,p_phase          in varchar2
8411                         ,x_loan_details   out NOCOPY lns_financials.loan_details_rec
8412                         ,x_dates_shifted_flag OUT NOCOPY VARCHAR2
8413                         ,x_return_status  OUT NOCOPY VARCHAR2
8414                         ,x_msg_count      OUT NOCOPY NUMBER
8415                         ,x_msg_data       OUT NOCOPY VARCHAR2)
8416 is
8417     l_return_status          VARCHAR2(1);
8418     l_msg_count              NUMBER;
8419     l_msg_data               VARCHAR2(32767);
8420     l_api_name               varchar2(25);
8421     l_loan_details           lns_financials.loan_Details_rec;
8422     l_day_difference         number;
8423     l_new_maturity_date      date;
8424     l_new_first_payment_date date;
8425     x                        number;
8426     l_new_int_first_pay_date date;
8427     l_new_prin_first_pay_date date;
8428     l_shift_dates_proc       varchar2(100);
8429     l_plsql_block            varchar2(200);
8430 
8431 begin
8432 
8433     -- Standard Start of API savepoint
8434     SAVEPOINT shiftLoanDates;
8435     l_api_name           := 'shiftLoanDates';
8436     x := 0;
8437 
8438     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8439     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id = ' || p_loan_id);
8440     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_new_start_date = ' || p_new_start_date);
8441     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase = ' || p_phase);
8442 
8443     -- Initialize API return status to SUCCESS
8444     x_return_status := FND_API.G_RET_STS_SUCCESS;
8445     x_dates_shifted_flag := 'N';
8446 
8447     --
8448     -- Api body
8449     -- ----------------------------------------------------------------
8450     lns_utility_pub.validate_any_id(p_api_version    =>  1.0
8451                                    ,p_init_msg_list  =>  'T'
8452                                    ,x_msg_count      =>  l_msg_count
8453                                    ,x_msg_data       =>  l_msg_data
8454                                    ,x_return_status  =>  l_return_status
8455                                    ,p_col_id         =>  p_loan_id
8456                                    ,p_col_name       =>  'LOAN_ID'
8457                                    ,p_table_name     =>  'LNS_LOAN_HEADERS_ALL');
8458 
8459     if l_return_status <> FND_API.G_RET_STS_SUCCESS then
8460         FND_MESSAGE.SET_NAME('LNS', 'LNS_INVALID_VALUE');
8461         FND_MESSAGE.SET_TOKEN('PARAMETER', 'LOAN_ID');
8462         FND_MESSAGE.SET_TOKEN('VALUE', p_loan_ID);
8463         FND_MSG_PUB.ADD;
8464         RAISE FND_API.G_EXC_ERROR;
8465     end if;
8466 
8467     l_loan_details := lns_financials.getLoanDetails(p_loan_id        => p_loan_id
8468                                                    ,p_based_on_terms => 'ORIGINAL'
8469 												   ,p_phase          => p_phase);
8470 
8471     if l_loan_Details.loan_start_date = p_new_start_date then
8472         x_loan_details := l_loan_details;
8473         return;
8474     end if;
8475 
8476     -- get the new maturity date
8477     l_new_maturity_date := LNS_FIN_UTILS.getMaturityDate(p_term         => l_loan_Details.loan_term
8478                                                         ,p_term_period  => l_loan_Details.loan_term_period
8479                                                         ,p_frequency    => l_loan_Details.amortization_frequency
8480                                                         ,p_start_date   => p_new_start_date);
8481 
8482     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_maturity_date ' || l_new_maturity_date);
8483 
8484     -- fix for FP bug 6938095: get package.procedure from LNS_SHIFT_PAY_DATES_PROC profile and call it dynamically
8485     l_shift_dates_proc := NVL(FND_PROFILE.VALUE('LNS_SHIFT_PAY_DATES_PROC'), 'LNS_DEFAULT_HOOKS_PVT.SHIFT_PAY_START_DATES');
8486     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_shift_dates_proc: ' || l_shift_dates_proc);
8487 
8488     l_plsql_block := 'BEGIN ' || l_shift_dates_proc || '(:1, :2, :3, :4, :5, :6, :7, :8, :9, :10); END;';
8489 
8490     BEGIN
8491 
8492         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Calling...');
8493 
8494         EXECUTE IMMEDIATE l_plsql_block
8495         USING
8496             IN p_loan_id,
8497             IN p_new_start_date,
8498             IN l_loan_details.loan_start_Date,
8499             IN l_loan_details.first_payment_Date,
8500             IN l_loan_details.PRIN_FIRST_PAY_DATE,
8501             IN l_loan_Details.maturity_Date,
8502             IN p_new_start_date,
8503             IN OUT l_new_maturity_date,
8504             OUT l_new_int_first_pay_date,
8505             OUT l_new_prin_first_pay_date;
8506 
8507         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Done');
8508 
8509     EXCEPTION
8510         WHEN OTHERS THEN
8511             logMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, 'ERROR: ' || sqlerrm);
8512             FND_MESSAGE.SET_NAME('LNS', 'LNS_API_OTHERS_EXCEP');
8513             FND_MESSAGE.SET_TOKEN('ERROR' ,SQLERRM);
8514             FND_MSG_PUB.ADD;
8515             RAISE FND_API.G_EXC_ERROR;
8516     END;
8517 
8518     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_int_first_pay_date: ' || l_new_int_first_pay_date);
8519     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_prin_first_pay_date: ' || l_new_prin_first_pay_date);
8520     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_maturity_date: ' || l_new_maturity_date);
8521 
8522     if l_new_int_first_pay_date is null or l_new_int_first_pay_date < p_new_start_date then
8523         FND_MESSAGE.SET_NAME('LNS', 'LNS_PAYMENT_START_DATE_ERROR2');
8524         FND_MSG_PUB.ADD;
8525         RAISE FND_API.G_EXC_ERROR;
8526     end if;
8527 
8528     if l_new_int_first_pay_date > l_new_maturity_date then
8529         FND_MESSAGE.SET_NAME('LNS', 'LNS_PAYMENT_START_DATE_ERROR1');
8530         FND_MSG_PUB.ADD;
8531         RAISE FND_API.G_EXC_ERROR;
8532     end if;
8533 
8534     if l_loan_details.PRIN_FIRST_PAY_DATE is not null then
8535         if l_new_prin_first_pay_date is null or l_new_prin_first_pay_date < p_new_start_date then
8536             FND_MESSAGE.SET_NAME('LNS', 'LNS_PRIN_PAY_START_DATE_ERROR2');
8537             FND_MSG_PUB.ADD;
8538             RAISE FND_API.G_EXC_ERROR;
8539         end if;
8540 
8541         if l_new_prin_first_pay_date > l_new_maturity_date then
8542             FND_MESSAGE.SET_NAME('LNS', 'LNS_PRIN_PAY_START_DATE_ERROR1');
8543             FND_MSG_PUB.ADD;
8544             RAISE FND_API.G_EXC_ERROR;
8545         end if;
8546     end if;
8547 
8548     -- assign the new dates to the loan details record
8549     l_loan_Details.loan_start_date    := p_new_start_date;
8550     l_loan_details.first_payment_Date := l_new_int_first_pay_date;
8551     l_loan_details.PRIN_FIRST_PAY_DATE := l_new_prin_first_pay_date;
8552     l_loan_Details.maturity_Date      := l_new_maturity_Date;
8553 
8554     x_loan_details := l_loan_details;
8555     x_dates_shifted_flag := 'Y';
8556 
8557     --
8558     -- End of API body
8559     --
8560     FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
8561 
8562     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8563    EXCEPTION
8564         WHEN FND_API.G_EXC_ERROR THEN
8565               ROLLBACK TO shiftLoanDates;
8566               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8567               x_return_status := FND_API.G_RET_STS_ERROR;
8568               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8569 
8570          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8571               ROLLBACK TO shiftLoanDates;
8572               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8573               x_return_status := FND_API.G_RET_STS_ERROR;
8574               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8575 
8576         WHEN OTHERS THEN
8577               ROLLBACK TO shiftLoanDates;
8578               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8579               x_return_status := FND_API.G_RET_STS_ERROR;
8580               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8581 end shiftLoanDates;
8582 
8583 
8584 /*=========================================================================
8585 || PUBLIC PROCEDURE calculateEPPayment
8586 ||
8587 || DESCRIPTION
8588 ||
8589 || Overview:  returns a termly equal principal payment amount for a loan
8590 ||
8591 || PSEUDO CODE/LOGIC
8592 ||
8593 || PARAMETERS
8594 ||
8595 || Parameter:  p_loan_amount     => amount of loan
8596 ||             p_num_intervals   => number of installments for loan
8597 ||             p_ending_balance  => future or residual value of the loan  (most loans will pass 0)
8598 ||             p_pay_in_arrears  => true if payments are at end of period
8599 ||                                  false otherwise
8600 ||
8601 || payment = (p_loan_amount - p_ending_balance) / p_num_intervals;
8602 ||
8603 || Return value:  principal amount to pay per installment
8604 ||
8605 || Source Tables:  NA
8606 ||
8607 || Target Tables:  NA
8608 ||
8609 || KNOWN ISSUES
8610 ||
8611 || NOTES
8612 ||
8613 || MODIFICATION HISTORY
8614 || Date                  Author            Description of Changes
8615 || 09/13/2007            scherkas          Created
8616  *=======================================================================*/
8617 function calculateEPPayment(p_loan_amount     in number
8618                          ,p_num_intervals   in number
8619                          ,p_ending_balance  in number
8620                          ,p_pay_in_arrears  in boolean) return number
8621 
8622 is
8623   l_periodic_amount   number;
8624   l_api_name          varchar2(25);
8625 
8626 begin
8627 
8628      l_api_name := 'calculateEPPayment';
8629      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8630 
8631      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ': loan amount is ' || p_loan_amount);
8632      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ending balance is ' || p_ending_balance);
8633      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number of intervals is ' || p_num_intervals);
8634 
8635      l_periodic_amount := (p_loan_amount - p_ending_balance) / p_num_intervals;
8636 
8637      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic_prin_amount: ' || l_periodic_amount);
8638      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8639 
8640      return l_periodic_amount;
8641 
8642 Exception
8643     When others then
8644         null;
8645 
8646 end calculateEPPayment;
8647 
8648 
8649 
8650 /*=========================================================================
8651 || PUBLIC PROCEDURE calculatePayment
8652 ||
8653 || DESCRIPTION
8654 ||
8655 || Overview:  returns a termly payment amount for a loan
8656 ||
8657 || PSEUDO CODE/LOGIC
8658 ||
8659 || PARAMETERS
8660 ||
8661 || Parameter:  p_annualized_rate => annual rate of the loan
8662 ||             p_loan_amount     => amount of loan
8663 ||             p_num_intervals   => number of installments for loan
8664 ||             p_ending_balance  => future or residual value of the loan  (most loans will pass 0)
8665 ||             p_pay_in_arrears  => true if payments are at end of period
8666 ||                                  false otherwise
8667 ||
8668 || payment =
8669 || loan_amount x  periodic_rate /
8670 ||  (1 - (1 / (1 + periodic_rate)^p_num_intervals  )) -
8671 ||   p_ending_balance x periodic_rate /
8672 || ((1 + periodic_rate)^p_num_intervals  -1)
8673 ||
8674 || Return value:  amount to pay per installment
8675 ||
8676 || Source Tables:  NA
8677 ||
8678 || Target Tables:  NA
8679 ||
8680 || KNOWN ISSUES
8681 ||
8682 || NOTES
8683 ||
8684 || MODIFICATION HISTORY
8685 || Date                  Author            Description of Changes
8686 || 12/11/2003 12:40PM     raverma           Created
8687 ||  7/22/2003             raverma           enable pay in arrears = false
8688  *=======================================================================*/
8689 function calculatePayment(p_loan_amount     in number
8690                          ,p_periodic_rate   in number
8691                          ,p_num_intervals   in number
8692                          ,p_ending_balance  in number
8693                          ,p_pay_in_arrears  in boolean) return number
8694 
8695 is
8696   l_periodic_amount   number;
8697   l_numerator         number;
8698   l_denominator       number;
8699   l_api_name          varchar2(25);
8700   l_num_intervals     number;
8701 
8702 begin
8703 
8704      l_api_name := 'calculatePayment';
8705      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8706 
8707      if p_pay_in_arrears then
8708          logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' pay in arrears');
8709      else
8710          logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' pay in advance');
8711      end if;
8712      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': number of intervals is ' || p_num_intervals);
8713      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic rate is ' || p_periodic_rate);
8714      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': ending balance is ' || p_ending_balance);
8715      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ': loan amount is ' || p_loan_amount);
8716 
8717      l_num_intervals := p_num_intervals;
8718      if l_num_intervals = 0 then
8719         l_num_intervals := 1;
8720      end if;
8721      -- check for 0 percent interest
8722      -- this is the pay in arrears formula
8723 
8724      if p_ending_balance = 0 then
8725 
8726         if p_pay_in_arrears then
8727             if p_periodic_rate <> 0 then
8728                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 1');
8729                 l_numerator := p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount;
8730                 l_denominator :=  Power ((1 + p_periodic_rate), l_num_intervals) - 1;
8731             else
8732                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 2');
8733                 l_numerator := Power (1, l_num_intervals) * p_loan_amount;
8734                 l_denominator := l_num_intervals;
8735             end if;
8736         else
8737             if p_periodic_rate <> 0 then
8738                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 3');
8739                 l_numerator := p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount;
8740                 l_denominator :=  Power ((1 + p_periodic_rate), l_num_intervals) - 1;
8741             else
8742                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 4');
8743                 l_numerator := Power (1, l_num_intervals - 1) * p_loan_amount;
8744                 l_denominator := l_num_intervals;
8745             end if;
8746 
8747         end if;
8748 
8749         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': numerator:' || l_numerator);
8750         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': denominator:' || l_denominator);
8751 
8752         l_periodic_amount := l_numerator / l_denominator;
8753 
8754      else -- for case of balloon payment
8755 
8756         if p_pay_in_arrears then
8757             if p_periodic_rate <> 0 then
8758 
8759                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 5');
8760                 l_periodic_amount := ( (p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount) / (Power ((1 + p_periodic_rate), l_num_intervals) - 1) ) +
8761                                     ( (p_periodic_rate * p_ending_balance) / ((1 + p_periodic_rate) - Power ((1 + p_periodic_rate), l_num_intervals + 1)) );
8762 
8763             else
8764                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 6');
8765                 l_periodic_amount := ( (Power ((1 + p_periodic_rate), l_num_intervals) * p_loan_amount) / l_num_intervals ) -
8766                                     ( p_ending_balance / l_num_intervals );
8767             end if;
8768 
8769         else
8770             if p_periodic_rate <> 0 then
8771                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 7');
8772                 l_periodic_amount := ( (p_periodic_rate * Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount) / (Power ((1 + p_periodic_rate), l_num_intervals) - 1) ) +
8773                                     ( (p_periodic_rate * p_ending_balance) / ((1 + p_periodic_rate) - Power ((1 + p_periodic_rate), l_num_intervals + 1)) );
8774             else
8775                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': if 8');
8776                 l_periodic_amount := ( (Power ((1 + p_periodic_rate), l_num_intervals - 1) * p_loan_amount) / l_num_intervals ) -
8777                                     ( p_ending_balance / l_num_intervals );
8778             end if;
8779 
8780         end if;
8781 
8782      end if;
8783 
8784      logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': periodic_amount: ' || l_periodic_amount);
8785      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8786 
8787      return l_periodic_amount;
8788 
8789 Exception
8790     When others then
8791         null;
8792 
8793 end calculatePayment;
8794 
8795 /*=========================================================================
8796 || PUBLIC PROCEDURE calculateInterest
8797 ||
8798 || DESCRIPTION
8799 ||
8800 || Overview:  returns an interest due on a loan
8801 ||            we will use the formula:
8802 ||                    FV = P*r^n
8803 ||            where FV = future value at a given point in time
8804 ||                  PV = Present value of loan / capital
8805 ||                  r = rate annualized
8806 ||                  n = period of payment
8807 ||            to compound interest continually we use the formula:
8808 ||                    FV   =   Pe^(Yr)
8809 ||            where Y = years and
8810 ||                  e = 2.71828....
8811 ||
8812 || PSEUDO CODE/LOGIC
8813 ||
8814 || PARAMETERS
8815 ||
8816 || Parameter: p_amount = amount of loan
8817 ||            p_annual_rate = interest rate for loan expressed as a whole number
8818 ||            p_start_date = date at which interest is calculated
8819 ||            p_end_date = date at which interest in ended
8820 ||            p_compounding_period = for future use
8821 ||
8822 || Return value: amount interest due
8823 ||
8824 || Source Tables:  NA
8825 ||
8826 || Target Tables:  NA
8827 ||
8828 || KNOWN ISSUES
8829 ||
8830 || NOTES
8831 ||
8832 || MODIFICATION HISTORY
8833 || Date                  Author            Description of Changes
8834 || 12/08/2003 10:56AM     raverma           Created
8835 || 03/17/2004             raverma           don't allow negative interest for now
8836  *=======================================================================*/
8837 function calculateInterest(p_amount             in  number
8838                           ,p_periodic_rate      in number
8839                           ,p_compounding_period in varchar2)  return number
8840 is
8841    l_periodic_rate number;
8842    l_amount        number;
8843    l_api_name      varchar2(25);
8844 
8845 begin
8846 
8847    l_api_name  := 'calculateInterest';
8848     -- logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8849     if p_amount > 0  then
8850        l_amount := p_amount;
8851     else
8852        l_amount := 0;
8853     end if;
8854     --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8855 
8856     return l_amount * p_periodic_rate;
8857 
8858 end calculateInterest;
8859 
8860 
8861 
8862 
8863 
8864 procedure validatePayoff(p_loan_details   in LNS_FINANCIALS.LOAN_DETAILS_REC
8865                         ,p_payoff_date    in date
8866                         ,p_reason         in VARCHAR2
8867                         ,x_return_status  OUT NOCOPY VARCHAR2
8868                         ,x_msg_count      OUT NOCOPY NUMBER
8869                         ,x_msg_data       OUT NOCOPY VARCHAR2)
8870 is
8871      l_api_name            varchar2(25);
8872      l_api_version_number  number;
8873      l_return_status       VARCHAR2(1);
8874      l_msg_count           NUMBER;
8875      l_msg_data            VARCHAR2(32767);
8876 
8877 begin
8878 
8879     -- Initialize API return status to SUCCESS
8880     x_return_status := FND_API.G_RET_STS_SUCCESS;
8881     l_api_name      := 'validatePayoff';
8882     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
8883     --
8884     -- Api body
8885     -- --------------------------------------------------------------------
8886 
8887 
8888     -- these dates should be further restricted
8889     if p_loan_details.loan_status = 'PAIDOFF' then
8890         FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_ALREADY');
8891         FND_MSG_PUB.Add;
8892         RAISE FND_API.G_EXC_ERROR;
8893 
8894     --karamach --Bug5295446 --Need to prevent payoff for loans in Approved status as well
8895     --elsif p_loan_details.loan_status = 'INCOMPLETE' or p_loan_details.loan_status = 'DELETED' or
8896      --     p_loan_details.loan_status = 'REJECTED' or p_loan_details.loan_status = 'PENDING' then
8897     elsif p_loan_details.loan_status IN ('INCOMPLETE','DELETED','REJECTED','PENDING') then
8898         FND_MESSAGE.Set_Name('LNS', 'LNS_INVOICE_SUMMARY_ERROR');
8899         FND_MSG_PUB.Add;
8900         RAISE FND_API.G_EXC_ERROR;
8901     end if;
8902 
8903     if p_payoff_date < p_loan_details.last_interest_accrual  then
8904         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff too early');
8905         FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_TOO_EARLY');
8906         FND_MESSAGE.SET_TOKEN('PAYOFF_DATE', fnd_date.date_to_displaydate(p_loan_details.last_interest_accrual));
8907         FND_MSG_PUB.Add;
8908         RAISE FND_API.G_EXC_ERROR;
8909     end if;
8910 
8911     if p_payoff_date < p_loan_details.last_activity_date then
8912         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff too early');
8913         FND_MESSAGE.Set_Name('LNS', 'LNS_PAYOFF_TOO_EARLY2');
8914         FND_MESSAGE.SET_TOKEN('PARAMETER', 'LAST_ACTIVITY_DATE');
8915         FND_MESSAGE.SET_TOKEN('VALUE', fnd_date.date_to_displaydate(p_loan_details.last_activity_date));
8916         FND_MSG_PUB.Add;
8917         RAISE FND_API.G_EXC_ERROR;
8918     end if;
8919 
8920     if p_reason = 'PAYOFF' then
8921         /* raverma added 12-08-05 */
8922         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - calling LNS_FUNDING_PUB.validate_disb_for_payoff returns ');
8923         LNS_FUNDING_PUB.VALIDATE_DISB_FOR_PAYOFF(P_API_VERSION      => 1.0
8924                                                 ,P_INIT_MSG_LIST    => FND_API.G_FALSE
8925                                                 ,P_COMMIT           => FND_API.G_FALSE
8926                                                 ,P_VALIDATION_LEVEL => 100
8927                                                 ,P_LOAN_ID          => p_loan_details.loan_id
8928                                                 ,x_return_status    => l_return_status
8929                                                 ,x_msg_count        => l_msg_count
8930                                                 ,x_msg_data         => l_msg_data);
8931         if l_return_Status <> FND_API.G_RET_STS_SUCCESS then
8932             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - validate_disb_for_payoff returns ' || l_return_Status);
8933             RAISE FND_API.G_EXC_ERROR;
8934         end if;
8935     end if;
8936 
8937     x_return_status := l_return_Status;
8938     -- --------------------------------------------------------------------
8939     -- End of API body
8940     --
8941 
8942     FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
8943 
8944     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
8945 
8946   exception
8947 
8948         WHEN FND_API.G_EXC_ERROR THEN
8949               x_return_status := FND_API.G_RET_STS_ERROR;
8950               x_msg_count := l_msg_count;
8951               x_msg_data  := l_msg_data;
8952               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8953               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8954 
8955          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
8956               x_return_status := FND_API.G_RET_STS_ERROR;
8957               x_msg_count := l_msg_count;
8958               x_msg_data  := l_msg_data;
8959               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8960               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8961 
8962         WHEN OTHERS THEN
8963               x_return_status := FND_API.G_RET_STS_ERROR;
8964               x_msg_count := l_msg_count;
8965               x_msg_data  := l_msg_data;
8966               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
8967               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
8968 
8969 end;
8970 
8971 
8972 
8973 /*=========================================================================
8974 || PUBLIC FUNCTION validatePayoff
8975 ||
8976 || DESCRIPTION
8977 ||      contains validation rules on dates and statuses for a payoff
8978 ||
8979 || PSEUDO CODE/LOGIC
8980 ||
8981 || PARAMETERS
8982 ||
8983 || Return value:
8984 ||
8985 || Source Tables: NA
8986 ||
8987 || Target Tables: NA
8988 ||
8989 || KNOWN ISSUES
8990 ||
8991 || NOTES
8992 ||
8993 ||
8994 || MODIFICATION HISTORY
8995 || Date                  Author            Description of Changes
8996 || 10/26/2004 12:55PM       raverma           Created
8997  *=======================================================================*/
8998 procedure validatePayoff(p_loan_details   in LNS_FINANCIALS.LOAN_DETAILS_REC
8999                         ,p_payoff_date    in date
9000                         ,x_return_status  OUT NOCOPY VARCHAR2
9001                         ,x_msg_count      OUT NOCOPY NUMBER
9002                         ,x_msg_data       OUT NOCOPY VARCHAR2)
9003 is
9004 
9005 begin
9006 
9007     lns_financials.validatePayoff(p_loan_details   => p_loan_details
9008                                  ,p_payoff_date    => p_payoff_date
9009                                  ,p_reason         => 'PAYOFF'
9010                                  ,x_return_status  => x_return_status
9011                                  ,x_msg_count      => x_msg_count
9012                                  ,x_msg_data       => x_msg_data);
9013 
9014 end;
9015 
9016 
9017 
9018 
9019 procedure calcLoanRemainingAmounts(p_api_version    IN NUMBER
9020                          ,p_init_msg_list  IN VARCHAR2
9021                          ,p_loan_id        in number
9022                          ,p_date           in date
9023                          ,p_reason         in varchar2
9024                          ,x_payoff_tbl     OUT NOCOPY LNS_FINANCIALS.PAYOFF_TBL2
9025                          ,x_return_status  OUT NOCOPY VARCHAR2
9026                          ,x_msg_count      OUT NOCOPY NUMBER
9027                          ,x_msg_data       OUT NOCOPY VARCHAR2)
9028 IS
9029 
9030      l_api_name            varchar2(25);
9031      l_api_version_number  number;
9032      l_return_status       VARCHAR2(1);
9033      l_msg_count           NUMBER;
9034      l_msg_data            VARCHAR2(32767);
9035 
9036      l_loan_details        LNS_FINANCIALS.LOAN_DETAILS_REC;
9037      l_rate_tbl            LNS_FINANCIALS.RATE_SCHEDULE_TBL;
9038      l_annualized_rate     number;
9039      l_periodic_rate       number;
9040      l_additional_interest number;
9041      l_additional_fees     number;
9042      l_payoff_tbl          LNS_FINANCIALS.PAYOFF_TBL2;
9043      l_principal_unpaid    number;
9044      l_interest_unpaid     number;
9045      l_fees_unpaid         number;
9046      l_payoff_date         date;
9047      l_from_date           date;
9048      l_to_date             date;
9049      l_multipler           number;
9050      l_balance             number;
9051      l_current_phase       varchar2(30);
9052      l_rate_type           varchar2(30);
9053      l_index_rate_id       number;
9054      l_norm_interest         number;
9055      l_add_prin_interest     number;
9056      l_add_int_interest      number;
9057      l_penal_prin_interest   number;
9058      l_penal_int_interest    number;
9059      l_penal_interest        number;
9060      l_add_start_date        date;
9061      l_add_end_date          date;
9062      l_prev_deferred_int     number;
9063      l_prev_cap_int          number;
9064      l_previous_annualized   number;
9065      l_early_pay_cr          number;
9066 
9067      l_norm_int_detail_str            varchar2(2000);
9068      l_add_prin_int_detail_str        varchar2(2000);
9069      l_add_int_int_detail_str         varchar2(2000);
9070      l_penal_prin_int_detail_str      varchar2(2000);
9071      l_penal_int_int_detail_str       varchar2(2000);
9072      l_penal_int_detail_str           varchar2(2000);
9073      l_early_pay_cr_detail_str        varchar2(2000);
9074 
9075      l_fee_basis_tbl         LNS_FEE_ENGINE.FEE_BASIS_TBL;
9076      l_fee_structures        LNS_FEE_ENGINE.FEE_STRUCTURE_TBL;
9077      l_fees_tbl              LNS_FEE_ENGINE.FEE_CALC_TBL;
9078      l_rate_details          LNS_FINANCIALS.INTEREST_RATE_REC;
9079 
9080      cursor c_additional_fees(p_loan_id number, p_phase varchar2, p_installment number) is
9081      select nvl(sum(sched.fee_amount), 0)
9082        from lns_fee_schedules sched
9083             ,lns_fees fees
9084       where sched.loan_id = p_loan_id
9085         and sched.fee_id = fees.fee_id
9086         and sched.active_flag = 'Y'
9087         and sched.billed_flag = 'N'
9088         and sched.phase = p_phase
9089         and sched.fee_installment <= decode(p_installment, -1, 1, (p_installment+1))
9090         and fees.fee_category <> 'RECUR';
9091 
9092      cursor c_loan_info(p_loan_id number) is
9093      select nvl(h.current_phase, 'TERM')
9094       from lns_loan_headers h
9095       where h.loan_id = p_loan_id;
9096 
9097     cursor c_get_last_bill_date(p_loan_id number, p_installment_number number)  is
9098         select ACTIVITY_DATE
9099         from LNS_PRIN_TRX_ACTIVITIES_V
9100         where loan_id = p_loan_id
9101         and PAYMENT_NUMBER = p_installment_number
9102         and PARENT_AMORTIZATION_ID is null
9103         and ACTIVITY_CODE in ('BILLING', 'START');
9104 
9105     cursor c_get_def_cap_amounts(p_loan_id number, p_installment_number number)  is
9106         select nvl(DEFERRED_INT_AMOUNT, 0), nvl(CAP_INT_AMOUNT, 0)
9107         from LNS_AMORTIZATION_SCHEDS
9108         where loan_id = p_loan_id
9109         and PAYMENT_NUMBER = p_installment_number
9110         and (REVERSED_FLAG is null or REVERSED_FLAG = 'N')
9111         and PARENT_AMORTIZATION_ID is null
9112         and nvl(PHASE, 'TERM') = 'TERM';
9113 
9114 begin
9115 
9116     l_api_name            := 'calcLoanRemainingAmounts';
9117     l_api_version_number  := 1;
9118     l_additional_interest := 0;
9119     l_additional_fees     := 0;
9120     l_principal_unpaid    := 0;
9121     l_interest_unpaid     := 0;
9122     l_fees_unpaid         := 0;
9123     l_balance             := 0;
9124     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9125     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id ' || p_loan_id);
9126     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_date ' || p_date);
9127     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_reason ' || p_reason);
9128 
9129     -- Standard Start of API savepoint
9130     SAVEPOINT calculatePayoff;
9131 
9132     -- Standard call to check for call compatibility.
9133     IF NOT FND_API.Compatible_API_Call (l_api_version_number, p_api_version,
9134                                         l_api_name, G_PKG_NAME)
9135     THEN
9136         RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
9137     END IF;
9138 
9139     -- Initialize message list IF p_init_msg_list is set to TRUE.
9140     IF FND_API.to_Boolean(p_init_msg_list) THEN
9141         FND_MSG_PUB.initialize;
9142     END IF;
9143 
9144     -- Initialize API return status to SUCCESS
9145     x_return_status := FND_API.G_RET_STS_SUCCESS;
9146 
9147     --
9148     -- Api body
9149     -- --------------------------------------------------------------------
9150 
9151     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting current phase');
9152     open c_loan_info(p_loan_id);
9153     fetch c_loan_info into l_current_phase;
9154     close c_loan_info;
9155     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - current phase ' || l_current_phase);
9156 
9157     l_loan_details  := lns_financials.getLoanDetails(p_loan_id        => p_loan_id
9158                                                     ,p_based_on_terms => 'CURRENT'
9159                                                     ,p_phase          => l_current_phase);
9160     l_rate_tbl      := lns_financials.getRateSchedule(p_loan_id, l_current_phase);
9161     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - got loan details and rate info');
9162 
9163     lns_financials.validatePayoff(p_loan_details   => l_loan_details
9164                                  ,p_payoff_date    => p_date
9165                                  ,p_reason         => p_reason
9166                                  ,x_return_status  => l_return_status
9167                                  ,x_msg_count      => l_msg_count
9168                                  ,x_msg_data       => l_msg_data);
9169     IF l_return_status <> FND_API.G_RET_STS_SUCCESS THEN
9170         LogMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, l_api_name || FND_MSG_PUB.Get(p_encoded => 'F'));
9171         RAISE FND_API.G_EXC_ERROR;
9172     END IF;
9173 
9174     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - processing late fees');
9175     lns_fee_engine.processLateFees(p_loan_id       => p_loan_id
9176                                   ,p_init_msg_list => p_init_msg_list
9177                                   ,p_commit        => 'F'
9178                                   ,p_phase         => l_loan_details.LOAN_PHASE
9179                                   ,x_return_status => l_return_status
9180                                   ,x_msg_count     => l_msg_count
9181                                   ,x_msg_data      => l_msg_data);
9182 
9183     if p_reason = 'PAYOFF' then
9184         -- fix for bug 9795950: adding payoff fees to payoff process
9185         l_fee_structures(1).fee_category := 'EVENT';
9186         l_fee_structures(1).fee_type     := 'EVENT_PAYOFF';
9187         l_fee_structures(1).phase        := l_loan_details.LOAN_PHASE;
9188 
9189         -- filling out basis table
9190         l_fee_basis_tbl(1).fee_basis_name   := 'TOTAL_BAL';
9191         l_fee_basis_tbl(1).fee_basis_amount := l_loan_details.remaining_balance;
9192         l_fee_basis_tbl(2).fee_basis_name   := 'ORIG_LOAN';
9193         l_fee_basis_tbl(2).fee_basis_amount := l_loan_details.requested_amount;
9194         l_fee_basis_tbl(3).fee_basis_name   := 'TOTAL_DISB_AMT';
9195         l_fee_basis_tbl(3).fee_basis_amount := l_loan_details.funded_amount;
9196         l_fee_basis_tbl(4).fee_basis_name   := 'OVERDUE_PRIN';
9197         l_fee_basis_tbl(4).fee_basis_amount := l_loan_details.unpaid_principal;
9198         l_fee_basis_tbl(5).fee_basis_name   := 'OVERDUE_PRIN_INT';
9199         l_fee_basis_tbl(5).fee_basis_amount := l_loan_details.unpaid_principal + l_loan_details.UNPAID_INTEREST;
9200         l_fee_basis_tbl(6).fee_basis_name   := 'CURR_LOAN';
9201         l_fee_basis_tbl(6).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT;
9202         l_fee_basis_tbl(7).fee_basis_name   := 'TOTAL_UNDISB_AMT';
9203         l_fee_basis_tbl(7).fee_basis_amount := l_loan_details.requested_amount + l_loan_details.ADD_REQUESTED_AMOUNT - l_loan_details.funded_amount;
9204         l_fee_basis_tbl(8).fee_basis_name   := 'OVERDUE_INT';
9205         l_fee_basis_tbl(8).fee_basis_amount := l_loan_details.UNPAID_INTEREST;
9206 
9207         lns_fee_engine.processFees(p_init_msg_list      => FND_API.G_FALSE
9208                                 ,p_commit             => FND_API.G_FALSE
9209                                 ,p_loan_id            => p_loan_id
9210                                 ,p_installment_number => -1
9211                                 ,p_fee_basis_tbl      => l_fee_basis_tbl
9212                                 ,p_fee_structures     => l_fee_structures
9213                                 ,x_fees_tbl           => l_fees_tbl
9214                                 ,x_return_status      => l_return_Status
9215                                 ,x_msg_count          => l_msg_count
9216                                 ,x_msg_data           => l_msg_data);
9217 
9218         if l_return_status <> FND_API.G_RET_STS_SUCCESS then
9219             FND_MESSAGE.SET_NAME('LNS', 'LNS_PROCESS_FEE_ERROR');
9220             FND_MSG_PUB.ADD;
9221             RAISE FND_API.G_EXC_ERROR;
9222         end if;
9223     end if;
9224 
9225     if p_date < l_loan_details.last_interest_accrual  then
9226         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff prior to last interest accrual');
9227         -- we will have a interest credit
9228         l_from_date   := p_date;
9229         l_to_date     := l_loan_details.last_interest_accrual;
9230         l_multipler   := -1;
9231 /*
9232         l_balance := lns_financials.getAverageDailyBalance(p_loan_id     => p_loan_id
9233                                                           ,p_term_id     => null
9234                                                           ,p_from_date   => p_date
9235                                                           ,p_to_date     => l_loan_details.last_interest_accrual
9236                                                           ,p_calc_method => null);
9237 */
9238     else
9239         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - payoff after lastinterest accrual');
9240         l_from_date   := l_loan_details.last_interest_accrual;
9241         l_to_date     := p_date;
9242         l_multipler   := 1;
9243 --        l_balance     := l_loan_details.remaining_balance;
9244     end if;
9245 --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - computed principal balance: ' || l_balance);
9246     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - from date: ' || l_from_date);
9247     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - to date: ' || l_to_date);
9248     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_muliplier: ' || l_multipler);
9249 
9250     BEGIN
9251         -- changes as per scherkas 11-16-2005
9252         select
9253               nvl(sum(SCHED.PRINCIPAL_REMAINING),0)
9254              ,nvl(sum(SCHED.INTEREST_REMAINING),0)
9255              ,nvl(sum(SCHED.FEE_REMAINING),0)
9256         into  l_principal_unpaid
9257              ,l_interest_unpaid
9258              ,l_fees_unpaid
9259         from LNS_AM_SCHEDS_V SCHED
9260               ,LNS_LOAN_HEADERS H
9261         where H.loan_id = p_loan_id and
9262               H.loan_id = Sched.loan_id and
9263               SCHED.reversed_code = 'N' and
9264               nvl(sched.phase, 'TERM') = nvl(h.current_phase, 'TERM');
9265     Exception
9266         when no_data_found then
9267             null;
9268     END;
9269     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_principal_unpaid: ' || l_principal_unpaid);
9270     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_interest_unpaid: ' || l_interest_unpaid);
9271     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_fees_unpaid: ' || l_fees_unpaid);
9272     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - status: ' || l_loan_details.loan_status);
9273 
9274     -- get the wtd rate if necessary
9275     if l_rate_tbl.count = 1 then
9276         l_annualized_rate := l_rate_tbl(1).annual_rate;
9277     else
9278         l_annualized_rate := lns_financials.getWeightedRate(p_loan_details => l_loan_details
9279                                                         ,p_start_date   => l_from_date
9280                                                         ,p_end_date     => l_to_date
9281                                                         ,p_rate_tbl     => l_rate_tbl);
9282     end if;
9283     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_annualized_rate: ' || l_annualized_rate);
9284 
9285     l_norm_interest := 0;
9286     l_add_prin_interest := 0;
9287     l_add_int_interest := 0;
9288     l_penal_prin_interest := 0;
9289     l_penal_int_interest := 0;
9290     l_penal_interest := 0;
9291     l_norm_int_detail_str := null;
9292     l_add_prin_int_detail_str := null;
9293     l_add_int_int_detail_str := null;
9294     l_penal_prin_int_detail_str := null;
9295     l_penal_int_int_detail_str := null;
9296     l_penal_int_detail_str := null;
9297 
9298     -- get additional interest start date
9299     open c_get_last_bill_date(p_loan_id, l_loan_details.last_installment_billed);
9300     fetch c_get_last_bill_date into l_add_start_date;
9301     close c_get_last_bill_date;
9302 
9303     -- get additional interest end date
9304     if trunc(l_add_start_date) > trunc(l_from_date) then
9305         l_add_start_date := l_from_date;
9306     end if;
9307     l_add_end_date := l_to_date;
9308 
9309     -- get previously deferred interest
9310     open c_get_def_cap_amounts(p_loan_id, l_loan_details.last_installment_billed);
9311     fetch c_get_def_cap_amounts into l_prev_deferred_int, l_prev_cap_int;
9312     close c_get_def_cap_amounts;
9313     if l_prev_deferred_int is null then
9314         l_prev_deferred_int := 0;
9315     end if;
9316     if l_prev_cap_int is null then
9317         l_prev_cap_int := 0;
9318     end if;
9319     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_deferred_int = ' || l_prev_deferred_int);
9320     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_prev_cap_int = ' || l_prev_cap_int);
9321 
9322     -- calculate normal interest
9323     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating normal interest...');
9324     LNS_FINANCIALS.CALC_NORM_INTEREST(p_loan_id => p_loan_id,
9325                         p_calc_method => l_loan_details.CALCULATION_METHOD,
9326                         p_period_start_date => l_from_date,
9327                         p_period_end_date => l_to_date,
9328                         p_interest_rate => l_annualized_rate,
9329                         p_day_count_method => l_loan_details.day_count_method,
9330                         p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9331                         p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9332                         p_adj_amount => 0,
9333                         p_CAP_AMOUNT => l_prev_cap_int,
9334                         x_norm_interest => l_norm_interest,
9335                         x_norm_int_details => l_norm_int_detail_str);
9336 
9337     l_norm_interest  := round(l_norm_interest, l_loan_details.currency_precision);
9338 
9339     -- calculate additional interest on unpaid principal
9340     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid principal...');
9341     LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => p_loan_id,
9342                         p_calc_method => l_loan_details.CALCULATION_METHOD,
9343                         p_period_start_date => l_add_start_date,
9344                         p_period_end_date => l_add_end_date,
9345                         p_interest_rate => l_annualized_rate,
9346                         p_day_count_method => l_loan_details.day_count_method,
9347                         p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9348                         p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9349                         p_penal_int_rate => l_loan_details.PENAL_INT_RATE,
9350                         p_prev_grace_end_date => l_from_date,
9351                         p_grace_start_date => l_from_date,
9352                         p_grace_end_date => (l_from_date + l_loan_details.PENAL_INT_GRACE_DAYS),
9353                         p_target => 'UNPAID_PRIN',
9354                         x_add_interest => l_add_prin_interest,
9355                         x_penal_interest => l_penal_prin_interest,
9356                         x_add_int_details => l_add_prin_int_detail_str,
9357                         x_penal_int_details => l_penal_prin_int_detail_str);
9358     l_add_prin_interest  := round(l_add_prin_interest, l_loan_details.currency_precision);
9359 
9360     -- calculate additional interest on unpaid interest
9361     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating additional interest on unpaid interest...');
9362     LNS_FINANCIALS.CALC_ADD_INTEREST(p_loan_id => p_loan_id,
9363                         p_calc_method => l_loan_details.CALCULATION_METHOD,
9364                         p_period_start_date => l_add_start_date,
9365                         p_period_end_date => l_add_end_date,
9366                         p_interest_rate => l_annualized_rate,
9367                         p_day_count_method => l_loan_details.day_count_method,
9368                         p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9369                         p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9370                         p_penal_int_rate => l_loan_details.PENAL_INT_RATE,
9371                         p_prev_grace_end_date => l_from_date,
9372                         p_grace_start_date => l_from_date,
9373                         p_grace_end_date => (l_from_date + l_loan_details.PENAL_INT_GRACE_DAYS),
9374                         p_target => 'UNPAID_INT',
9375                         x_add_interest => l_add_int_interest,
9376                         x_penal_interest => l_penal_int_interest,
9377                         x_add_int_details => l_add_int_int_detail_str,
9378                         x_penal_int_details => l_penal_int_int_detail_str);
9379     l_add_int_interest  := round(l_add_int_interest, l_loan_details.currency_precision);
9380 
9381     l_rate_details := getRateDetails(p_installment => (l_loan_details.last_installment_billed + 1)
9382                                     ,p_rate_tbl    => l_rate_tbl);
9383     l_previous_annualized := l_rate_details.annual_rate;
9384 
9385     -- calculate interest credit on early payment
9386     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculating early payment credit amount...');
9387     LNS_FINANCIALS.CALC_EARLY_PAY_CR(p_loan_id => p_loan_id,
9388                         p_calc_method => l_loan_details.CALCULATION_METHOD,
9389                         p_installment => (l_loan_details.last_installment_billed + 1),
9390                         p_interest_rate => l_previous_annualized,
9391                         p_day_count_method => l_loan_details.day_count_method,
9392                         p_payment_freq => l_loan_details.PAYMENT_FREQUENCY,
9393                         p_compound_freq => l_loan_details.INTEREST_COMPOUNDING_FREQ,
9394                         x_early_pay_cr => l_early_pay_cr,
9395                         x_EARLY_PAY_CR_DETAILS => l_early_pay_cr_detail_str);
9396 
9397     l_penal_interest := round(l_penal_prin_interest + l_penal_int_interest, l_loan_details.currency_precision);
9398     l_additional_interest := (l_prev_deferred_int + l_prev_cap_int + l_norm_interest + l_add_prin_interest +
9399         l_add_int_interest + l_penal_interest - l_early_pay_cr) * l_multipler;
9400     if l_penal_prin_int_detail_str is not null and l_penal_int_int_detail_str is not null then
9401         l_penal_int_detail_str := l_penal_prin_int_detail_str || ' +<br>' || l_penal_int_int_detail_str;
9402     else
9403         l_penal_int_detail_str := l_penal_prin_int_detail_str || l_penal_int_int_detail_str;
9404     end if;
9405     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_additional_interest: ' || l_additional_interest);
9406 
9407     begin
9408         open c_additional_fees(p_loan_id, l_current_phase, l_loan_details.last_installment_billed);
9409         fetch c_additional_fees into l_additional_fees;
9410         close c_additional_fees;
9411     exception when no_data_found then
9412         null;
9413     end;
9414 
9415     l_payoff_tbl(1).PAYOFF_PURPOSE  := 'PRIN';
9416     l_payoff_tbl(1).BILLED_AMOUNT   := l_principal_unpaid;
9417     l_payoff_tbl(1).UNBILLED_AMOUNT := l_loan_details.remaining_balance - l_principal_unpaid;
9418     l_payoff_tbl(1).TOTAL_AMOUNT    := l_loan_details.remaining_balance;
9419 
9420     l_payoff_tbl(2).PAYOFF_PURPOSE  := 'INT';
9421     l_payoff_tbl(2).BILLED_AMOUNT   := l_interest_unpaid;
9422     l_payoff_tbl(2).UNBILLED_AMOUNT := l_additional_interest;
9423     l_payoff_tbl(2).TOTAL_AMOUNT    := l_additional_interest + l_interest_unpaid;
9424 
9425     l_payoff_tbl(3).PAYOFF_PURPOSE  := 'FEE';
9426     l_payoff_tbl(3).BILLED_AMOUNT   := l_fees_unpaid;
9427     l_payoff_tbl(3).UNBILLED_AMOUNT := l_additional_fees;
9428     l_payoff_tbl(3).TOTAL_AMOUNT    := l_fees_unpaid + l_additional_fees;
9429 
9430     x_payoff_tbl := l_payoff_tbl;
9431 
9432     -- --------------------------------------------------------------------
9433     -- End of API body
9434     --
9435 
9436     FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data  => x_msg_data);
9437 
9438     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9439 
9440     EXCEPTION
9441         WHEN FND_API.G_EXC_ERROR THEN
9442               ROLLBACK TO calculatePayoff;
9443               x_return_status := FND_API.G_RET_STS_ERROR;
9444               x_msg_count := l_msg_count;
9445               x_msg_data  := l_msg_data;
9446               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9447               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
9448 
9449          WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
9450               ROLLBACK TO calculatePayoff;
9451               x_return_status := FND_API.G_RET_STS_ERROR;
9452               x_msg_count := l_msg_count;
9453               x_msg_data  := l_msg_data;
9454               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9455               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
9456 
9457         WHEN OTHERS THEN
9458               ROLLBACK TO calculatePayoff;
9459               x_return_status := FND_API.G_RET_STS_ERROR;
9460               x_msg_count := l_msg_count;
9461               x_msg_data  := l_msg_data;
9462               FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
9463               logMessage(FND_LOG.LEVEL_ERROR, G_PKG_NAME, sqlerrm);
9464 
9465 end;
9466 
9467 
9468 
9469 /*=========================================================================
9470 || PUBLIC FUNCTION calculatePayoff
9471 ||
9472 || DESCRIPTION
9473 ||      calculate any additional interest due on loan, etc fees, to
9474 ||      pay off
9475 ||
9476 || PSEUDO CODE/LOGIC
9477 ||     1. get number of interest rates running over remaining period
9478 ||     2. get weighted average of those rates
9479 ||     3. calculate interest due on remaining principal
9480 ||         from payoff_date
9481 ||
9482 || PARAMETERS
9483 ||    p_loan_id     => loan_id to payoff
9484 ||    p_payoff_date => date at which to payoff the loan
9485 ||
9486 || Return value:
9487 ||
9488 || Source Tables: NA
9489 ||
9490 || Target Tables: NA
9491 ||
9492 || KNOWN ISSUES
9493 ||
9494 || NOTES
9495 ||
9496 ||
9497 || MODIFICATION HISTORY
9498 || Date                  Author            Description of Changes
9499 || 03/24/2004 12:55PM       raverma           Created
9500 || 04/15/2004               raverma           check to see if loan is PAIDOFF
9501  *=======================================================================*/
9502 procedure calculatePayoff(p_api_version    IN NUMBER
9503                          ,p_init_msg_list  IN VARCHAR2
9504                          ,p_loan_id        in number
9505                          ,p_payoff_date    in date
9506                          ,x_payoff_tbl     OUT NOCOPY LNS_FINANCIALS.PAYOFF_TBL2
9507                          ,x_return_status  OUT NOCOPY VARCHAR2
9508                          ,x_msg_count      OUT NOCOPY NUMBER
9509                          ,x_msg_data       OUT NOCOPY VARCHAR2)
9510 IS
9511     l_payoff_tbl            LNS_FINANCIALS.PAYOFF_TBL2;
9512 begin
9513 
9514     calcLoanRemainingAmounts(p_api_version    => 1.0
9515                             ,p_init_msg_list  => p_init_msg_list
9516                             ,p_loan_id        => p_loan_id
9517                             ,p_date           => p_payoff_date
9518                             ,p_reason         => 'PAYOFF'
9519                             ,x_payoff_tbl     => l_payoff_tbl
9520                             ,x_return_status  => x_return_status
9521                             ,x_msg_count      => x_msg_count
9522                             ,x_msg_data       => x_msg_data);
9523 
9524     x_payoff_tbl := l_payoff_tbl;
9525 
9526 end;
9527 
9528 
9529 
9530 -- Introduced to fix bug 7565117
9531 procedure get_factors(p_frequency in varchar2,
9532                        p_days_in_year in number,
9533                        x_ppy in out nocopy number,
9534                        x_days_in_period in out nocopy number)
9535 is
9536     l_days_in_year      number;
9537 begin
9538 
9539     if p_frequency = 'DAILY' then
9540         x_ppy := p_days_in_year;
9541     elsif p_frequency = 'WEEKLY' then
9542         x_ppy := 52;
9543     elsif p_frequency = 'BIWEEKLY' then
9544         x_ppy := 26;
9545     elsif p_frequency = 'SEMI-MONTHLY' then
9546         x_ppy := 24;
9547     elsif p_frequency = 'MONTHLY' then
9548         x_ppy := 12;
9549     elsif p_frequency = 'BI-MONTHLY' then
9550         x_ppy := 6;
9551     elsif p_frequency = 'QUARTERLY' then
9552         x_ppy := 4;
9553     elsif p_frequency = 'SEMI-ANNUALLY' then
9554         x_ppy := 2;
9555     elsif p_frequency = 'YEARLY' then
9556         x_ppy := 1;
9557     else
9558         FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_INTERVAL');
9559         FND_MESSAGE.SET_TOKEN('INTERVAL',p_frequency);
9560         FND_MSG_PUB.Add;
9561         RAISE FND_API.G_EXC_ERROR;
9562     end if;
9563 
9564     x_days_in_period := p_days_in_year/x_ppy;
9565     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_ppy = ' || x_ppy);
9566     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_days_in_period = ' || x_days_in_period);
9567 
9568 end;
9569 
9570 
9571 /*=========================================================================
9572 || PUBLIC PROCEDURE getCompoundPeriodicRate
9573 ||
9574 || DESCRIPTION
9575 ||
9576 || Overview:  this function will return the compound interest rate
9577 ||
9578 || Parameters:
9579 ||            p_compound_freq - mandatory; compounding frequency
9580 ||            p_payment_freq - mandatory; payment frequency
9581 ||            p_start_date - optional; start date of rate
9582 ||            p_end_date - optional; end date of rate
9583 ||            p_annualized rate  - mandatory; interest rate expressed as a WHOLE number
9584 ||            p_days_count_method - mandatory; day count method
9585 ||
9586 || Source Tables:  NA
9587 ||
9588 || Target Tables:  NA
9589 ||
9590 || Return value: compound periodic interest rate on the loan
9591 ||
9592  | KNOWN ISSUES
9593  |
9594  | NOTES
9595 ||
9596 || MODIFICATION HISTORY
9597 || Date                  Author            Description of Changes
9598 || 09/21/2007            scherkas           Created
9599 ||  4/08/2008            scherkas          Fix logic to work with any number of years between period_start_date and period_end_date
9600  *=======================================================================*/
9601 function getCompoundPeriodicRate(p_compound_freq in varchar2
9602                         ,p_payment_freq in varchar2
9603                         ,p_annualized_rate   in number
9604                         ,p_period_start_date in date
9605                         ,p_period_end_date   in date
9606                         ,p_days_count_method in varchar2
9607                         ,p_target in varchar2) return number
9608 is
9609     l_periodic_rate   number;
9610     l_day_count       number;
9611     l_days_in_year    number;
9612     l_api_name        varchar2(25);
9613     l_year1           number;
9614     l_year2           number;
9615     l_rate1           number;
9616     l_days_ratio      number;
9617     l_payments_per_year  number;
9618     l_compounds_per_year number;
9619     l_start_date      date;
9620     l_end_date        date;
9621     l_days_in_period  number;
9622     l_total_periodic_rate   number;
9623     l_avrg_days_in_years    number;
9624     l_years_count           number;
9625 
9626 begin
9627 
9628     l_api_name        := 'getCompoundPeriodicRate';
9629     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9630     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_compound_freq: ' || p_compound_freq);
9631     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_payment_freq: ' || p_payment_freq);
9632     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_annualized_rate: ' || p_annualized_rate);
9633     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_days_count_method: ' || p_days_count_method);
9634     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_period_start_date: ' || p_period_start_date);
9635     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_period_end_date: ' || p_period_end_date);
9636     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_target: ' || p_target);
9637 
9638     select to_number(to_char(p_period_start_date, 'YYYY')) into l_year1 from dual;
9639     select to_number(to_char(p_period_end_date, 'YYYY')) into l_year2 from dual;
9640 
9641     l_periodic_rate := 0;
9642     l_total_periodic_rate := 0;
9643 
9644     if p_target = 'INTEREST' then
9645 
9646         l_days_ratio := 0;
9647         l_avrg_days_in_years := 0;
9648         l_years_count := 0;
9649 
9650         for k in l_year1..l_year2 loop
9651 
9652             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ------ Calculating for year ' || k);
9653             l_periodic_rate := 0;
9654             l_rate1        := 0;
9655             l_day_count    := 0;
9656             l_days_in_year := 0;
9657 
9658             if k = l_year1 then
9659                 l_start_date := p_period_start_date;
9660             else
9661                 l_start_date := l_end_date;
9662             end if;
9663 
9664             if k = l_year2 then
9665                 l_end_date := p_period_end_date;
9666             else
9667                 l_end_date := to_date('01/01/' || to_char(k+1),'DD/MM/YYYY');
9668             end if;
9669 
9670             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_start_date = ' || l_start_date);
9671             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_date = ' || l_end_date);
9672 
9673             l_day_count := LNS_FIN_UTILS.getDayCount(p_start_date       => l_start_date
9674                                                     ,p_end_date         => l_end_date
9675                                                     ,p_day_count_method => p_days_count_method);
9676 
9677             l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year              => k
9678                                                     ,p_year_count_method => p_days_count_method);
9679 
9680             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_day_count = ' || l_day_count);
9681             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_days_in_year = ' || l_days_in_year);
9682 
9683             get_factors(p_frequency => p_compound_freq,
9684                         p_days_in_year => l_days_in_year,
9685                         x_ppy => l_compounds_per_year,
9686                         x_days_in_period => l_days_in_period);
9687             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compounds per year = ' || l_compounds_per_year);
9688 
9689             get_factors(p_frequency => p_payment_freq,
9690                         p_days_in_year => l_days_in_year,
9691                         x_ppy => l_payments_per_year,
9692                         x_days_in_period => l_days_in_period);
9693             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payments_per_year = ' || l_payments_per_year);
9694             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_days_in_period = ' || l_days_in_period);
9695 
9696             l_periodic_rate := l_day_count/l_days_in_period * (Power((1+((p_annualized_rate)/(100*l_compounds_per_year))),(l_compounds_per_year/l_payments_per_year))-1);
9697             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_periodic_rate = ' || l_periodic_rate);
9698 
9699             l_total_periodic_rate := l_total_periodic_rate + l_periodic_rate;
9700             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_total_periodic_rate = ' || l_total_periodic_rate);
9701 
9702         end loop;
9703 
9704     else
9705 
9706         l_avrg_days_in_years := 0;
9707         l_years_count := 0;
9708         for k in l_year1..l_year2 loop
9709 
9710             l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year              => k
9711                                                     ,p_year_count_method => p_days_count_method);
9712 
9713             l_avrg_days_in_years := l_avrg_days_in_years + l_days_in_year;
9714             l_years_count := l_years_count + 1;
9715 
9716         end loop;
9717 
9718         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_years_count = ' || l_years_count);
9719         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total number of days in all years = ' || l_avrg_days_in_years);
9720 
9721         l_avrg_days_in_years := l_avrg_days_in_years / l_years_count;
9722         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_avrg_days_in_years = ' || l_avrg_days_in_years);
9723 
9724         get_factors(p_frequency => p_payment_freq,
9725                     p_days_in_year => l_avrg_days_in_years,
9726                     x_ppy => l_payments_per_year,
9727                     x_days_in_period => l_days_in_period);
9728         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': avarage payments per year = ' || l_payments_per_year);
9729 
9730         get_factors(p_frequency => p_compound_freq,
9731                     p_days_in_year => l_avrg_days_in_years,
9732                     x_ppy => l_compounds_per_year,
9733                     x_days_in_period => l_days_in_period);
9734         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compounds per year = ' || l_compounds_per_year);
9735 
9736         l_total_periodic_rate := Power((1+((p_annualized_rate)/(100*l_compounds_per_year))),(l_compounds_per_year/l_payments_per_year))-1;
9737         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_total_periodic_rate = ' || l_total_periodic_rate);
9738 
9739     end if;
9740 
9741     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-------------');
9742     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Final Periodic rate ' || l_total_periodic_rate);
9743     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9744 
9745     return l_total_periodic_rate;
9746 
9747 end getCompoundPeriodicRate;
9748 
9749 
9750 /*=========================================================================
9751 || PUBLIC PROCEDURE getPeriodicRate
9752 ||
9753 || DESCRIPTION
9754 ||
9755 || Overview:  this function will return the interest rate for a given
9756 ||             period of time so the interest in a give month at
9757 ||             12% interest per year will return a 1% monthly rate
9758 ||              (30 /360 methodology)
9759 ||
9760 || Parameter: p_start_date optional start date of rate
9761 ||            p_end_date optional end date of rate
9762 ||            p_annualized rate = interest rate expressed as a WHOLE number
9763 ||            p_days_count_method = for future use
9764 ||
9765 || Source Tables:  NA
9766 ||
9767 || Target Tables:  NA
9768 ||
9769 || Return value: periodic interest rate on the loan
9770 ||
9771  | KNOWN ISSUES
9772  |
9773  | NOTES
9774 ||
9775 || MODIFICATION HISTORY
9776 || Date                  Author            Description of Changes
9777 || 12/09/2003 1:51PM     raverma           Created
9778 ||  2/26/2004            raverma           added more robust day / year counting methodolgy
9779 ||  7/22/2004            raverma           handle situation where start date = end date
9780 ||  3/22/2006            karamach          Fix date format issue for bug5112031
9781 ||  4/08/2008            scherkas          Fix logic to work with any number of years between period_start_date and period_end_date
9782  *=======================================================================*/
9783 function getPeriodicRate(p_payment_freq in varchar2
9784                         ,p_period_start_date in date
9785                         ,p_period_end_date   in date
9786                         ,p_annualized_rate   in number
9787                         ,p_days_count_method in varchar2
9788                         ,p_target            in varchar2) return number
9789 is
9790     l_annual_rate     number;
9791     l_periodic_rate   number;
9792     l_day_count       number;
9793     l_days_in_year    number;
9794     l_api_name        varchar2(25);
9795     l_year1           number;
9796     l_year2           number;
9797     l_periodic_factor number;
9798     l_rate1           number;
9799     l_rate2           number;
9800     l_start_date      date;
9801     l_end_date        date;
9802     l_avrg_days_in_years    number;
9803     l_years_count           number;
9804     l_payments_per_year     number;
9805     l_days_in_period  number;
9806 
9807 begin
9808 
9809     l_api_name        := 'getPeriodicRate';
9810     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9811     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_days_count_method);
9812     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': annualized rate: ' || p_annualized_rate);
9813     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
9814     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
9815     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': p_target: ' || p_target);
9816 
9817     l_annual_rate   := p_annualized_rate / 100;
9818     l_periodic_rate := 0;
9819 
9820     select to_number(to_char(p_period_start_date, 'YYYY')) into l_year1 from dual;
9821     select to_number(to_char(p_period_end_date, 'YYYY')) into l_year2 from dual;
9822 
9823     if p_target = 'INTEREST' then
9824 
9825         for k in l_year1..l_year2 loop
9826 
9827             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ' ------ Calculating for year ' || k);
9828             l_rate1        := 0;
9829             l_day_count    := 0;
9830             l_days_in_year := 0;
9831 
9832             if k = l_year1 then
9833                 l_start_date := p_period_start_date;
9834             else
9835                 l_start_date := l_end_date;
9836             end if;
9837 
9838             if k = l_year2 then
9839                 l_end_date := p_period_end_date;
9840             else
9841                 l_end_date := to_date('01/01/' || to_char(k+1),'DD/MM/YYYY');
9842             end if;
9843 
9844             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_start_date = ' || l_start_date);
9845             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_end_date = ' || l_end_date);
9846 
9847             l_day_count := LNS_FIN_UTILS.getDayCount(p_start_date       => l_start_date
9848                                                     ,p_end_date         => l_end_date
9849                                                     ,p_day_count_method => p_days_count_method);
9850 
9851             l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year              => k
9852                                                     ,p_year_count_method => p_days_count_method);
9853 
9854             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_day_count = ' || l_day_count);
9855             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_days_in_year = ' || l_days_in_year);
9856 
9857             l_rate1 := (l_day_count / l_days_in_year) * l_annual_rate;
9858             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': rate1 = ' || l_rate1);
9859 
9860             l_periodic_rate := l_periodic_rate + l_rate1;
9861             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Periodic rate = ' || l_periodic_rate);
9862 
9863         end loop;
9864 
9865     else
9866 
9867         l_avrg_days_in_years := 0;
9868         l_years_count := 0;
9869         for k in l_year1..l_year2 loop
9870 
9871             l_days_in_year := LNS_FIN_UTILS.daysInYear(p_year              => k
9872                                                     ,p_year_count_method => p_days_count_method);
9873 
9874             l_avrg_days_in_years := l_avrg_days_in_years + l_days_in_year;
9875             l_years_count := l_years_count + 1;
9876 
9877         end loop;
9878 
9879         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_years_count = ' || l_years_count);
9880         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total number of days in all years = ' || l_avrg_days_in_years);
9881 
9882         l_avrg_days_in_years := l_avrg_days_in_years / l_years_count;
9883         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': avarage days_in_year = ' || l_avrg_days_in_years);
9884 
9885         get_factors(p_frequency => p_payment_freq,
9886                     p_days_in_year => l_avrg_days_in_years,
9887                     x_ppy => l_payments_per_year,
9888                     x_days_in_period => l_days_in_period);
9889         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_payments_per_year = ' || l_payments_per_year);
9890 
9891         l_periodic_rate := l_annual_rate / l_payments_per_year;
9892 
9893     end if;
9894 
9895     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || '-------------');
9896     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Final Periodic rate ' || l_periodic_rate);
9897     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9898 
9899     return l_periodic_rate;
9900 
9901 end getPeriodicRate;
9902 
9903 /*
9904 ||
9905 || Parameter: p_rate = annualized interest rate
9906 ||            p_period_value = time factor like '2'
9907 ||            p_period_type = 'DAILY', 'WEEKLY', 'BI-WEEKLY', 'MONTHLY'
9908 ||                            'BI-MONTHLY',
9909 || Return value:
9910 ||
9911 || Source Tables:
9912 ||
9913 || Target Tables:
9914 ||
9915 || Creation date:       12/08/2003 3:33PM
9916 ||
9917 || Major Modifications: when            who                       what
9918 ||
9919 */
9920 function compoundInterest(p_rate in number
9921                          ,p_period_value in number
9922                          ,p_period_type in varchar2) return number
9923 is
9924 begin
9925         null;
9926 end compoundInterest;
9927 
9928 /*=========================================================================
9929 || PUBLIC PROCEDURE getAnnualRate
9930 ||
9931 || DESCRIPTION
9932 ||
9933 || Overview:  gets the current interest rate for the loan
9934 ||
9935 || Parameter:  loan_id
9936 ||
9937 || Return value: current annual rate for the loan
9938 ||
9939 || Source Tables: LNS_RATE_SCHEDULES
9940 ||
9941 || Target Tables: NA
9942 ||
9943 || KNOWN ISSUES
9944 ||
9945 || NOTES
9946 ||
9947 || MODIFICATION HISTORY
9948 || Date                  Author            Description of Changes
9949 || 12/15/2003 4:28PM     raverma           Created
9950 ||
9951  *=======================================================================*/
9952 function getAnnualRate(p_loan_Id in number) return number
9953 is
9954  l_rate     number;
9955  l_api_name varchar2(20);
9956 
9957 begin
9958 
9959      --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
9960 
9961     select rs.current_interest_rate into l_rate
9962       from lns_rate_schedules rs,
9963            lns_terms t,
9964            lns_loan_headers_all h
9965      where h.loan_id = p_loan_id
9966        and h.loan_id = t.loan_id
9967        and rs.term_id = t.term_id
9968        and rs.start_date_active <= sysdate
9969        and rs.end_date_active >= sysdate;
9970 
9971      --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
9972 
9973     return l_rate;
9974 
9975 Exception
9976 
9977     When Others then
9978       logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Error: ' || sqlerrm);
9979     --seed this message
9980     -- FND_MESSAGE.Set_Name('LNS', 'LNS_UNABLE_TO_COMPUTE_BALANCE');
9981     -- FND_MSG_PUB.Add;
9982     -- RAISE FND_API.G_EXC_ERROR;
9983 
9984 end getAnnualRate;
9985 
9986 /*=========================================================================
9987 || PUBLIC PROCEDURE getActiveRate
9988 ||
9989 || DESCRIPTION
9990 ||
9991 || Overview:  gets the current interest rate for the loan
9992 ||                we will look at the last installment billed (not reversed)
9993 ||                to get the rate on the loan
9994 || Parameter:  loan_id
9995 ||
9996 || Return value: current annual rate for the loan
9997 ||
9998 || Source Tables: LNS_RATE_SCHEDULES,
9999 ||
10000 || Target Tables: NA
10001 ||
10002 || KNOWN ISSUES
10003 ||
10004 || NOTES
10005 ||
10006 || MODIFICATION HISTORY
10007 || Date                  Author            Description of Changes
10008 || 3/8/2004 4:28PM     raverma           Created
10009 ||
10010  *=======================================================================*/
10011 function getActiveRate(p_loan_id in number) return number
10012 is
10013  l_rate_details     LNS_FINANCIALS.INTEREST_RATE_REC;
10014  l_last_installment number;
10015  l_active_rate      number;
10016  l_rate_tbl         LNS_FINANCIALS.RATE_SCHEDULE_TBL;
10017 
10018 
10019 begin
10020 
10021  l_active_rate      := -1;
10022  l_rate_tbl         := getRateSchedule(p_loan_id, 'TERM');
10023 
10024  if l_rate_tbl.count = 1 then
10025    l_active_rate := l_rate_tbl(1).annual_rate;
10026 
10027  else
10028 
10029    begin
10030 
10031 		 l_last_installment := LNS_BILLING_UTIL_PUB.LAST_PAYMENT_NUMBER(p_loan_id);
10032 
10033 		 if l_last_installment = 0
10034 		 	 then l_last_installment := 1;
10035 		 end if;
10036 
10037    exception when others then
10038      l_last_installment := 1;
10039    end;
10040    l_rate_details := getRateDetails(p_installment => l_last_installment
10041                                    ,p_rate_tbl    => l_rate_tbl);
10042    l_active_rate := l_rate_Details.annual_rate;
10043 
10044  end if;
10045 
10046  return l_active_rate;
10047 
10048 end getActiveRate;
10049 
10050 
10051 /*=========================================================================
10052 || PUBLIC PROCEDURE calculateInterestRate
10053 ||
10054 || DESCRIPTION
10055 ||
10056 || Overview:      function to calcualte interest for a variableRate Loan
10057 ||
10058 || Parameter:
10059 ||           p_initial_rate            in number => initial interest rate for loan
10060 ||           p_last_period_rate        in number => last periodic rate
10061 ||           p_max_period_adjustment   in number => maximum rate diff between adjustments
10062 ||           p_max_lifetime_adjustment in number => maximum lifetime rate difference
10063 ||           p_ceiling                 in number => maximum rate
10064 ||           p_floor                   in number => minimum rate
10065 ||           p_rate_to_compare         in number => index rate plus spread
10066 ||
10067 || Return value:  variable interest rate
10068 ||
10069 || Source Tables: NA
10070 ||
10071 || Target Tables: NA
10072 ||
10073 || KNOWN ISSUES
10074 ||
10075 || NOTES
10076 ||
10077 || Creation date:       12/08/2003 6:31PM
10078 ||
10079 || Major Modifications: when            who                       what
10080 ||                     11/20/2005    raverma                   created
10081  *=======================================================================*/
10082 function calculateInterestRate(p_initial_rate            in number
10083                               ,p_rate_to_compare         in number
10084                               ,p_last_period_rate        in number
10085                               ,p_max_first_adjustment    in number
10086                               ,p_max_period_adjustment   in number
10087                               ,p_max_lifetime_adjustment in number
10088                               ,p_ceiling_rate            in number
10089                               ,p_floor_rate              in number
10090                               ,p_installment_number      in number) return number
10091 
10092 is
10093   l_new_rate       number;
10094   l_rate_diff      number;
10095   l_life_rate_diff number;
10096   l_sign1          number;
10097   l_sign2          number;
10098   l_api_name       varchar2(30);
10099 
10100 begin
10101 
10102     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10103     -- need to check for NULLs
10104     l_rate_diff      := ABS(p_rate_to_compare - p_last_period_rate);
10105     l_life_rate_diff := ABS(p_rate_to_compare - p_initial_rate);
10106     l_sign1          := 1;
10107     l_sign2          := 1;
10108     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_rate_diff ' || l_rate_diff);
10109     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_life_rate_diff ' || l_life_rate_diff);
10110 
10111     -- rate differentials go both ways
10112     if p_rate_to_compare < p_last_period_rate then
10113         l_sign1 := -1;
10114     end if;
10115 
10116     -- rate differentials go both ways
10117     if p_rate_to_compare < p_initial_rate then
10118         l_sign2 := -1;
10119     end if;
10120 
10121     l_new_rate := p_rate_to_compare;
10122 
10123     if l_new_rate > p_ceiling_rate and p_ceiling_rate is not null then
10124         l_new_rate := p_ceiling_rate;
10125         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was above CEILING of: ' || p_ceiling_rate);
10126     end if;
10127 
10128     l_life_rate_diff := ABS(l_new_rate - p_initial_rate);
10129     if l_life_rate_diff > p_max_lifetime_adjustment and p_max_lifetime_adjustment is not null then
10130         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New Rate was above life differential of: ' || l_life_rate_diff );
10131         l_new_rate := p_last_period_rate + (p_max_lifetime_adjustment * l_sign2);
10132     end if;
10133     l_rate_diff      := ABS(l_new_rate - p_last_period_rate);
10134 
10135     if l_rate_diff > p_max_period_adjustment and p_max_period_adjustment is not null then
10136         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - New rate was above adjustment differential of: ' || l_rate_diff);
10137         l_new_rate := p_last_period_rate + (p_max_period_adjustment * l_sign1);
10138     end if;
10139 
10140     if l_new_rate < p_floor_rate and p_floor_rate is not null then
10141         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' -  New Rate was below floor of ' || p_floor_rate );
10142         l_new_rate := p_floor_rate;
10143     end if;
10144     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_new_rate ' || l_new_rate);
10145 
10146   return l_new_rate;
10147 
10148 end calculateInterestRate;
10149 
10150 /*=========================================================================
10151 || PUBLIC PROCEDURE getRemainingBalance
10152 ||
10153 || DESCRIPTION
10154 ||
10155 || Overview:      function to get the remaining balance on the loan
10156 ||
10157 || Parameter:  loan_id
10158 ||
10159 || Return value:  Amount Or BALANCE on loan
10160 ||
10161 || Source Tables: LNS_TERMS, LNS_LOAN_HEADER, LNS_AMORTIZATION_SCHEDS
10162 ||
10163 || Target Tables: NA
10164 ||
10165 || KNOWN ISSUES
10166 ||
10167 || NOTES
10168 ||
10169 || Creation date:       12/08/2003 6:31PM
10170 ||
10171 || Major Modifications: when            who                       what
10172 ||                     12/26/2003  raverma base the remaining balance from
10173 ||                                 loan status
10174 ||                      2/03/2004  balance if ACTIVE is based on PRINCIPAL_BALANCE
10175 ||                      7/29/2004  balance if DEFAULT or DELINQUENT = ACTIVE
10176  *=======================================================================*/
10177 function getRemainingBalance(p_loan_id in number) return number
10178 is
10179     l_balance        number;
10180     l_initial_amount number;
10181     l_billed_amount  number;
10182     l_loan_status    varchar2(30);
10183     l_column         varchar2(30);
10184     l_table          varchar2(30);
10185     l_api_name       varchar2(30);
10186 
10187 begin
10188     l_balance        := -1;
10189     l_initial_amount := 0;
10190     l_billed_amount  := 0;
10191     l_api_name       := 'getRemainingBalance';
10192     --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10193 
10194      Execute Immediate
10195              ' Select Loan_Status ' ||
10196              ' From lns_loan_headers_all ' ||
10197              ' where loan_id = :p_loan_id'
10198               into l_loan_status
10199              using p_loan_id;
10200 
10201      if l_loan_status = 'APPROVED' then
10202         l_column := 'TOTAL_PRINCIPAL_BALANCE';
10203         l_table  := 'LNS_PAY_SUM_V';
10204 --        l_column := 'REQUESTED_AMOUNT';
10205 --        l_table  := 'LNS_LOAN_HEADERS_ALL';
10206 
10207      elsif l_loan_Status = 'ACTIVE' then
10208         l_column := 'TOTAL_PRINCIPAL_BALANCE';
10209         l_table  := 'LNS_PAY_SUM_V';
10210 
10211      elsif l_loan_Status = 'DELINQUENT' then
10212         l_column := 'TOTAL_PRINCIPAL_BALANCE';
10213         l_table  := 'LNS_PAY_SUM_V';
10214 
10215      elsif l_loan_Status = 'DEFAULT' then
10216         l_column := 'TOTAL_PRINCIPAL_BALANCE';
10217         l_table  := 'LNS_PAY_SUM_V';
10218 
10219      elsif l_loan_Status = 'PAIDOFF' then
10220         l_column := 'TOTAL_PRINCIPAL_BALANCE';
10221         l_table  := 'LNS_PAY_SUM_V';
10222 --        l_column := 'REQUESTED_AMOUNT';
10223 --        l_table  := 'LNS_LOAN_HEADERS_ALL';
10224 
10225      elsif l_loan_Status = 'CANCELLED' then
10226         l_column := 'TOTAL_PRINCIPAL_BALANCE';
10227         l_table  := 'LNS_PAY_SUM_V';
10228 
10229      elsif l_loan_status = 'PENDING' then
10230         l_column := 'REQUESTED_AMOUNT';
10231         l_table  := 'LNS_LOAN_HEADERS_ALL';
10232 
10233      elsif l_loan_status = 'INCOMPLETE' then
10234         l_column := 'REQUESTED_AMOUNT';
10235         l_table  := 'LNS_LOAN_HEADERS_ALL';
10236 
10237      elsif l_loan_status = 'IN_FUNDING' then
10238         l_column := 'REQUESTED_AMOUNT';
10239         l_table  := 'LNS_LOAN_HEADERS_ALL';
10240 
10241      elsif l_loan_status = 'FUNDING_ERROR' then
10242         l_column := 'REQUESTED_AMOUNT';
10243         l_table  := 'LNS_LOAN_HEADERS_ALL';
10244 
10245      else -- catch any new statuses
10246         l_column := 'REQUESTED_AMOUNT';
10247         l_table  := 'LNS_LOAN_HEADERS_ALL';
10248 
10249      end if;
10250 
10251      Execute Immediate
10252              ' Select ' || l_column ||
10253              ' From ' || l_table ||
10254              ' where loan_id = :p_loan_id'
10255              into l_balance
10256              using p_loan_id;
10257 
10258     --    logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': remainingBalance: ' || l_balance);
10259     --    logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
10260 
10261     return l_balance;
10262 /*
10263   Exception
10264         When Others then
10265          logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Error: ' || sqlerrm);
10266         --seed this message
10267          FND_MESSAGE.Set_Name('LNS', 'LNS_UNABLE_TO_COMPUTE_BALANCE');
10268          FND_MSG_PUB.Add;
10269          RAISE FND_API.G_EXC_ERROR;
10270  */
10271 end getRemainingBalance;
10272 
10273 
10274 function getFundedAmount(p_loan_id in number, p_date in date, p_based_on_terms varchar2) return number
10275 is
10276 
10277     l_api_name  varchar2(30) := 'getFundedAmount';
10278     l_funded_amount         number;
10279     l_bill_on_appr_amounts  varchar2(1);
10280 
10281     cursor c_get_loan_balance(p_loan_id number, p_date date) is
10282         select
10283         decode(loan.loan_class_code,
10284         'DIRECT', (select nvl(sum(disb_line.LINE_AMOUNT), 0) from lns_disb_lines disb_line, lns_disb_headers disb_hdr
10285                     where disb_hdr.loan_id = loan.loan_id and /*disb_hdr.phase = 'TERM' and */
10286                     disb_hdr.disb_header_id = disb_line.disb_header_id and disb_line.STATUS = 'FULLY_FUNDED' and
10287                     trunc(disb_line.DISBURSEMENT_DATE) <= trunc(p_date)),
10288         'ERS', (select nvl(sum(lines.REQUESTED_AMOUNT), 0) from lns_loan_lines lines
10289                 where lines.loan_id = loan.loan_id and lines.STATUS = 'APPROVED' and lines.end_date is null and
10290                 trunc(lines.ADJUSTMENT_DATE) <= trunc(p_date)))
10291         from lns_loan_headers_all loan
10292         where loan.loan_id = p_loan_id;
10293 
10294     cursor c_get_loan_balance1(p_loan_id number, p_date date) is
10295         select
10296         decode(loan.loan_class_code,
10297         'DIRECT', (select nvl(sum(disb_hdr.HEADER_AMOUNT), 0) from lns_disb_headers disb_hdr
10298                     where disb_hdr.loan_id = loan.loan_id and
10299                     disb_hdr.STATUS is null and
10300                     (disb_hdr.PAYMENT_REQUEST_DATE is null or trunc(disb_hdr.PAYMENT_REQUEST_DATE) <= trunc(p_date))),
10301         'ERS', (select nvl(sum(lines.REQUESTED_AMOUNT), 0) from lns_loan_lines lines
10302                 where lines.loan_id = loan.loan_id and (lines.STATUS is null or lines.STATUS = 'PENDING') and
10303                 lines.end_date is null))
10304         from lns_loan_headers_all loan
10305         where loan.loan_id = p_loan_id;
10306 
10307     cursor c_get_loan_balance2(p_loan_id number, p_date date) is
10308         select
10309         decode(loan.loan_class_code,
10310         'DIRECT', loan.requested_amount + nvl(loan.ADD_REQUESTED_AMOUNT, 0) /* +
10311                 (select nvl(sum(adj.ADJUSTMENT_AMOUNT), 0) from LNS_LOAN_AMOUNT_ADJS adj
10312                 where adj.LOAN_ID = loan.loan_id and adj.STATUS = 'APPROVED' and
10313                 trunc(adj.EFFECTIVE_DATE) <= trunc(p_date))*/,
10314         'ERS', (select nvl(sum(lines.REQUESTED_AMOUNT), 0) from lns_loan_lines lines
10315                 where lines.loan_id = loan.loan_id and (lines.STATUS is null or lines.STATUS = 'PENDING') and
10316                 lines.end_date is null))
10317         from lns_loan_headers_all loan
10318         where loan.loan_id = p_loan_id;
10319 
10320     cursor c_get_bill_opt(p_loan_id number) is
10321         select nvl(BILL_ON_APPR_AMOUNT_FLAG, 'N')
10322         from lns_loan_headers_all
10323         where loan_id = p_loan_id;
10324 begin
10325     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10326     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_loan_id = ' || p_loan_id);
10327     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_date = ' || p_date);
10328     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'p_based_on_terms = ' || p_based_on_terms);
10329 
10330     open c_get_bill_opt(p_loan_id);
10331     fetch c_get_bill_opt into l_bill_on_appr_amounts;
10332     close c_get_bill_opt;
10333     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_bill_on_appr_amounts = ' || l_bill_on_appr_amounts);
10334 
10335     if l_bill_on_appr_amounts = 'N' then  -- bill based on funding amounts
10336 
10337         if p_based_on_terms = 'CURRENT' then
10338             open c_get_loan_balance(p_loan_id, p_date);
10339             fetch c_get_loan_balance into l_funded_amount;
10340             close c_get_loan_balance;
10341         else
10342             open c_get_loan_balance1(p_loan_id, p_date);
10343             fetch c_get_loan_balance1 into l_funded_amount;
10344             close c_get_loan_balance1;
10345         end if;
10346 
10347     else   -- bill based on approved amounts
10348 
10349         open c_get_loan_balance2(p_loan_id, p_date);
10350         fetch c_get_loan_balance2 into l_funded_amount;
10351         close c_get_loan_balance2;
10352 
10353     end if;
10354 
10355     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'l_funded_amount = ' || l_funded_amount);
10356     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
10357 
10358     return l_funded_amount;
10359 end;
10360 
10361 
10362 /*========================================================================
10363  | PUBLIC FUNCTION weightBalance
10364  |
10365  | DESCRIPTION
10366  |      takes a table of loan_activities, sorts them and weights the balance
10367 ||       by the from/to dates
10368  |
10369  | PSEUDO CODE/LOGIC
10370 ||     - calculate the wtd average daily balance for the loan (construction)
10371 ||     - day counting method is accoring to the terms of the loan
10372 ||
10373 ||      within the given from/to date range
10374 ||      ADB =[(# of days X Balance 1 ) +
10375 ||            (# of days X Balance 2 ) +
10376 ||            (# of days X Balance 3 ) +
10377 ||             .
10378 ||             .
10379 ||             .
10380 ||            (# of days X Balance N ) ]
10381 ||             /
10382 ||             Total Number of Days (from <-> to dates)
10383  |
10384  | PARAMETERS
10385  |
10386  | Return value:
10387  |
10388  | Source Tables: NA
10389  |
10390  | Target Tables: NA
10391  |
10392  | KNOWN ISSUES
10393  |
10394  | MODIFICATION HISTORY
10395  | Date                  Author            Description of Changes
10396  | 07/19/05 4:13:PM       raverma           Created
10397  *=======================================================================*/
10398 function weightBalance(p_loan_activities   IN LNS_FINANCIALS.LOAN_ACTIVITY_TBL
10399                       ,p_from_date         in date
10400                       ,p_to_date     			 in date
10401                       ,p_day_count_method	 in varchar2) return number
10402 is
10403     l_balance_days          number;
10404     l_total_days            number;
10405 		l_num_days							number;
10406     l_weighted_balance      number;
10407     k                       number;
10408     m                       number;
10409     l_api_name              varchar2(25);
10410     l_begin_balance         number;
10411     l_end_balance           number;
10412 		l_total_activity_amount number;
10413 		l_loan_activities       LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
10414 
10415 
10416 begin
10417 		 l_api_name := 'weightBalance';
10418      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
10419      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - number of activities: ' || p_loan_activities.count);
10420      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date:          ' ||  p_from_date);
10421      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date:            ' || p_to_date);
10422      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_day_count_method:   ' || p_day_count_method);
10423 
10424 		 -- sort activities by activity date
10425 
10426      -- # of days @ balance 1
10427      -- # of days @ balance 2
10428      -- # of days @ balance N
10429      -- find balance on from date
10430      -- find balance on to date
10431      -- find number of balance changes between the 2
10432      -- loop thru each balance change and calc # of days at balance
10433      -- now calculate ADB using dates from and to
10434      l_balance_days          := 0;
10435      l_total_days            := 0;
10436 	   l_num_days					     := 0;
10437      l_weighted_balance      := 0;
10438 		 l_total_activity_amount := 0;
10439 		 l_loan_activities       := p_loan_activities;
10440  		 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - sorting the activities');
10441 		 sortRows(l_loan_activities);
10442 
10443 		 /*
10444 		 for j in 1..p_loan_activities.count
10445 		 loop
10446 			dbms_output.put_line(p_loan_activities(j).activity_date );
10447 			dbms_output.put_line(p_loan_activities(j).ending_balance );
10448 		 end loop;
10449 			*/
10450 
10451 		 m := l_loan_activities.count;
10452 
10453 		 if m = 1 then
10454 	     l_weighted_balance := l_loan_activities(1).ending_balance;
10455 		 else
10456 
10457 	 		 for p in 1..m loop
10458 			  	--dbms_output.put_line('p is ' || p);
10459 					 if l_loan_activities(p).activity_amount > 0 then
10460 						     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p ' || p);
10461 						     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity date: ' || l_loan_activities(p).activity_date);
10462 						     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity amount: ' || l_loan_activities(p).activity_amount);
10463 							 if p = 1 then
10464 									 -- this is for the previous balance
10465 				           l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date       => p_from_date
10466 				                                                  ,p_end_date         => p_to_date
10467 				                                                  ,p_day_count_method => p_day_count_method);
10468 						   elsif p < m then
10469 				           l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date       => l_loan_activities(p).activity_date
10470 				                                                  ,p_end_date         => l_loan_activities(p+1).activity_date
10471 				                                                  ,p_day_count_method => p_day_count_method);
10472 				       elsif p = m  then
10473 				          --dbms_output.put_line('2');
10474 				           l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date       => l_loan_activities(p).activity_date
10475 				                                                  ,p_end_date         => p_to_date
10476 				                                                  ,p_day_count_method => p_day_count_method);
10477 				       end if;
10478 
10479 							 if l_num_days > 0 then
10480 							    l_total_activity_amount := l_total_activity_amount + l_loan_activities(p).activity_amount;
10481 							 end if;
10482 
10483 						   logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - total activity amount: ' || l_total_activity_amount);
10484 				       --dbms_output.put_line('day count is ' || l_num_days);
10485 				       --dbms_output.put_line('balance is ' || p_loan_activities(p).ending_balance);
10486                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
10487                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_num_days: ' || l_num_days);
10488                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - activity_amount: ' || l_loan_activities(p).activity_amount);
10489 				       l_balance_days := l_balance_days + (l_num_days * l_loan_activities(p).activity_amount);
10490                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - result l_balance_days: ' || l_balance_days);
10491 				   end if;
10492 
10493 			 end loop;
10494 
10495 	     -- this is the total days (denominator)
10496 		    l_total_Days := LNS_FIN_UTILS.getDayCount(p_start_date       => p_from_date
10497 		                                             ,p_end_date         => p_to_date
10498 		                                             ,p_day_count_method => p_day_count_method);
10499 		    -- dbms_output.put_line('total days is ' || l_total_Days );
10500         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
10501         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_total_days: ' || l_total_days);
10502 		    l_weighted_balance := l_balance_days / l_total_days;
10503         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_weighted_balance: ' || l_weighted_balance);
10504 
10505 		 end if;
10506 
10507      return l_weighted_balance;
10508 
10509 end weightBalance;
10510 
10511 /*=========================================================================
10512 || PUBLIC FUNCTION getWeightedBalance
10513 ||
10514 || DESCRIPTION
10515 ||
10516 || PARAMETERS
10517 ||                p_loan_id   loan_id
10518 ||                p_term_id   term_id (for future use)
10519 ||                p_from_date date from which to calculate ADB
10520 ||                p_to_date   date to which to calculate ADB
10521 ||                p_calc_method 'ACTUAL' or 'TARGET'
10522 ||
10523 || Return value: wtd average daily balance for the loan
10524 ||
10525 || Source Tables: LNS_DISB_HEADERS, LNS_DISB_LINES
10526 ||
10527 || Target Tables: NA
10528 ||
10529 || KNOWN ISSUES
10530 ||
10531 || NOTES
10532 ||
10533 || MODIFICATION HISTORY
10534 || Date                  Author            Description of Changes
10535 || 07/17/05 1:51:PM      raverma           Created
10536  *=======================================================================*/
10537 procedure getWeightedBalance(p_loan_id          in number
10538                            ,p_from_date        in date
10539                            ,p_to_date          in date
10540                            ,p_calc_method      in varchar2
10541                            ,p_phase            in varchar2
10542                            ,p_day_count_method in varchar2
10543                            ,p_adj_amount       in number
10544                            ,x_wtd_balance      out NOCOPY number
10545                            ,x_begin_balance    out NOCOPY number
10546                            ,x_end_balance      out NOCOPY number)
10547 
10548 is
10549 	l_api_name         varchar2(25);
10550 	l_loan_activities  LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
10551 	i                  number;
10552 	l_activity_date    date;
10553 	l_activity_amount  number;
10554 	l_loan_start_date  date;
10555     l_display_order    number;
10556     l_precision        number;
10557 
10558 	cursor c_actual_balance(p_loan_id number, p_from_date date, p_to_date date)  IS
10559 		select * from
10560             (select p_from_date activity_date
10561                 ,nvl(sum(line_amount), 0)
10562                 ,1 display_order
10563             from lns_disb_lines lines
10564             where disb_header_id in (select disb_header_id from lns_disb_headers where loan_id = p_loan_id)
10565                 and trunc(disbursement_date) <= p_from_date
10566             UNION
10567             select trunc(line.disbursement_date) activity_date
10568                 ,nvl(sum(inv.amount), 0)
10569                 ,2 display_order
10570             from AP_INVOICE_PAYMENTS_ALL inv
10571                 ,lns_disb_headers head
10572                 ,lns_disb_lines line
10573             where head.loan_id = p_loan_id
10574                 and line.disb_header_id = head.disb_header_id
10575                 and line.invoice_id is not null
10576                 and line.invoice_id = inv.invoice_id
10577                 and line.status IN ('PARTIALLY_FUNDED', 'FULLY_FUNDED')
10578                 and trunc(line.disbursement_date) > p_from_date
10579                 and trunc(line.disbursement_date) < p_to_date
10580             group by trunc(line.disbursement_date))
10581         order by display_order, activity_date;
10582 
10583     cursor c_theoretical_balance(p_loan_id number, p_from_date date, p_to_date date) IS
10584             select * from
10585                 (select p_from_date activity_date
10586                     ,nvl(sum(header_amount),0)
10587                     ,1 display_order
10588                 from lns_disb_headers
10589                 where loan_id = p_loan_id
10590                     and trunc(payment_request_date) <= p_from_date
10591                 UNION
10592                 select payment_request_date activity_date
10593                     ,nvl(sum(header_amount),0)
10594                     ,2 display_order
10595                 from lns_disb_headers
10596                 where loan_id = p_loan_id
10597                     and trunc(payment_request_date) > p_from_date
10598                     and trunc(payment_request_date) < p_to_date
10599                 group by payment_request_date
10600                 UNION
10601                 select lines.*
10602                 from
10603                 (select p_from_date activity_date
10604                     ,nvl(sum(REQUESTED_AMOUNT),0)
10605                     ,3 display_order
10606                 from lns_loan_lines
10607                 where loan_id = p_loan_id
10608                     and (status is null or status = 'PENDING')
10609                     and end_date is null) lines,
10610                 lns_loan_headers_all loan
10611                 where loan.loan_id = p_loan_id
10612                 and loan.LOAN_CLASS_CODE = 'ERS')
10613             order by display_order, activity_date;
10614 
10615     cursor c_loan_boundaries(p_loan_id number)
10616     is
10617         select open_loan_start_date
10618             from lns_loan_headers
10619             where loan_id = p_loan_id;
10620 
10621     cursor c_curr_precision(p_loan_id number) is
10622         select curr.precision
10623         from lns_loan_headers_all h
10624         ,fnd_currencies  curr
10625         where h.loan_id = p_loan_id
10626 	    and curr.currency_code = h.loan_currency;
10627 
10628 begin
10629 
10630      l_api_name             := 'getWeightedBalance';
10631      i                      := 0;
10632 	 x_wtd_balance			:= 0;
10633      x_begin_balance := 0;
10634      x_end_balance := 0;
10635      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Begin');
10636      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
10637      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
10638 	 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_loan_id: ' || p_loan_id);
10639 	 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_calc_method: ' || p_calc_method);
10640 	 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_adj_amount: ' || p_adj_amount);
10641 	 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_phase: ' || p_phase);
10642 
10643      -- validate the from and to Dates
10644      if p_from_date > p_to_date  then
10645         FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_ACTIVE_DATE');
10646         FND_MSG_PUB.Add;
10647         RAISE FND_API.G_EXC_ERROR;
10648      end if;
10649 
10650      l_loan_activities(1).ending_balance := 0;
10651 
10652      if p_calc_method = 'ACTUAL' then
10653 
10654         -- get all the balance activities on the loan
10655         OPEN c_actual_balance(p_loan_id, p_from_date, p_to_date);
10656         LOOP
10657             i := i + 1;
10658             FETCH c_actual_balance INTO
10659                 l_activity_date
10660                 ,l_activity_amount
10661                 ,l_display_order;
10662             EXIT WHEN c_actual_balance%NOTFOUND;
10663 
10664             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
10665             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date = ' || l_activity_date);
10666             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount = ' || l_activity_amount);
10667             l_loan_activities(i).activity_date    := l_activity_date;
10668             l_loan_activities(i).activity_amount  := l_activity_amount;
10669             if i = 1 then
10670                 l_loan_activities(i).ending_balance   := l_activity_amount;
10671                 x_begin_balance := l_loan_activities(i).ending_balance;
10672                 x_end_balance := l_loan_activities(i).ending_balance;
10673             else
10674                 l_loan_activities(i).ending_balance   := l_activity_amount + l_loan_activities(i-1).ending_balance;
10675                 x_end_balance := l_loan_activities(i).ending_balance;
10676             end if;
10677             l_activity_date                       := null;
10678             l_activity_amount                     := null;
10679         END LOOP;
10680         close c_actual_balance;
10681 
10682      elsif p_calc_method = 'TARGET' then
10683 
10684         OPEN c_theoretical_balance(p_loan_id, p_from_date, p_to_date);
10685         LOOP
10686             i := i + 1;
10687             FETCH c_theoretical_balance INTO
10688                 l_activity_date
10689                 ,l_activity_amount
10690                 ,l_display_order;
10691             EXIT WHEN c_theoretical_balance%NOTFOUND;
10692 
10693             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
10694             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date = ' || l_activity_date);
10695             logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount = ' || l_activity_amount);
10696 
10697             if i = 1 then
10698                 l_activity_amount := l_activity_amount - p_adj_amount;
10699                 logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - NEW l_activity_amount = ' || l_activity_amount);
10700 
10701                 l_loan_activities(i).ending_balance   := l_activity_amount;
10702                 x_begin_balance := l_loan_activities(i).ending_balance;
10703             else
10704                 l_loan_activities(i).ending_balance   := l_activity_amount + l_loan_activities(i-1).ending_balance;
10705             end if;
10706 
10707             x_end_balance := l_loan_activities(i).ending_balance;
10708             l_loan_activities(i).activity_date    := l_activity_date;
10709             l_loan_activities(i).activity_amount  := l_activity_amount;
10710 
10711             l_activity_date                       := null;
10712             l_activity_amount                     := null;
10713         END LOOP;
10714         close c_theoretical_balance;
10715 
10716     end if;
10717 
10718      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - getting wtd balance');
10719      x_wtd_balance := weightBalance(p_loan_activities    => l_loan_activities
10720                                     ,p_from_date          => p_from_date
10721                                     ,p_to_date     			 => p_to_date
10722                                     ,p_day_count_method	 => p_day_count_method);
10723 
10724      OPEN c_curr_precision(p_loan_id);
10725      FETCH c_curr_precision INTO l_precision;
10726      CLOSE c_curr_precision;
10727 
10728      x_wtd_balance := round(x_wtd_balance, l_precision);
10729      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_wtd_balance = ' || x_wtd_balance);
10730      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_begin_balance = ' || x_begin_balance);
10731      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - x_end_balance = ' || x_end_balance);
10732 
10733 end getWeightedBalance;
10734 
10735 
10736 
10737 /*=========================================================================
10738 || PUBLIC FUNCTION getAverageDailyBalance
10739 ||
10740 || DESCRIPTION
10741 ||     - calculate average daily balance for the loan (term)
10742 ||     - day counting method is accoring to the terms of the loan
10743 ||
10744 ||      only one method supported right now:
10745 ||      within the given from/to date range
10746 ||      ADB =[(# of days X Balance 1 ) +
10747 ||            (# of days X Balance 2 ) +
10748 ||            (# of days X Balance 3 ) +
10749 ||             .
10750 ||             .
10751 ||             .
10752 ||            (# of days X Balance N ) ]
10753 ||             /
10754 ||             Total Number of Days (from <-> to dates)
10755 ||
10756 || PARAMETERS
10757 ||                p_loan_id   loan_id
10758 ||                p_term_id   term_id (for future use)
10759 ||                p_from_date date from which to calculate ADB
10760 ||                p_to_date   date to which to calculate ADB
10761 ||                p_calc_method for future use
10762 ||
10763 || Return value: average daily balance for the loan
10764 ||
10765 || Source Tables: LNS_RECEIVABLE_ACTIVITIES_V, LNS_LOAN_HEADERS
10766 ||
10767 || Target Tables: NA
10768 ||
10769 || KNOWN ISSUES
10770 ||
10771 || NOTES
10772 ||
10773 ||
10774 || MODIFICATION HISTORY
10775 || Date                  Author            Description of Changes
10776 || 05/31/06 1:51:PM       karamach          Added cursor c_loan_phase and passed current_phase to getLoanDetails api to fix bug5237022
10777 || 09/30/04 1:51:PM       raverma           Created
10778 ||
10779  *=======================================================================*/
10780 function getAverageDailyBalance(p_loan_id     number
10781                                ,p_term_id     number
10782                                ,p_from_date   date
10783                                ,p_to_date     date
10784                                ,p_calc_method number) return number
10785 is
10786 
10787     -- this cursor will get balance by activity date
10788     -- the markers ensure that funding and maturity are the 1st and last rows
10789     cursor c_balance_history(p_loan_id number) is
10790     select trunc(loan_start_date) activity_date,
10791            funded_amount          activity_amount,
10792            funded_amount          ending_balance
10793       from lns_loan_headers
10794      where loan_id = p_loan_id
10795     union all
10796     select trunc(activity_date)          activity_date,
10797            sum(activity_amount)          activity_amount,
10798            LNS_BILLING_UTIL_PUB.LOAN_BALANCE_BY_DATE(P_LOAN_ID, activity_date)     --min(balance_by_activity_date) ending_balance
10799       from LNS_REC_ACT_CASH_CM_V rav
10800      where rav.loan_id = p_loan_id and
10801            line_type_code = 'PRIN' and
10802            (activity_code in ('PMT', 'ADJ') or (activity_code = 'CM' and activity_number like 'NET%'))
10803     group by activity_date
10804     union all
10805     select trunc(loan_maturity_date) activity_date
10806           ,null
10807           ,lns_financials.getRemainingBalance(p_loan_id)
10808       from lns_loan_headers
10809      where loan_id = p_loan_id
10810     order by activity_date asc;
10811 
10812     -- this cursor will get the current phase of the loan
10813     cursor c_loan_phase(p_loan_id number) is
10814     select nvl(current_phase,'TERM') current_phase
10815       from lns_loan_headers
10816      where loan_id = p_loan_id;
10817 
10818     l_activity_date         date;
10819     l_activity_amount       number;
10820     l_balance_days          number;
10821     l_num_days              number;
10822     l_total_days            number;
10823     l_loan_details          LNS_FINANCIALS.LOAN_DETAILS_REC;
10824     l_loan_activities       LNS_FINANCIALS.LOAN_ACTIVITY_TBL;
10825     l_average_daily_balance number;
10826     k                       number;
10827     m                       number;
10828     l_num_balance_changes   number;
10829     l_api_name              varchar2(25);
10830     l_begin_balance         number;
10831     l_end_balance           number;
10832     i                       number;
10833 --    l_marker                number;
10834     l_loan_phase            varchar2(30);
10835 
10836 begin
10837 
10838      --LNS_BILLING_UTIL_PUB.LOAN_BALANCE_BY_DATE(P_LOAN_ID IN NUMBER, P_DATE IN DATE) function
10839      l_api_name             := 'getAverageDailyBalance';
10840      l_balance_days         := 0;
10841      l_num_days             := 0;
10842      l_total_days           := 0;
10843      l_average_daily_balance:= 0;
10844      i                      := 0;
10845      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - Begin');
10846      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_from_date: ' || p_from_date);
10847      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - p_to_date: ' || p_to_date);
10848 
10849      -- validate the from and to Dates
10850      if p_from_date > p_to_date  then
10851         FND_MESSAGE.Set_Name('LNS', 'LNS_INVALID_ACTIVE_DATE');
10852         FND_MSG_PUB.Add;
10853         RAISE FND_API.G_EXC_ERROR;
10854      end if;
10855 
10856      OPEN c_loan_phase(p_loan_id);
10857      FETCH c_loan_phase INTO l_loan_phase;
10858      CLOSE c_loan_phase;
10859 
10860      l_loan_details := lns_financials.getLoanDetails(p_loan_id        => p_loan_id
10861                                                     ,p_based_on_terms => 'CURRENT'
10862 						    --karamach bug5237022
10863                                                     --,p_phase          => 'TERM');
10864                                                     ,p_phase          => l_loan_phase);
10865 
10866      -- validate if dates are within the boundaries of loan_start and maturity_dates
10867      if p_to_date > l_loan_details.maturity_date then
10868         FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR1');
10869         FND_MSG_PUB.Add;
10870         RAISE FND_API.G_EXC_ERROR;
10871      end if;
10872 
10873      if p_from_date < l_loan_details.loan_start_date then
10874         FND_MESSAGE.Set_Name('LNS', 'LNS_PAYMENT_START_DATE_ERROR2');
10875         FND_MSG_PUB.Add;
10876         RAISE FND_API.G_EXC_ERROR;
10877      end if;
10878 
10879      -- get all the balance activities on the loan
10880      OPEN c_balance_history(p_loan_id);
10881      LOOP
10882          i := i + 1;
10883      FETCH c_balance_history INTO
10884          l_activity_date
10885         ,l_activity_amount
10886         ,l_end_balance;
10887 --        ,l_marker;
10888          logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - #: ' || i);
10889          logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_date: ' || l_activity_date);
10890          logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_activity_amount: ' || l_activity_amount);
10891          logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_end_balance: ' || l_end_balance);
10892      EXIT WHEN c_balance_history%NOTFOUND;
10893 
10894          l_loan_activities(i).activity_date    := l_activity_date;
10895          l_loan_activities(i).activity_amount  := l_activity_amount;
10896          l_loan_activities(i).ending_balance   := l_end_balance;
10897 
10898      END LOOP;
10899      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - number of activities: ' || l_loan_activities.count);
10900 
10901      -- # of balance changes = l_loan_activities.count - 2
10902      -- # of days @ balance 1
10903      -- # of days @ balance 2
10904      -- # of days @ balance N
10905      -- find balance on from date
10906      -- find balance on to date
10907      -- find number of balance changes between the 2
10908      -- loop thru each balance change and calc # of days at balance
10909      -- now calculate ADB using dates from and to
10910      k := 1;
10911      WHILE p_from_date >= l_loan_activities(k).activity_date loop
10912            l_begin_balance := l_loan_activities(k).ending_balance;
10913            k := k + 1;
10914      end loop;
10915      k := k - 1;
10916 
10917      m := 1;
10918      WHILE p_to_date >= l_loan_activities(m).activity_date loop
10919            l_end_balance := l_loan_activities(m).ending_balance;
10920            m := m + 1;
10921      end loop;
10922      m := m - 1;
10923 
10924      --dbms_output.put_line('output k' || k);
10925      --dbms_output.put_line('output m' || m);
10926 
10927      if k = m then
10928          l_average_daily_balance := l_loan_activities(k).ending_balance;
10929      else
10930          for p in k..m loop
10931             --dbms_output.put_line('p is ' || p);
10932              if p = k then              -- first record
10933                 --dbms_output.put_line('1');
10934                  l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date       => p_from_date
10935                                                         ,p_end_date         => l_loan_activities(p + 1).activity_date
10936                                                         ,p_day_count_method => l_loan_details.day_count_method);
10937 
10938              elsif p = m then
10939              --   dbms_output.put_line('3');
10940                  l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date       => l_loan_activities(p).activity_date
10941                                                         ,p_end_date         => p_to_date
10942                                                         ,p_day_count_method => l_loan_details.day_count_method);
10943 
10944              else
10945              --   dbms_output.put_line('2');
10946                  l_num_days := LNS_FIN_UTILS.getDayCount(p_start_date       => l_loan_activities(p).activity_date
10947                                                         ,p_end_date         => l_loan_activities(p + 1).activity_date
10948                                                         ,p_day_count_method => l_loan_details.day_count_method);
10949 
10950              end if;
10951              --dbms_output.put_line('day count is ' || l_num_days);
10952              --dbms_output.put_line('balance is ' || l_loan_activities(p).ending_balance);
10953              l_balance_days := l_balance_days + l_num_days * l_loan_activities(p).ending_balance;
10954 
10955          end loop;
10956          -- this is the total days (denominator)
10957          l_total_Days := LNS_FIN_UTILS.getDayCount(p_start_date       => p_from_date
10958                                                   ,p_end_date         => p_to_date
10959                                                   ,p_day_count_method => l_loan_details.day_count_method);
10960 
10961          --dbms_output.put_line('total days is ' || l_total_Days );
10962          l_average_daily_balance := l_balance_days / l_total_days;
10963      end if;
10964 
10965      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_balance_days: ' || l_balance_days);
10966      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_total_balance: ' || l_total_days);
10967      --dbms_output.put_line('adb is ' || l_average_daily_balance);
10968      logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - l_end_balance: ' || l_end_balance);
10969      return round(l_average_daily_balance, l_loan_details.currency_precision);
10970 
10971 EXCEPTION
10972 
10973     When others Then
10974         return -1;
10975         logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - ' || sqlerrm);
10976 
10977 
10978 end getAverageDailyBalance;
10979 
10980 
10981 function getAPR(p_loan_id     in number
10982                ,p_term_id     in number
10983                ,p_actual_flag in varchar2) return number
10984 is
10985 
10986 begin
10987            null;
10988            /*
10989     public static double RATE(double d, double d1, double d2)
10990     {
10991         double d3 = 1.0D;
10992         double d4 = 0.5D;
10993         double d5 = d1;
10994         if(d * d1 <= d2)
10995         {
10996             return 0.0D;
10997         }
10998         for(int i = 1; i < 50; i++)
10999         {
11000             double d6 = PMT(d3, d, d2);
11001             if(d6 == d1)
11002             {
11003                 return d3;
11004             }
11005             if(d6 < d1)
11006             {
11007                 d3 += d4;
11008             } else
11009             {
11010                 d3 -= d4;
11011             }
11012             d4 /= 2D;
11013         }
11014 
11015         return d3;
11016     }
11017              */
11018 end;
11019 
11020 
11021 -- This procedure calculates normal interest
11022 procedure CALC_NORM_INTEREST(p_loan_id               in  number,
11023                            p_calc_method           in  varchar2,
11024                            p_period_start_date     in  date,
11025                            p_period_end_date       in  date,
11026                            p_interest_rate         in  number,
11027                            p_day_count_method      in  varchar2,
11028                            p_payment_freq          in  varchar2,
11029                            p_compound_freq         in  varchar2,
11030                            p_adj_amount            in  number,
11031                            p_CAP_AMOUNT          in  number default 0,
11032                            x_norm_interest         out NOCOPY number,
11033                            x_norm_int_details      out NOCOPY varchar2)
11034 is
11035     l_api_name              varchar2(25);
11036     l_activity_date         date;
11037     l_activity_code         varchar2(30);
11038     l_activity_amount       number;
11039     l_theory_balance        number;
11040     l_actual_balance        number;
11041     l_days_late             number;
11042     l_display_order         number;
11043     l_rate                  number;
11044     l_day_count             number;
11045     i                       number;
11046     l_norm_prev_amount      number;
11047     l_norm_interest         number;
11048     l_norm_prev_act_date    date;
11049     l_cum_norm_interest     number;
11050     l_periodic_rate         number;
11051     l_norm_int_detail_str   varchar2(2000);
11052     l_precision             number;
11053 
11054     cursor c_trx_activities(p_loan_id number, p_start_date date, p_end_date date) is
11055         select
11056         trunc(ACTIVITY_DATE),
11057         ACTIVITY_CODE,
11058         ACTIVITY_AMOUNT,
11059         THEORETICAL_BALANCE,
11060         ACTUAL_BALANCE,
11061         DAYS_LATE,
11062         display_order
11063         from LNS_PRIN_TRX_ACTIVITIES_V
11064         where loan_id = p_loan_id and
11065         trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
11066         trunc(ACTIVITY_DATE) <= trunc(p_end_date) and
11067         ACTIVITY_CODE in ('START', 'DUE', 'DISBURSEMENT', 'INVOICE_ADDED')
11068         order by activity_date, display_order, LOAN_AMORTIZATION_ID;
11069 
11070     cursor c_curr_precision(p_loan_id number) is
11071         select curr.precision
11072         from lns_loan_headers_all h
11073         ,fnd_currencies  curr
11074         where h.loan_id = p_loan_id
11075 	    and curr.currency_code = h.loan_currency;
11076 
11077 begin
11078 
11079     l_api_name  := 'CALC_NORM_INTEREST';
11080     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11081     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
11082     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
11083     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
11084     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
11085     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
11086     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
11087     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
11088     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
11089     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
11090     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
11091     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': adj amount: ' || p_adj_amount);
11092     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': capitalized int: ' || p_CAP_AMOUNT);
11093 
11094     -- calculating normal and additional interest
11095     i := 1;
11096     l_norm_interest := 0;
11097     l_cum_norm_interest := 0;
11098     l_norm_prev_amount := 0;
11099     l_norm_prev_act_date := p_period_start_date;
11100     x_norm_interest := 0;
11101 
11102     OPEN c_curr_precision(p_loan_id);
11103     FETCH c_curr_precision INTO l_precision;
11104     CLOSE c_curr_precision;
11105 
11106     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
11107 
11108     OPEN c_trx_activities(p_loan_id, p_period_start_date, p_period_end_date);
11109     LOOP
11110 
11111         FETCH c_trx_activities INTO
11112           l_activity_date
11113           ,l_activity_code
11114           ,l_activity_amount
11115           ,l_theory_balance
11116           ,l_actual_balance
11117           ,l_days_late
11118           ,l_display_order;
11119 
11120         EXIT WHEN c_trx_activities%NOTFOUND;
11121 
11122         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11123         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date  Act  Act_Amount   Theory_Bal  Actual_Bal  Days_Late');
11124         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_activity_date || '  ' || l_activity_code || '  ' || l_activity_amount || '  ' || l_theory_balance || '  ' || l_actual_balance || '  ' || l_days_late);
11125 
11126         l_theory_balance := l_theory_balance + p_CAP_AMOUNT;
11127         -- normal interest
11128         if l_activity_code = 'DISBURSEMENT' or l_activity_code = 'INVOICE_ADDED' then
11129             l_norm_prev_amount := l_theory_balance - l_activity_amount - p_adj_amount;
11130         end if;
11131 
11132         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating normal interest...');
11133         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_norm_prev_act_date || ' - ' || l_activity_date);
11134         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_norm_prev_amount);
11135         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11136 
11137         if (p_calc_method = 'SIMPLE') then
11138 
11139             -- recalculate periodic rate for each period if day counting methodolgy varies
11140 
11141             l_periodic_rate := lns_financials.getPeriodicRate(
11142                                     p_payment_freq      => p_payment_freq
11143                                     ,p_period_start_date => l_norm_prev_act_date
11144                                     ,p_period_end_date   => l_activity_date
11145                                     ,p_annualized_rate   => p_interest_rate
11146                                     ,p_days_count_method => p_day_count_method
11147                                     ,p_target            => 'INTEREST');
11148 
11149         elsif (p_calc_method = 'COMPOUND') then
11150 
11151             l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11152                             ,p_payment_freq => p_payment_freq
11153                             ,p_annualized_rate => p_interest_rate
11154                             ,p_period_start_date => l_norm_prev_act_date
11155                             ,p_period_end_date => l_activity_date
11156                             ,p_days_count_method => p_day_count_method
11157                             ,p_target => 'INTEREST');
11158 
11159         end if;
11160         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11161 
11162         l_norm_interest := lns_financials.calculateInterest(p_amount => l_norm_prev_amount
11163                                                     ,p_periodic_rate => l_periodic_rate
11164                                                     ,p_compounding_period => null);
11165         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'normal interest = ' || l_norm_interest);
11166 
11167         if trunc(l_norm_prev_act_date) <> trunc(l_activity_date) then
11168             if l_norm_int_detail_str is not null then
11169                 l_norm_int_detail_str := l_norm_int_detail_str || ' +<br>';
11170             end if;
11171             l_norm_int_detail_str := l_norm_int_detail_str ||
11172                 'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_norm_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11173                 ' * Balance ' || round(l_norm_prev_amount, l_precision) ||
11174                 ' * Rate ' || p_interest_rate || '%';
11175             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
11176         end if;
11177 
11178         l_cum_norm_interest := l_cum_norm_interest + l_norm_interest;
11179         if l_activity_code = 'DISBURSEMENT' or l_activity_code = 'INVOICE_ADDED' then
11180             l_norm_prev_amount := l_theory_balance - p_adj_amount;
11181         else
11182             l_norm_prev_amount := l_theory_balance;
11183         end if;
11184         l_norm_prev_act_date := l_activity_date;
11185         i := i + 1;
11186         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative normal interest = ' || l_cum_norm_interest);
11187 
11188     END LOOP;
11189     close c_trx_activities;
11190 
11191     -- manually adding last record for p_period_end_date date
11192     l_activity_date := p_period_end_date;
11193     l_activity_code := 'DUE';
11194     l_activity_amount := 0;
11195     l_days_late := 0;
11196 
11197     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11198     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date  Act  Act_Amount   Theory_Bal  Actual_Bal  Days_Late');
11199     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '*' || l_activity_date || '  ' || l_activity_code || '  ' || l_activity_amount || '  ' || l_theory_balance || '  ' || l_actual_balance || '  ' || l_days_late);
11200 
11201     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating normal interest...');
11202     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_norm_prev_act_date || ' - *' || l_activity_date);
11203     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_norm_prev_amount);
11204     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11205 
11206     -- normal interest
11207     if (p_calc_method = 'SIMPLE') then
11208 
11209         -- recalculate periodic rate for each period if day counting methodolgy varies
11210 
11211         l_periodic_rate := lns_financials.getPeriodicRate(
11212                                 p_payment_freq      => p_payment_freq
11213                                 ,p_period_start_date => l_norm_prev_act_date
11214                                 ,p_period_end_date   => l_activity_date
11215                                 ,p_annualized_rate   => p_interest_rate
11216                                 ,p_days_count_method => p_day_count_method
11217                                 ,p_target            => 'INTEREST');
11218     elsif (p_calc_method = 'COMPOUND') then
11219 
11220         l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11221                         ,p_payment_freq => p_payment_freq
11222                         ,p_annualized_rate => p_interest_rate
11223                         ,p_period_start_date => l_norm_prev_act_date
11224                         ,p_period_end_date => l_activity_date
11225                         ,p_days_count_method => p_day_count_method
11226                         ,p_target => 'INTEREST');
11227 
11228     end if;
11229     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11230 
11231     l_norm_interest := lns_financials.calculateInterest(p_amount => l_norm_prev_amount
11232                                                 ,p_periodic_rate => l_periodic_rate
11233                                                 ,p_compounding_period => null);
11234     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'normal interest = ' || l_norm_interest);
11235 
11236     if trunc(l_norm_prev_act_date) <> trunc(l_activity_date) then
11237         if l_norm_int_detail_str is not null then
11238             l_norm_int_detail_str := l_norm_int_detail_str || ' +<br>';
11239         end if;
11240         l_norm_int_detail_str := l_norm_int_detail_str ||
11241             'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_norm_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11242             ' * Balance ' || round(l_norm_prev_amount, l_precision) ||
11243             ' * Rate ' || p_interest_rate || '%';
11244         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_norm_int_detail_str);
11245     end if;
11246 
11247     l_cum_norm_interest := l_cum_norm_interest + l_norm_interest;
11248 
11249     x_norm_interest := round(l_cum_norm_interest, l_precision);
11250     x_norm_int_details := x_norm_interest || ' (' || l_norm_int_detail_str || ')';
11251 
11252     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Normal Interest = ' || x_norm_interest);
11253     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Normal Interest Details = ' || x_norm_int_details);
11254     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
11255     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11256 
11257 end;
11258 
11259 
11260 -- This procedure calculates additional and penal interest
11261 procedure CALC_ADD_INTEREST(p_loan_id               in  number,
11262                            p_calc_method           in  varchar2,
11263                            p_period_start_date     in  date,
11264                            p_period_end_date       in  date,
11265                            p_interest_rate         in  number,
11266                            p_day_count_method      in  varchar2,
11267                            p_payment_freq          in  varchar2,
11268                            p_compound_freq         in  varchar2,
11269                            p_penal_int_rate        in  number,
11270                            p_prev_grace_end_date   in  date,
11271                            p_grace_start_date      in  date,
11272                            p_grace_end_date        in  date,
11273                            p_target                in  varchar2,
11274                            x_add_interest          out NOCOPY number,
11275                            x_penal_interest        out NOCOPY number,
11276                            x_add_int_details       out NOCOPY varchar2,
11277                            x_penal_int_details     out NOCOPY varchar2)
11278 is
11279     l_api_name              varchar2(25);
11280     l_activity_date         date;
11281     l_activity_code         varchar2(30);
11282     l_activity_amount       number;
11283     l_theory_balance        number;
11284     l_actual_balance        number;
11285     l_days_late             number;
11286     l_display_order         number;
11287     l_rate                  number;
11288     l_day_count             number;
11289     i                       number;
11290     l_add_prev_amount       number;
11291     l_add_interest          number;
11292     l_add_prev_act_date     date;
11293     l_cum_add_interest      number;
11294     l_periodic_rate         number;
11295     l_penal_interest        number;
11296     l_cum_penal_interest    number;
11297     l_penal_period_rate     number;
11298     l_interest_rate         number;
11299     l_first_act_after_grace boolean;
11300     l_first_act_after_prev_grace    boolean;
11301     l_add_int_setting       varchar2(1);
11302     l_add_int_detail_str    varchar2(2000);
11303     l_penal_int_detail_str  varchar2(2000);
11304     l_penal_prev_act_date   date;
11305     l_precision             number;
11306 
11307     cursor c_trx_prin_activities(p_loan_id number, p_start_date date, p_end_date date) is
11308         select
11309         trunc(ACTIVITY_DATE),
11310         ACTIVITY_CODE,
11311         ACTIVITY_AMOUNT,
11312         INTEREST_RATE,
11313         THEORETICAL_BALANCE,
11314         ACTUAL_BALANCE,
11315         DAYS_LATE,
11316         display_order
11317         from LNS_PRIN_TRX_ACTIVITIES_V
11318         where loan_id = p_loan_id and
11319         trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
11320         trunc(ACTIVITY_DATE) < trunc(p_end_date) and
11321         ACTIVITY_CODE not in ('DISBURSEMENT', 'INVOICE_ADDED')
11322         order by activity_date, display_order;
11323 
11324     cursor c_trx_int_activities(p_loan_id number, p_start_date date, p_end_date date) is
11325         select
11326         trunc(ACTIVITY_DATE),
11327         ACTIVITY_CODE,
11328         ACTIVITY_AMOUNT,
11329         INTEREST_RATE,
11330         THEORETICAL_BALANCE,
11331         ACTUAL_BALANCE,
11332         DAYS_LATE,
11333         display_order
11334         from LNS_INT_TRX_ACTIVITIES_V
11335         where loan_id = p_loan_id and
11336         trunc(ACTIVITY_DATE) >= trunc(p_start_date) and
11337         trunc(ACTIVITY_DATE) < trunc(p_end_date)
11338         order by activity_date, display_order;
11339 
11340     cursor c_add_int_setting(p_loan_id number, p_target varchar2) is
11341         select decode(p_target, 'UNPAID_PRIN', nvl(term.CALC_ADD_INT_UNPAID_PRIN, 'Y'), 'UNPAID_INT', nvl(term.CALC_ADD_INT_UNPAID_INT, 'Y'))
11342         from lns_loan_headers loan,
11343         lns_terms term
11344         where loan.loan_id = p_loan_id and
11345         loan.loan_id = term.loan_id;
11346 
11347     cursor c_curr_precision(p_loan_id number) is
11348         select curr.precision
11349         from lns_loan_headers_all h
11350         ,fnd_currencies  curr
11351         where h.loan_id = p_loan_id
11352 	    and curr.currency_code = h.loan_currency;
11353 
11354 begin
11355 
11356     l_api_name  := 'CALC_ADD_INTEREST';
11357     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11358     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
11359     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
11360     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
11361     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
11362     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': start date: ' || p_period_start_date);
11363     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': end date: ' || p_period_end_date);
11364     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
11365     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
11366     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
11367     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
11368     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': target: ' || p_target);
11369     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': penal_int_rate: ' || p_penal_int_rate);
11370     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': prev_grace_end_date: ' || p_prev_grace_end_date);
11371     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': grace_start_date: ' || p_grace_start_date);
11372     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': grace_end_date: ' || p_grace_end_date);
11373 
11374     x_add_interest := 0;
11375     x_penal_interest := 0;
11376 
11377     -- fix for bug 8609721
11378     OPEN c_add_int_setting(p_loan_id, p_target);
11379     FETCH c_add_int_setting INTO l_add_int_setting;
11380     CLOSE c_add_int_setting;
11381     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_add_int_setting = ' || l_add_int_setting);
11382 
11383     if (l_add_int_setting = 'N' or p_interest_rate = 0) and p_penal_int_rate = 0 then  -- fix for bug 8609721
11384         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculate additional interest is off and penal interest rate = 0');
11385         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': exiting');
11386         return;
11387     end if;
11388 
11389     if p_period_start_date > p_period_end_date then
11390         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': x_add_interest: ' || x_add_interest);
11391         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': x_add_interest: ' || x_add_interest);
11392         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': exiting');
11393         return;
11394     end if;
11395 
11396     -- calculating normal and additional interest
11397     i := 1;
11398     l_add_interest := 0;
11399     l_cum_add_interest := 0;
11400     l_add_prev_amount := 0;
11401     l_add_prev_act_date := p_period_start_date;
11402     l_penal_interest := 0;
11403     l_cum_penal_interest := 0;
11404     l_interest_rate := 0;
11405     l_first_act_after_grace := true;
11406     l_first_act_after_prev_grace := true;
11407     l_penal_prev_act_date := p_grace_end_date;
11408 
11409     OPEN c_curr_precision(p_loan_id);
11410     FETCH c_curr_precision INTO l_precision;
11411     CLOSE c_curr_precision;
11412 
11413     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
11414 
11415     if p_target = 'UNPAID_PRIN' then
11416         OPEN c_trx_prin_activities(p_loan_id, p_period_start_date, p_period_end_date);
11417     elsif p_target = 'UNPAID_INT' then
11418         OPEN c_trx_int_activities(p_loan_id, p_period_start_date, p_period_end_date);
11419     end if;
11420 
11421     LOOP
11422 
11423         l_add_interest := 0;
11424         l_penal_interest := 0;
11425 
11426         if p_target = 'UNPAID_PRIN' then
11427             FETCH c_trx_prin_activities INTO
11428                 l_activity_date
11429                 ,l_activity_code
11430                 ,l_activity_amount
11431                 ,l_interest_rate
11432                 ,l_theory_balance
11433                 ,l_actual_balance
11434                 ,l_days_late
11435                 ,l_display_order;
11436 
11437             EXIT WHEN c_trx_prin_activities%NOTFOUND;
11438         elsif p_target = 'UNPAID_INT' then
11439             FETCH c_trx_int_activities INTO
11440                 l_activity_date
11441                 ,l_activity_code
11442                 ,l_activity_amount
11443                 ,l_interest_rate
11444                 ,l_theory_balance
11445                 ,l_actual_balance
11446                 ,l_days_late
11447                 ,l_display_order;
11448 
11449             EXIT WHEN c_trx_int_activities%NOTFOUND;
11450         end if;
11451 
11452         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11453         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date  Act  Act_Amount  Rate   Theory_Bal  Actual_Bal  Days_Late');
11454         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_activity_date || '  ' || l_activity_code || '  ' || l_activity_amount || '  ' || l_interest_rate || '  ' || l_theory_balance || '  ' || l_actual_balance || '  ' || l_days_late);
11455 
11456         if l_add_prev_amount >= 0 then
11457 
11458             if l_add_int_setting = 'Y' then  -- fix for bug 8609721
11459 
11460                 -- additional interest
11461                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating additional interest...');
11462                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - ' || l_activity_date);
11463                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11464                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11465 
11466                 if (p_calc_method = 'SIMPLE') then
11467 
11468                     -- recalculate periodic rate for each period if day counting methodolgy varies
11469 
11470                     l_periodic_rate := lns_financials.getPeriodicRate(
11471                                             p_payment_freq      => p_payment_freq
11472                                             ,p_period_start_date => l_add_prev_act_date
11473                                             ,p_period_end_date   => l_activity_date
11474                                             ,p_annualized_rate   => p_interest_rate
11475                                             ,p_days_count_method => p_day_count_method
11476                                             ,p_target            => 'INTEREST');
11477 
11478                 elsif (p_calc_method = 'COMPOUND') then
11479 
11480                     l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11481                                     ,p_payment_freq => p_payment_freq
11482                                     ,p_annualized_rate => p_interest_rate
11483                                     ,p_period_start_date => l_add_prev_act_date
11484                                     ,p_period_end_date => l_activity_date
11485                                     ,p_days_count_method => p_day_count_method
11486                                     ,p_target => 'INTEREST');
11487 
11488                 end if;
11489                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11490 
11491                 l_add_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11492                                                             ,p_periodic_rate => l_periodic_rate
11493                                                             ,p_compounding_period => null);
11494                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'additional interest = ' || l_add_interest);
11495 
11496                 if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11497                     if l_add_int_detail_str is not null then
11498                         l_add_int_detail_str := l_add_int_detail_str || ' +<br>';
11499                     end if;
11500                     l_add_int_detail_str := l_add_int_detail_str ||
11501                         'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11502                         ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11503                         ' * Rate ' || p_interest_rate || '%';
11504                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_add_int_detail_str);
11505                 end if;
11506 
11507             end if;
11508 
11509             if p_penal_int_rate > 0 and
11510             ((trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and trunc(l_activity_date) <= trunc(p_grace_start_date)) or
11511                 (trunc(l_activity_date) > trunc(p_grace_end_date)))
11512             then
11513 
11514                 if trunc(l_activity_date) > trunc(p_grace_end_date) and
11515                 l_first_act_after_grace = true
11516                 then
11517                     l_add_prev_act_date := p_grace_start_date;
11518                     l_first_act_after_grace := false;
11519                 elsif trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and
11520                     trunc(l_activity_date) <= trunc(p_grace_start_date) and
11521                     l_first_act_after_prev_grace = true
11522                 then
11523                     if trunc(p_prev_grace_end_date) < trunc(p_period_start_date) then
11524                         l_add_prev_act_date := p_period_start_date;
11525                     else
11526                         l_add_prev_act_date := p_prev_grace_end_date;
11527                     end if;
11528                     l_first_act_after_prev_grace := false;
11529                 end if;
11530 
11531                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating penal interest...');
11532                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - ' || l_activity_date);
11533                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11534                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_penal_int_rate);
11535 
11536                 -- calc penal interest rate
11537                 if (p_calc_method = 'SIMPLE') then
11538 
11539                     l_penal_period_rate := lns_financials.getPeriodicRate(
11540                                             p_payment_freq      => p_payment_freq
11541                                             ,p_period_start_date => l_add_prev_act_date
11542                                             ,p_period_end_date   => l_activity_date
11543                                             ,p_annualized_rate   => p_penal_int_rate
11544                                             ,p_days_count_method => p_day_count_method
11545                                             ,p_target            => 'INTEREST');
11546 
11547                 elsif (p_calc_method = 'COMPOUND') then
11548 
11549                     l_penal_period_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11550                                     ,p_payment_freq => p_payment_freq
11551                                     ,p_annualized_rate => p_penal_int_rate
11552                                     ,p_period_start_date => l_add_prev_act_date
11553                                     ,p_period_end_date => l_activity_date
11554                                     ,p_days_count_method => p_day_count_method
11555                                     ,p_target => 'INTEREST');
11556 
11557                 end if;
11558 
11559                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal periodic_rate = ' || l_penal_period_rate);
11560 
11561                 l_penal_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11562                                                             ,p_periodic_rate => l_penal_period_rate
11563                                                             ,p_compounding_period => null);
11564                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal interest = ' || l_penal_interest);
11565 
11566                 if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11567                     if l_penal_int_detail_str is not null then
11568                         l_penal_int_detail_str := l_penal_int_detail_str || ' +<br>';
11569                     end if;
11570                     l_penal_int_detail_str := l_penal_int_detail_str ||
11571                         'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11572                         ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11573                         ' * Rate ' || p_penal_int_rate || '%';
11574                     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_penal_int_detail_str);
11575                 end if;
11576             end if;
11577 
11578         else
11579             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Ignoring this record b/c l_add_prev_amount < 0');
11580         end if;
11581 
11582         l_cum_add_interest := l_cum_add_interest + l_add_interest;
11583         l_cum_penal_interest := l_cum_penal_interest + l_penal_interest;
11584         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative additional interest = ' || l_cum_add_interest);
11585         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'cumulative penal interest = ' || l_cum_penal_interest);
11586 
11587         if p_target = 'UNPAID_PRIN' then
11588             l_add_prev_amount := l_actual_balance - l_theory_balance;
11589         elsif p_target = 'UNPAID_INT' then
11590             l_add_prev_amount := l_theory_balance - l_actual_balance;
11591         end if;
11592 
11593         l_add_prev_act_date := l_activity_date;
11594         i := i + 1;
11595 
11596     END LOOP;
11597     if p_target = 'UNPAID_PRIN' then
11598         close c_trx_prin_activities;
11599     elsif p_target = 'UNPAID_INT' then
11600         close c_trx_int_activities;
11601     end if;
11602 
11603     -- manually adding last record for p_period_end_date date
11604     l_activity_date := p_period_end_date;
11605     l_activity_code := 'DUE';
11606     l_activity_amount := 0;
11607     l_days_late := 0;
11608     l_add_interest := 0;
11609     l_penal_interest := 0;
11610 /*
11611     if p_interest_rate is not null then
11612         l_interest_rate := p_interest_rate;
11613     end if;
11614 */
11615     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
11616     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Act_Date  Act  Act_Amount  Rate  Theory_Bal  Actual_Bal  Days_Late');
11617     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '*' || l_activity_date || '  ' || l_activity_code || '  ' || l_activity_amount || '  ' || l_interest_rate || '  ' || l_theory_balance || '  ' || l_actual_balance || '  ' || l_days_late);
11618 
11619     if l_add_prev_amount >= 0 then
11620         if l_add_int_setting = 'Y' then   -- fix for bug 8609721
11621 
11622             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating additional interest...');
11623             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - *' || l_activity_date);
11624             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11625             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
11626 
11627             -- additional interest
11628             if (p_calc_method = 'SIMPLE') then
11629 
11630                 -- recalculate periodic rate for each period if day counting methodolgy varies
11631 
11632                 l_periodic_rate := lns_financials.getPeriodicRate(
11633                                         p_payment_freq      => p_payment_freq
11634                                         ,p_period_start_date => l_add_prev_act_date
11635                                         ,p_period_end_date   => l_activity_date
11636                                         ,p_annualized_rate   => p_interest_rate
11637                                         ,p_days_count_method => p_day_count_method
11638                                         ,p_target            => 'INTEREST');
11639 
11640             elsif (p_calc_method = 'COMPOUND') then
11641 
11642                 l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11643                                 ,p_payment_freq => p_payment_freq
11644                                 ,p_annualized_rate => p_interest_rate
11645                                 ,p_period_start_date => l_add_prev_act_date
11646                                 ,p_period_end_date => l_activity_date
11647                                 ,p_days_count_method => p_day_count_method
11648                                 ,p_target => 'INTEREST');
11649 
11650             end if;
11651             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
11652 
11653             l_add_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11654                                                         ,p_periodic_rate => l_periodic_rate
11655                                                         ,p_compounding_period => null);
11656             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'additional interest = ' || l_add_interest);
11657 
11658             if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11659                 if l_add_int_detail_str is not null then
11660                     l_add_int_detail_str := l_add_int_detail_str || ' +<br>';
11661                 end if;
11662                 l_add_int_detail_str := l_add_int_detail_str ||
11663                     'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11664                     ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11665                     ' * Rate ' || p_interest_rate || '%';
11666                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_add_int_detail_str);
11667             end if;
11668 
11669         end if;
11670 
11671         if p_penal_int_rate > 0 and
11672         ((trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and trunc(l_activity_date) <= trunc(p_grace_start_date)) or
11673             (trunc(l_activity_date) > trunc(p_grace_end_date)))
11674         then
11675 
11676             if trunc(l_activity_date) > trunc(p_grace_end_date) and
11677             l_first_act_after_grace = true
11678             then
11679                 l_add_prev_act_date := p_grace_start_date;
11680                 l_first_act_after_grace := false;
11681             elsif trunc(l_activity_date) >= trunc(p_prev_grace_end_date) and
11682                 trunc(l_activity_date) <= trunc(p_grace_start_date) and
11683                 l_first_act_after_prev_grace = true
11684             then
11685                 if trunc(p_prev_grace_end_date) < trunc(p_period_start_date) then
11686                     l_add_prev_act_date := p_period_start_date;
11687                 else
11688                     l_add_prev_act_date := p_prev_grace_end_date;
11689                 end if;
11690                 l_first_act_after_prev_grace := false;
11691             end if;
11692 
11693             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating penal interest...');
11694             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_add_prev_act_date || ' - *' || l_activity_date);
11695             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_add_prev_amount);
11696             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_penal_int_rate);
11697 
11698             -- calc penal interest rate
11699             if (p_calc_method = 'SIMPLE') then
11700 
11701                 l_penal_period_rate := lns_financials.getPeriodicRate(
11702                                         p_payment_freq      => p_payment_freq
11703                                         ,p_period_start_date => l_add_prev_act_date
11704                                         ,p_period_end_date   => l_activity_date
11705                                         ,p_annualized_rate   => p_penal_int_rate
11706                                         ,p_days_count_method => p_day_count_method
11707                                         ,p_target            => 'INTEREST');
11708 
11709             elsif (p_calc_method = 'COMPOUND') then
11710 
11711                 l_penal_period_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
11712                                 ,p_payment_freq => p_payment_freq
11713                                 ,p_annualized_rate => p_penal_int_rate
11714                                 ,p_period_start_date => l_add_prev_act_date
11715                                 ,p_period_end_date => l_activity_date
11716                                 ,p_days_count_method => p_day_count_method
11717                                 ,p_target => 'INTEREST');
11718 
11719             end if;
11720 
11721             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal periodic_rate = ' || l_penal_period_rate);
11722 
11723             l_penal_interest := lns_financials.calculateInterest(p_amount => l_add_prev_amount
11724                                                         ,p_periodic_rate => l_penal_period_rate
11725                                                         ,p_compounding_period => null);
11726             logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'penal interest = ' || l_penal_interest);
11727 
11728             if trunc(l_add_prev_act_date) <> trunc(l_activity_date) then
11729                 if l_penal_int_detail_str is not null then
11730                     l_penal_int_detail_str := l_penal_int_detail_str || ' +<br>';
11731                 end if;
11732                 l_penal_int_detail_str := l_penal_int_detail_str ||
11733                     'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_add_prev_act_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_activity_date-1), 1) ||
11734                     ' * Balance ' || round(l_add_prev_amount, l_precision) ||
11735                     ' * Rate ' || p_penal_int_rate || '%';
11736                 logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_penal_int_detail_str);
11737             end if;
11738 
11739         end if;
11740 
11741     else
11742         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Ignoring this record b/c l_add_prev_amount < 0');
11743     end if;
11744 
11745     l_cum_add_interest := l_cum_add_interest + l_add_interest;
11746     l_cum_penal_interest := l_cum_penal_interest + l_penal_interest;
11747 
11748     x_add_interest := round(l_cum_add_interest, l_precision);
11749     x_penal_interest := round(l_cum_penal_interest, l_precision);
11750     if x_add_interest = 0 and l_add_int_detail_str is null then
11751         x_add_int_details := null;
11752     else
11753         x_add_int_details := x_add_interest || ' (' || l_add_int_detail_str || ')';
11754     end if;
11755     x_penal_int_details := l_penal_int_detail_str;
11756 
11757     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Additional Interest = ' || x_add_interest);
11758     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Additional Interest Details = ' || x_add_int_details);
11759 
11760     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Penal Interest = ' || x_penal_interest);
11761     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Penal Interest Details = ' || x_penal_int_details);
11762 
11763     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
11764     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11765 
11766 end;
11767 
11768 
11769 
11770 procedure get_char2num_conv_chars(x_chars_to_replace out nocopy varchar2, x_replace_chars out nocopy varchar2)
11771 is
11772     l_num number;
11773     l_str varchar2(10);
11774     l_char varchar2(1);
11775 BEGIN
11776 
11777     l_num := 123.12;
11778 
11779     select to_char(l_num) into l_str from dual;
11780     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'number 123.12 => string ' || l_str);
11781 
11782     l_char := substr(l_str, 4, 1);
11783     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'number . => char ' || l_char);
11784 
11785     x_chars_to_replace := ',.';
11786     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_chars_to_replace = ' || x_chars_to_replace);
11787     x_replace_chars := l_char || l_char;
11788     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'x_replace_chars = ' || x_replace_chars);
11789 
11790 END;
11791 
11792 
11793 
11794 -- this procedure loads original amortization schedule from agreement report
11795 procedure LOAD_ORIGINAL_SCHEDULE(p_loan_details in LNS_FINANCIALS.LOAN_DETAILS_REC,
11796                                  x_loan_amort_tbl out nocopy LNS_FINANCIALS.AMORTIZATION_TBL)
11797 is
11798 /*-----------------------------------------------------------------------+
11799  | Local Variable Declarations and initializations                       |
11800  +-----------------------------------------------------------------------*/
11801 
11802     l_api_name              CONSTANT VARCHAR2(30) := 'LOAD_ORIGINAL_SCHEDULE';
11803     l_clob                  CLOB;
11804     l_parser                dbms_xmlparser.Parser;
11805     l_doc                   dbms_xmldom.DOMDocument;
11806     l_nl                    dbms_xmldom.DOMNodeList;
11807     l_n                     dbms_xmldom.DOMNode;
11808     i                       number;
11809     l_data                  varchar2(2000);
11810     l_loan_id               number;
11811     l_period_start_date     date;
11812     l_replace_chars         varchar2(10);
11813     l_chars_to_replace      varchar2(10);
11814     l_adj                   number;
11815     l_FUNDED_AMOUNT         number;
11816     l_value                 varchar2(100);
11817     l_date_format           varchar2(20);
11818     l_unknown_date_format   varchar2(20);
11819 
11820     l_amort_tbl             LNS_FINANCIALS.AMORTIZATION_TBL;
11821     l_rate_schedule         LNS_FINANCIALS.RATE_SCHEDULE_TBL;
11822 
11823 /*-----------------------------------------------------------------------+
11824  | Cursor Declarations                                                   |
11825  +-----------------------------------------------------------------------*/
11826 
11827     CURSOR c_get_xml(p_loan_id NUMBER) IS
11828         SELECT nvl(DOCUMENT_XML, empty_clob())
11829         FROM LNS_LOAN_DOCUMENTS
11830         WHERE source_id = p_loan_id and
11831         SOURCE_TABLE = 'LNS_LOAN_HEADERS_ALL' and
11832         DOCUMENT_TYPE = 'LOAN_AGREEMENT' AND
11833         VERSION = 1;
11834 
11835 BEGIN
11836 
11837     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11838     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
11839 
11840     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Fetching clob...');
11841     l_clob := empty_clob();
11842     open c_get_xml(p_loan_details.LOAN_ID);
11843     fetch c_get_xml into l_clob;
11844     close c_get_xml;
11845     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'lenght = ' || length(l_clob));
11846 
11847     if length(l_clob) = 0 then
11848         x_loan_amort_tbl := l_amort_tbl;
11849         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Clob is empty. Returning.');
11850         return;
11851     end if;
11852 
11853     -- Create a parser.
11854     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Creating a parser...');
11855     l_parser := dbms_xmlparser.newParser;
11856 
11857     -- Parse the document and create a new DOM document.
11858     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Parsing the document and creating a new DOM document...');
11859     dbms_xmlparser.parseClob(l_parser, l_clob);
11860     l_doc := dbms_xmlparser.getDocument(l_parser);
11861 
11862     -- Free resources associated with the CLOB and Parser now they are no longer needed.
11863     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Freeing resources...');
11864     dbms_xmlparser.freeParser(l_parser);
11865 
11866     get_char2num_conv_chars(l_chars_to_replace, l_replace_chars);
11867 
11868     -- Get a list of all the RATE_SCHEDULE_ROW nodes in the document using the XPATH syntax.
11869     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Getting a list of all the RATE_SCHEDULE_ROW nodes...');
11870     l_nl := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(l_doc),'/LNSAGREEMENT/ROWSET/ROW/RATE_SCHEDULE/RATE_SCHEDULE_ROW');
11871     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11872     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Rate schedule:');
11873     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FROM   TO    RATE');
11874     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '----   ----  ----');
11875 
11876     i := 0;
11877     l_unknown_date_format := '?';
11878     FOR cur_emp IN 0 .. dbms_xmldom.getLength(l_nl) - 1 LOOP
11879         l_n := dbms_xmldom.item(l_nl, cur_emp);
11880         i := i+1;
11881 
11882         dbms_xslprocessor.valueOf(l_n,'INSTALLMENT_FROM/text()',l_data);
11883         l_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11884         dbms_xslprocessor.valueOf(l_n,'INSTALLMENT_TO/text()',l_data);
11885         l_rate_schedule(i).END_INSTALLMENT_NUMBER := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11886         dbms_xslprocessor.valueOf(l_n,'INTEREST_RATE/text()',l_data);
11887         l_rate_schedule(i).ANNUAL_RATE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11888 
11889         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME,
11890                     l_rate_schedule(i).BEGIN_INSTALLMENT_NUMBER || '  ' ||
11891                     l_rate_schedule(i).END_INSTALLMENT_NUMBER || '  ' ||
11892                     l_rate_schedule(i).ANNUAL_RATE);
11893     END LOOP;
11894 
11895     -- Get a list of all the AMORTIZATION_ROW nodes in the document using the XPATH syntax.
11896     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Getting a list of all the AMORTIZATION_ROW nodes...');
11897     l_nl := dbms_xslprocessor.selectNodes(dbms_xmldom.makeNode(l_doc),'/LNSAGREEMENT/ROWSET/ROW/AMORTIZATION/AMORTIZATION_ROW');
11898 
11899     -- Loop through the list and create a new record in a tble collection
11900     -- for each EMP record.
11901 
11902     i := 0;
11903     l_period_start_date := p_loan_details.LOAN_START_DATE;
11904     l_FUNDED_AMOUNT := 0;
11905     FOR cur_emp IN 0 .. dbms_xmldom.getLength(l_nl) - 1 LOOP
11906         l_n := dbms_xmldom.item(l_nl, cur_emp);
11907         i := i+1;
11908 
11909         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
11910 
11911         -- Use XPATH syntax to assign values to he elements of the collection.
11912         dbms_xslprocessor.valueOf(l_n,'PAYMENT_NUMBER/text()',l_data);
11913         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_NUMBER data = ' || l_data);
11914         l_amort_tbl(i).INSTALLMENT_NUMBER := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11915 
11916         dbms_xslprocessor.valueOf(l_n,'DUE_DATE/text()',l_data);
11917         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DUE_DATE data = ' || l_data);
11918 
11919         if l_date_format is null then
11920             -- convert due date logic:
11921             -- 1. trying 11i format DD-MON-RRRR
11922             -- 2. trying old R12 format MM/DD/YYYY
11923             -- 3. trying new R12 format YYYY-MM-DD
11924             BEGIN
11925                 l_date_format := 'DD-MON-RRRR';   -- 11i code used fnd_date.date_to_chardate api which used this hardcoded date format
11926                 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Trying to convert using 11i format ' || l_date_format || '...');
11927                 l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11928                 LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Success!');
11929             EXCEPTION
11930                 WHEN OTHERS THEN
11931                 BEGIN
11932                     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Failed. ERROR: ' || sqlerrm);
11933                     l_date_format := 'MM/DD/YYYY';
11934                     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Trying to convert using old R12 format ' || l_date_format || '...');
11935                     l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11936                     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Success!');
11937                 EXCEPTION
11938                     WHEN OTHERS THEN
11939                     BEGIN
11940                         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Failed. ERROR: ' || sqlerrm);
11941                         l_date_format := 'YYYY-MM-DD';
11942                         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Trying to convert using new R12 format ' || l_date_format || '...');
11943                         l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11944                         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Success!');
11945                     EXCEPTION
11946                         WHEN OTHERS THEN
11947                             LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Failed. ERROR: ' || sqlerrm);
11948                             LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Oh well, we tried hard. Unknown date format. No due date then :(');
11949                             l_amort_tbl(i).DUE_DATE := to_date(null);
11950                             l_date_format := l_unknown_date_format;
11951                     END;
11952                 END;
11953             END;
11954         elsif l_date_format = l_unknown_date_format then
11955             LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Date format is unknown, setting due date to null');
11956             l_amort_tbl(i).DUE_DATE := to_date(null);
11957         else
11958             LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Date format = ' || l_date_format);
11959             l_amort_tbl(i).DUE_DATE := to_date(l_data, l_date_format);
11960             LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Due date is converted successfully');
11961         end if;
11962 
11963         dbms_xslprocessor.valueOf(l_n,'PAYMENT_PRINCIPAL/text()',l_data);
11964         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_PRINCIPAL data = ' || l_data);
11965         l_amort_tbl(i).PRINCIPAL_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11966 
11967         dbms_xslprocessor.valueOf(l_n,'PAYMENT_INTEREST/text()',l_data);
11968         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_INTEREST data = ' || l_data);
11969         l_amort_tbl(i).INTEREST_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11970 
11971         dbms_xslprocessor.valueOf(l_n,'PAYMENT_FEES/text()',l_data);
11972         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_FEES data = ' || l_data);
11973         l_amort_tbl(i).FEE_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11974 
11975         dbms_xslprocessor.valueOf(l_n,'OTHER_AMOUNT/text()',l_data);
11976         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'OTHER_AMOUNT data = ' || l_data);
11977         l_amort_tbl(i).OTHER_AMOUNT := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11978 
11979         dbms_xslprocessor.valueOf(l_n,'PAYMENT_TOTAL/text()',l_data);
11980         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PAYMENT_TOTAL data = ' || l_data);
11981         l_amort_tbl(i).TOTAL := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11982 
11983         dbms_xslprocessor.valueOf(l_n,'BEGINNING_BALANCE/text()',l_data);
11984         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'BEGINNING_BALANCE data = ' || l_data);
11985         l_amort_tbl(i).BEGIN_BALANCE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11986 
11987         dbms_xslprocessor.valueOf(l_n,'ENDING_BALANCE/text()',l_data);
11988         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'ENDING_BALANCE data = ' || l_data);
11989         l_amort_tbl(i).END_BALANCE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11990 
11991         dbms_xslprocessor.valueOf(l_n,'INTEREST_CUMULATIVE/text()',l_data);
11992         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'INTEREST_CUMULATIVE data = ' || l_data);
11993         l_amort_tbl(i).INTEREST_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11994 
11995         dbms_xslprocessor.valueOf(l_n,'PRINCIPAL_CUMULATIVE/text()',l_data);
11996         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PRINCIPAL_CUMULATIVE data = ' || l_data);
11997         l_amort_tbl(i).PRINCIPAL_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
11998 
11999         dbms_xslprocessor.valueOf(l_n,'FEES_CUMULATIVE/text()',l_data);
12000         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'FEES_CUMULATIVE data = ' || l_data);
12001         l_amort_tbl(i).FEES_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
12002 
12003         dbms_xslprocessor.valueOf(l_n,'OTHER_CUMULATIVE/text()',l_data);
12004         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'OTHER_CUMULATIVE data = ' || l_data);
12005         l_amort_tbl(i).OTHER_CUMULATIVE := to_number(nvl(translate(l_data, l_chars_to_replace, l_replace_chars), 0));
12006 
12007         dbms_xslprocessor.valueOf(l_n,'SOURCE/text()',l_data);
12008         l_amort_tbl(i).SOURCE := l_data;
12009 
12010         dbms_xslprocessor.valueOf(l_n,'NORMAL_INT_AMOUNT/text()',l_data);
12011         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT data = ' || l_data);
12012         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12013         if l_value is not null then
12014             l_amort_tbl(i).NORMAL_INT_AMOUNT := to_number(l_value);
12015         else
12016             l_amort_tbl(i).NORMAL_INT_AMOUNT := l_amort_tbl(i).INTEREST_AMOUNT;
12017         end if;
12018         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_AMOUNT = ' || l_amort_tbl(i).NORMAL_INT_AMOUNT);
12019 
12020         dbms_xslprocessor.valueOf(l_n,'PREV_DEFERRED_INT_AMOUNT/text()',l_data);
12021         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_DEFERRED_INT_AMOUNT data = ' || l_data);
12022         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12023         if l_value is not null then
12024             l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT := to_number(l_value);
12025         else
12026             l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT := 0;
12027         end if;
12028         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_DEFERRED_INT_AMOUNT = ' || l_amort_tbl(i).PREV_DEFERRED_INT_AMOUNT);
12029 
12030         dbms_xslprocessor.valueOf(l_n,'DEFERRED_INT_AMOUNT/text()',l_data);
12031         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DEFERRED_INT_AMOUNT data = ' || l_data);
12032         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12033         if l_value is not null then
12034             l_amort_tbl(i).DEFERRED_INT_AMOUNT := to_number(l_value);
12035         else
12036             l_amort_tbl(i).DEFERRED_INT_AMOUNT := 0;
12037         end if;
12038         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DEFERRED_INT_AMOUNT = ' || l_amort_tbl(i).DEFERRED_INT_AMOUNT);
12039 
12040         dbms_xslprocessor.valueOf(l_n,'PREV_CAP_INT_AMOUNT/text()',l_data);
12041         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT data = ' || l_data);
12042         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12043         if l_value is not null then
12044             l_amort_tbl(i).PREV_CAP_INT_AMOUNT := to_number(l_value);
12045         else
12046             l_amort_tbl(i).PREV_CAP_INT_AMOUNT := 0;
12047         end if;
12048         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PREV_CAP_INT_AMOUNT = ' || l_amort_tbl(i).PREV_CAP_INT_AMOUNT);
12049 
12050         dbms_xslprocessor.valueOf(l_n,'CURR_CAP_INT_AMOUNT/text()',l_data);
12051         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT data = ' || l_data);
12052         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12053         if l_value is not null then
12054             l_amort_tbl(i).CURR_CAP_INT_AMOUNT := to_number(l_value);
12055         else
12056             l_amort_tbl(i).CURR_CAP_INT_AMOUNT := 0;
12057         end if;
12058         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CURR_CAP_INT_AMOUNT = ' || l_amort_tbl(i).CURR_CAP_INT_AMOUNT);
12059 
12060         dbms_xslprocessor.valueOf(l_n,'CAP_INT_AMOUNT/text()',l_data);
12061         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT data = ' || l_data);
12062         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12063         if l_value is not null then
12064             l_amort_tbl(i).CAP_INT_AMOUNT := to_number(l_value);
12065         else
12066             l_amort_tbl(i).CAP_INT_AMOUNT := 0;
12067         end if;
12068         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_AMOUNT = ' || l_amort_tbl(i).CAP_INT_AMOUNT);
12069 
12070         dbms_xslprocessor.valueOf(l_n,'NORMAL_INT_DETAILS/text()',l_data);
12071         l_amort_tbl(i).NORMAL_INT_DETAILS := l_data;
12072         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'NORMAL_INT_DETAILS = ' || l_amort_tbl(i).NORMAL_INT_DETAILS);
12073 
12074         dbms_xslprocessor.valueOf(l_n,'DEFERRED_INT_DETAILS/text()',l_data);
12075         l_amort_tbl(i).DEFERRED_INT_DETAILS := l_data;
12076         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DEFERRED_INT_DETAILS = ' || l_amort_tbl(i).DEFERRED_INT_DETAILS);
12077 
12078         dbms_xslprocessor.valueOf(l_n,'CAP_INT_DETAILS/text()',l_data);
12079         l_amort_tbl(i).CAP_INT_DETAILS := l_data;
12080         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'CAP_INT_DETAILS = ' || l_amort_tbl(i).CAP_INT_DETAILS);
12081 
12082         dbms_xslprocessor.valueOf(l_n,'DISBURSEMENT_AMOUNT/text()',l_data);
12083         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DISBURSEMENT_AMOUNT data = ' || l_data);
12084         l_value := translate(l_data, l_chars_to_replace, l_replace_chars);
12085         if l_value is not null then
12086             l_amort_tbl(i).DISBURSEMENT_AMOUNT := to_number(l_value);
12087         else
12088             if l_amort_tbl(i).INSTALLMENT_NUMBER = 0 or l_amort_tbl(i).INSTALLMENT_NUMBER = 1 then
12089                 l_adj := 0;
12090             else
12091                 l_adj := l_amort_tbl(i-1).END_BALANCE;
12092             end if;
12093             l_amort_tbl(i).DISBURSEMENT_AMOUNT  :=
12094                 abs(l_amort_tbl(i).BEGIN_BALANCE - l_amort_tbl(i).END_BALANCE - l_amort_tbl(i).PRINCIPAL_AMOUNT) +
12095                 (l_amort_tbl(i).BEGIN_BALANCE - l_adj);
12096         end if;
12097         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'DISBURSEMENT_AMOUNT = ' || l_amort_tbl(i).DISBURSEMENT_AMOUNT);
12098 
12099         FOR j IN 1 .. l_rate_schedule.count LOOP
12100             if l_amort_tbl(i).INSTALLMENT_NUMBER >= l_rate_schedule(j).BEGIN_INSTALLMENT_NUMBER and
12101                 l_amort_tbl(i).INSTALLMENT_NUMBER <= l_rate_schedule(j).END_INSTALLMENT_NUMBER
12102             then
12103                 l_amort_tbl(i).INTEREST_RATE := l_rate_schedule(j).ANNUAL_RATE;
12104                 exit;
12105             end if;
12106         END LOOP;
12107 
12108         l_amort_tbl(i).PERIOD_START_DATE    := l_period_start_date;
12109         l_amort_tbl(i).PERIOD_END_DATE      := l_amort_tbl(i).DUE_DATE;
12110         l_amort_tbl(i).UNPAID_PRIN          := 0;
12111         l_amort_tbl(i).UNPAID_INT           := 0;
12112         l_amort_tbl(i).ADD_PRIN_INT_AMOUNT  := 0;
12113         l_amort_tbl(i).ADD_INT_INT_AMOUNT   := 0;
12114         l_amort_tbl(i).PENAL_INT_AMOUNT     := 0;
12115         l_amort_tbl(i).EARLY_PAY_CR_AMOUNT  := 0;
12116 
12117         if l_amort_tbl(i).INSTALLMENT_NUMBER = 0 then
12118             l_amort_tbl(i).INTEREST_RATE := l_rate_schedule(1).ANNUAL_RATE;
12119             l_amort_tbl(i).PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_amort_tbl(i).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE(l_amort_tbl(i).PERIOD_START_DATE, 1);
12120         else
12121             l_amort_tbl(i).PERIOD := FND_DATE.DATE_TO_DISPLAYDATE(l_amort_tbl(i).PERIOD_START_DATE, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_amort_tbl(i).DUE_DATE-1), 1);
12122         end if;
12123 
12124         l_amort_tbl(i).FUNDED_AMOUNT := l_FUNDED_AMOUNT + l_amort_tbl(i).DISBURSEMENT_AMOUNT;
12125         l_FUNDED_AMOUNT := l_amort_tbl(i).FUNDED_AMOUNT;
12126         l_period_start_date := l_amort_tbl(i).PERIOD_END_DATE;
12127 
12128     END LOOP;
12129 
12130     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
12131     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Original amortization schedule:');
12132     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'PN   DD       RATE  BB      PAY     PRIN    INT     FEE     OTHER   EB');
12133     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '---  -------  ----  ------  ------  ------  ------  ------  ------  ------');
12134 
12135     FOR i IN 1 .. l_amort_tbl.count LOOP
12136         LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME,
12137                     l_amort_tbl(i).INSTALLMENT_NUMBER || '  ' ||
12138                     l_amort_tbl(i).DUE_DATE || '  ' ||
12139                     l_amort_tbl(i).INTEREST_RATE || '  ' ||
12140                     l_amort_tbl(i).BEGIN_BALANCE  || '  ' ||
12141                     l_amort_tbl(i).TOTAL || '  ' ||
12142                     l_amort_tbl(i).PRINCIPAL_AMOUNT || '  ' ||
12143                     l_amort_tbl(i).INTEREST_AMOUNT  || '  ' ||
12144                     l_amort_tbl(i).FEE_AMOUNT  || '  ' ||
12145                     l_amort_tbl(i).OTHER_AMOUNT  || '  ' ||
12146                     l_amort_tbl(i).END_BALANCE);
12147     END LOOP;
12148 
12149     -- Free any resources associated with the document now it
12150     -- is no longer needed.
12151     LogMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Freeing resources...');
12152     dbms_xmldom.freeDocument(l_doc);
12153     dbms_xmlparser.freeParser(l_parser);
12154 
12155     x_loan_amort_tbl := l_amort_tbl;
12156     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
12157 
12158 EXCEPTION
12159     WHEN OTHERS THEN
12160         LogMessage(FND_LOG.LEVEL_UNEXPECTED, G_PKG_NAME, ' - in exception. Error: ' || sqlerrm);
12161         --dbms_lob.freetemporary(l_clob);
12162         dbms_xmlparser.freeParser(l_parser);
12163         dbms_xmldom.freeDocument(l_doc);
12164         FND_MESSAGE.SET_NAME('LNS', 'LNS_API_OTHERS_EXCEP');
12165         FND_MESSAGE.SET_TOKEN('ERROR' ,sqlerrm);
12166         FND_MSG_PUB.Add;
12167 END;
12168 
12169 
12170 -- This procedure calculates interest credit on early payment
12171 procedure CALC_EARLY_PAY_CR(p_loan_id               in  number,
12172                            p_calc_method           in  varchar2,
12173                            p_installment           in  number,
12174                            p_interest_rate         in  number,
12175                            p_day_count_method      in  varchar2,
12176                            p_payment_freq          in  varchar2,
12177                            p_compound_freq         in  varchar2,
12178                            x_early_pay_cr          out NOCOPY number,
12179                            x_EARLY_PAY_CR_DETAILS  out NOCOPY varchar2)
12180 is
12181     l_api_name              varchar2(25);
12182     l_activity_code         varchar2(30);
12183     l_activity_amount       number;
12184     l_theory_balance        number;
12185     l_actual_balance        number;
12186     l_days_late             number;
12187     l_display_order         number;
12188     i                       number;
12189     l_from_date             date;
12190     l_to_date               date;
12191     l_cr_amount             number;
12192     l_cum_cr_amount         number;
12193     l_cr_detail_str        varchar2(2000);
12194     l_periodic_rate         number;
12195     l_precision             number;
12196     l_early_pay_setting     varchar2(1);
12197     l_amount                number;
12198 
12199     cursor c_early_payments(p_loan_id number, p_payment_number number) is
12200         select
12201         trunc(ACTIVITY_DATE),
12202         trunc(DUE_DATE),
12203         ACTIVITY_CODE,
12204         ACTIVITY_AMOUNT,
12205         THEORETICAL_BALANCE,
12206         ACTUAL_BALANCE,
12207         DAYS_LATE,
12208         display_order
12209         from LNS_PRIN_TRX_ACTIVITIES_V
12210         where loan_id = p_loan_id and
12211         payment_number = p_payment_number and
12212         DAYS_LATE < 0 and
12213         ACTIVITY_CODE in ('PMT', 'CM', 'ADJUSTMENT')
12214         order by activity_date, display_order, LOAN_AMORTIZATION_ID;
12215 
12216     cursor c_early_payment_setting(p_loan_id number) is
12217         select nvl(term.CALC_EARLY_PAY_CR, 'N')
12218         from lns_loan_headers loan,
12219         lns_terms term
12220         where loan.loan_id = p_loan_id and
12221         loan.loan_id = term.loan_id;
12222 
12223     cursor c_curr_precision(p_loan_id number) is
12224         select curr.precision
12225         from lns_loan_headers_all h
12226         ,fnd_currencies  curr
12227         where h.loan_id = p_loan_id
12228 	    and curr.currency_code = h.loan_currency;
12229 
12230 begin
12231 
12232     l_api_name  := 'CALC_EARLY_PAY_CR';
12233     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
12234     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - BEGIN');
12235     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Input:');
12236     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': loan_id: ' || p_loan_id);
12237     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': calc_method: ' || p_calc_method);
12238     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': installment: ' || p_installment);
12239     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': interest rate: ' || p_interest_rate);
12240     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': days count method: ' || p_day_count_method);
12241     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': compound frequency: ' || p_compound_freq);
12242     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': payment frequency: ' || p_payment_freq);
12243 
12244     i := 1;
12245     l_cr_amount := 0;
12246     l_cum_cr_amount := 0;
12247     x_early_pay_cr := 0;
12248 
12249     -- checking for setting
12250     OPEN c_early_payment_setting(p_loan_id);
12251     FETCH c_early_payment_setting INTO l_early_pay_setting;
12252     CLOSE c_early_payment_setting;
12253     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': l_early_pay_setting = ' || l_early_pay_setting);
12254 
12255     if l_early_pay_setting = 'N' then
12256         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Calculate Interest Credit on Early Payments is off. Exiting');
12257         return;
12258     end if;
12259 
12260     OPEN c_curr_precision(p_loan_id);
12261     FETCH c_curr_precision INTO l_precision;
12262     CLOSE c_curr_precision;
12263 
12264     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Querying trx history...');
12265 
12266     OPEN c_early_payments(p_loan_id, p_installment-1);
12267     LOOP
12268 
12269         FETCH c_early_payments INTO
12270           l_from_date
12271           ,l_to_date
12272           ,l_activity_code
12273           ,l_activity_amount
12274           ,l_theory_balance
12275           ,l_actual_balance
12276           ,l_days_late
12277           ,l_display_order;
12278 
12279         EXIT WHEN c_early_payments%NOTFOUND;
12280 
12281         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, '--------- Record ' || i || '---------');
12282         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'From_Date  To_Date  Act  Act_Amount   Theory_Bal  Actual_Bal  Days_Late');
12283         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_from_date || '  ' || l_to_date || '  ' ||
12284             l_activity_code || '  ' || l_activity_amount || '  ' || l_theory_balance || '  ' || l_actual_balance || '  ' || l_days_late);
12285 
12286         l_amount := abs(l_theory_balance - l_actual_balance);
12287         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculating amount...');
12288         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Period = ' || l_from_date || ' - ' || l_to_date);
12289         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Amount = ' || l_amount);
12290         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Interest Rate = ' || p_interest_rate);
12291 
12292         if (p_calc_method = 'SIMPLE') then
12293 
12294             -- recalculate periodic rate for each period if day counting methodolgy varies
12295 
12296             l_periodic_rate := lns_financials.getPeriodicRate(
12297                                     p_payment_freq      => p_payment_freq
12298                                     ,p_period_start_date => l_from_date
12299                                     ,p_period_end_date   => l_to_date
12300                                     ,p_annualized_rate   => p_interest_rate
12301                                     ,p_days_count_method => p_day_count_method
12302                                     ,p_target            => 'INTEREST');
12303 
12304         elsif (p_calc_method = 'COMPOUND') then
12305 
12306             l_periodic_rate := getCompoundPeriodicRate(p_compound_freq => p_compound_freq
12307                             ,p_payment_freq => p_payment_freq
12308                             ,p_annualized_rate => p_interest_rate
12309                             ,p_period_start_date => l_from_date
12310                             ,p_period_end_date => l_to_date
12311                             ,p_days_count_method => p_day_count_method
12312                             ,p_target => 'INTEREST');
12313 
12314         end if;
12315         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'periodic_rate = ' || l_periodic_rate);
12316 
12317         l_cr_amount := lns_financials.calculateInterest(p_amount => l_amount
12318                                                     ,p_periodic_rate => l_periodic_rate
12319                                                     ,p_compounding_period => null);
12320         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Calculated credit amount = ' || l_cr_amount);
12321 
12322         if l_cr_detail_str is not null then
12323             l_cr_detail_str := l_cr_detail_str || ' +<br>';
12324         end if;
12325         l_cr_detail_str := l_cr_detail_str ||
12326             'Period ' || FND_DATE.DATE_TO_DISPLAYDATE(l_from_date, 1) || ' - ' || FND_DATE.DATE_TO_DISPLAYDATE((l_to_date-1), 1) ||
12327             ' * Balance ' || round(l_amount, l_precision) ||
12328             ' * Rate ' || p_interest_rate || '%';
12329         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_cr_detail_str);
12330 
12331         l_cum_cr_amount := l_cum_cr_amount + l_cr_amount;
12332         i := i + 1;
12333         logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, 'Cumulative credit amount = ' || l_cum_cr_amount);
12334 
12335     END LOOP;
12336     close c_early_payments;
12337 
12338     x_early_pay_cr := round(l_cum_cr_amount, l_precision);
12339     if l_cr_detail_str is not null then
12340         l_cr_detail_str := ' (' || l_cr_detail_str || ')';
12341     end if;
12342 
12343     x_EARLY_PAY_CR_DETAILS := x_early_pay_cr || l_cr_detail_str;
12344 
12345     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Credit Amount = ' || x_early_pay_cr);
12346     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, l_api_name || ': Total Credit Amount Details = ' || x_EARLY_PAY_CR_DETAILS);
12347     logMessage(FND_LOG.LEVEL_PROCEDURE, G_PKG_NAME, l_api_name || ' - END');
12348     logMessage(FND_LOG.LEVEL_STATEMENT, G_PKG_NAME, ' ');
12349 
12350 end;
12351 
12352 
12353 
12354 END LNS_FINANCIALS;