DBA Data[Home] [Help]

PACKAGE BODY: APPS.AP_INVOICE_LINES_UTILITY_PKG

Source


1 PACKAGE BODY AP_INVOICE_LINES_UTILITY_PKG AS
2 /* $Header: apilnutb.pls 120.48.12020000.3 2013/02/13 23:28:37 tjbhatt ship $ */
3 
4 /*=============================================================================
5  |  FUNCTION - get_encumbered_flag()
6  |
7  |  DESCRIPTION
8  |      returns the invoice-level encumbrance status of an invoice.
9  |      Establish the invoice line level encumbrance flag.
10  |      Function will return one of the following statuses
11  |       'Y' - Fully encumbered
12  |       'P' - One or more distributions is encumbered, but not all
13  |       'N' - No distributions are encumbered
14  |       ''  - Budgetary control disabled
15  |  PARAMETERS
16  |      p_invoice_id - invoice id
17  |      p_line_number - invoice line number
18  |
19  |  NOTES
20  |      -- Meaning of distribution encumbrance_flag:
21  |      -- Y: Regular line, has already been successfully encumbered by AP.
22  |      -- W: Regular line, has been encumbered in advisory mode even though
23  |      --    insufficient funds existed.
24  |      -- H: Line has not been encumbered yet, since it was put on hold.
25  |      -- N or Null : Line not yet seen by this code.
26  |      -- D: Same as Y for reversal distribution line.
27  |      -- X: Same as W for reversal distribution line.
28  |      -- P: Same as H for reversal distribution line.
29  |      -- R: Same as N for reversal distribution line.
30  |
31  |  MODIFICATION HISTORY
32  |  Date         Author             Description of Change
33  |
34  *============================================================================*/
35 
36     FUNCTION get_encumbered_flag(
37                  p_invoice_id  IN  NUMBER,
38                  p_line_number IN  NUMBER )
39     RETURN VARCHAR2
40     IS
41       l_purch_encumbrance_flag    VARCHAR2(1) := '';
42       l_encumbered_flag           VARCHAR2(1) := '';
43       l_distribution_count        number      := 0;
44       l_encumbered_count          number      := 0;
45       l_org_id                    FINANCIALS_SYSTEM_PARAMS_ALL.ORG_ID%TYPE;
46 
47       CURSOR encumbrance_flag_cursor is
48       SELECT nvl(encumbered_flag,'N')
49       FROM   ap_invoice_distributions
50       WHERE  invoice_id = p_invoice_id
51         AND  invoice_line_number = p_line_number;
52     BEGIN
53 
54 
55     -- Added the IF condition for the bug 8763038
56     IF ( p_invoice_id IS NOT NULL ) THEN
57 
58       SELECT NVL(fsp.purch_encumbrance_flag,'N'),
59              ai.org_id
60         INTO l_purch_encumbrance_flag,
61              l_org_id
62         FROM ap_invoices_all ai,
63              financials_system_params_all fsp
64        WHERE ai.invoice_id = p_invoice_id
65          AND ai.org_id = fsp.org_id;
66 
67       IF (l_purch_encumbrance_flag = 'N') THEN
68         RETURN(NULL);
69       END IF;
70 
71       OPEN encumbrance_flag_cursor;
72       LOOP
73       FETCH encumbrance_flag_cursor INTO l_encumbered_flag;
74       EXIT WHEN encumbrance_flag_cursor%NOTFOUND;
75         IF (l_encumbered_flag in ('Y','D', 'W','X')) THEN
76           l_encumbered_count := l_encumbered_count + 1;
77         END IF;
78           l_distribution_count := l_distribution_count + 1;
79       END LOOP;
80 
81       IF (l_encumbered_count > 0) THEN
82         -- At least one distribution is encumbered
83         IF (l_distribution_count = l_encumbered_count) THEN
84           -- Invoice Line is fully encumbered
85           RETURN('Y');
86         ELSE
87           -- Invoice Line is partially encumbered
88           RETURN('P');
89         END IF;
90       ELSE
91         -- No distributions are encumbered
92         RETURN('N');
93       END IF;
94 
95      ELSE
96 
97         RETURN(NULL);
98 
99      END IF; -- Bug 8763038
100 
101      END get_encumbered_flag;
102 
103 
104 /*=============================================================================
105  |  FUNCTION -  get_posting_status
106  |
107  |  DESCRIPTION
108  |      returns the invoice line posting status.
109  |
110  |  PARAMETER
111  |      p_invoice_id - invoice id
112  |      p_line_number - invoice line number
113  |
114  |  NOTES
115  |      'Y' - Posted
116  |      'S' - Selected
117  |      'P' - Partial
118  |      'N' - Unposted
119  |      ---------------------------------------------------------------------
120  |      -- Declare cursor to establish the invoice-level posting flag
121  |      --
122  |      -- The first two selects simply look at the posting flags (cash and/or
123  |      -- accrual) for the distributions.  The rest is to cover one specific
124  |      -- case when some of the distributions are fully posting (Y) and some
125  |      -- are unposting (N).  The status should be partial (P).
126  |      --
127  |      -- MOAC.  Use ap_invoice_distributions_all table instead of SO view
128  |      -- since this procedure is called when policy context is not set to
129  |      -- the corresponding OU for the invoice_id
130  |
131  |  MODIFICATION HISTORY
132  |  Date         Author             Description of Change
133  |  28-MAY-04    yicao              SLA Obsolescence: Remove some accounting
134  |                                  related options
135  *============================================================================*/
136    FUNCTION get_posting_status(
137                  p_invoice_id   IN NUMBER,
138                  p_line_number  IN NUMBER )
139     RETURN VARCHAR2
140     IS
141 
142       invoice_line_posting_flag           VARCHAR2(1);
143       distribution_posting_flag           VARCHAR2(1);
144       l_cash_basis_flag                   VARCHAR2(1);
145       l_org_id                            AP_SYSTEM_PARAMETERS_ALL.ORG_ID%TYPE;
146 
147 
148       CURSOR posting_cursor IS
149       SELECT cash_posted_flag
150       FROM   ap_invoice_distributions_all
151       WHERE  invoice_id = p_invoice_id
152       AND    invoice_line_number = p_line_number
153       AND    l_cash_basis_flag = 'Y'
154       UNION
155       SELECT accrual_posted_flag
156       FROM   ap_invoice_distributions_all
157       WHERE  invoice_id = p_invoice_id
158       AND    invoice_line_number = p_line_number
159       AND    l_cash_basis_flag <> 'Y'
160       UNION
161       SELECT 'P'
162       FROM   ap_invoice_distributions_all
163       WHERE  invoice_id = p_invoice_id
164       AND    invoice_line_number = p_line_number
165       AND    ( (cash_posted_flag  = 'Y'
166                 AND l_cash_basis_flag = 'Y')
167               OR
168                 (accrual_posted_flag = 'Y'
169                  AND l_cash_basis_flag <> 'Y'))
170       AND EXISTS
171                (SELECT 'An N is also in the valid flags'
172                 FROM   ap_invoice_distributions_all
173                 WHERE  invoice_id = p_invoice_id
174                 AND    invoice_line_number = p_line_number
175                 AND    ((cash_posted_flag  = 'N'
176                          AND l_cash_basis_flag = 'Y')
177                 OR
178                        (accrual_posted_flag  = 'N'
179                          AND l_cash_basis_flag <> 'Y')));
180 
181     BEGIN
182 
183     /*-----------------------------------------------------------------+
184     |  Get Accounting Methods from gl_sets_of_books                    |
185     |      l_cash_basis_flag: 'Y' --cash basis                         |
186     |                         'N' --accrual basis                      |
187     |  MOAC.  Added org_id to select statement.                        |
188     +-----------------------------------------------------------------*/
189       BEGIN
190       SELECT nvl(sob.sla_ledger_cash_basis_flag, 'N'),
191              asp.org_id
192       INTO l_cash_basis_flag,
193            l_org_id
194       FROM ap_invoices_all ai,
195            ap_system_parameters_all asp,
196            gl_sets_of_books sob
197       WHERE ai.invoice_id = p_invoice_id
198       AND ai.org_id = asp.org_id
199       AND asp.set_of_books_id = sob.set_of_books_id;
200 
201       EXCEPTION
202          WHEN OTHERS THEN
203               null;
204       END;
205       /*Added the above exception for Bug 14841063 */
206 
207       invoice_line_posting_flag := 'X';
208 
209       OPEN posting_cursor;
210 
211       LOOP
212       FETCH posting_cursor INTO distribution_posting_flag;
213       EXIT WHEN posting_cursor%NOTFOUND;
214 
215         IF (distribution_posting_flag = 'S') THEN
216           invoice_line_posting_flag := 'S';
217         ELSIF (distribution_posting_flag = 'P' AND
218                invoice_line_posting_flag <> 'S') THEN
219           invoice_line_posting_flag := 'P';
220         ELSIF (distribution_posting_flag = 'N' AND
221                invoice_line_posting_flag NOT IN ('S','P')) THEN
222           invoice_line_posting_flag := 'N';
223         ELSIF (invoice_line_posting_flag NOT IN ('S','P','N')) THEN
224           invoice_line_posting_flag := 'Y';
225         END IF;
226       END LOOP;
227       CLOSE posting_cursor;
228 
229       if (invoice_line_posting_flag = 'X') then
230         invoice_line_posting_flag := 'N';
231       end if;
232 
233       RETURN(invoice_line_posting_flag);
234 
235 
236     END get_posting_status;
237 
238 /*============================================================================
239  |  FUNCTION - get_approval_status
240  |
241  |  DESCRIPTION
242  |      returns the invoice line level approval status lookup code.
243  |
244  |  PARAMETERS
245  |      p_invoice_id - invoice id
246  |      p_line_number - invoice line number
247  |
248  |
249  |  NOTES
250  |      Invoices Line  -'APPROVED'
251  |                      'NEEDS REAPPROVAL'
252  |                      'NEVER APPROVED'
253  |                      'CANCELLED'
254  |
255  |  MODIFICATION HISTORY
256  |  Date         Author             Description of Change
257  |
258  *============================================================================*/
259 
260     FUNCTION get_approval_status(
261                  p_invoice_id               IN NUMBER,
262                  p_line_number              IN NUMBER)
263     RETURN VARCHAR2
264     IS
265 
266       invoice_line_approval_status    VARCHAR2(25);
267       invoice_line_approval_flag      VARCHAR2(1);
268       distribution_approval_flag      VARCHAR2(1);
269       encumbrance_flag                VARCHAR2(1);
270       invoice_holds                   NUMBER;
271       sum_distributions               NUMBER;
272       dist_var_hold                   NUMBER;
273       match_flag_cnt                  NUMBER;
274       l_cancelled_count               NUMBER;
275       l_discarded_count               NUMBER;
276       l_org_id                        FINANCIALS_SYSTEM_PARAMS_ALL.ORG_ID%TYPE;
277       ---------------------------------------------------------------------
278       -- Declare cursor to establish the invoice-level approval flag
279       --
280       -- The first select simply looks at the match status flag for the
281       -- distributions.  The rest is to cover one specific case when some
282       -- of the distributions are tested (T or A) and some are untested
283       -- (NULL).  The status should be needs reapproval (N).
284       --
285       CURSOR approval_cursor IS
286       SELECT nvl(match_status_flag, 'N')
287       FROM   ap_invoice_distributions_all
288       WHERE  invoice_id = p_invoice_id
289       AND    invoice_line_number =  p_line_number;
290 
291     BEGIN
292 
293          ---------------------------------------------------------------------
294          -- Get the encumbrance flag
295          -- MOAC.  Included select from ap_invoices_all to get the org_id from
296          --        the invoice_id since it is unique
297 
298       SELECT NVL(fsp.purch_encumbrance_flag,'N'), ai.org_id
299       INTO encumbrance_flag, l_org_id
300       FROM ap_invoices_all ai,
301            financials_system_params_all fsp
302       WHERE ai.invoice_id = p_invoice_id
303       AND ai.org_id = fsp.org_id;
304 
305          ---------------------------------------------------------------------
306          -- Get the number of holds for the invoice
307          --
308       SELECT count(*)
309       INTO   invoice_holds
310       FROM   ap_holds_all
311       WHERE  invoice_id = p_invoice_id
312       AND    release_lookup_code is NULL;
313 
314          ---------------------------------------------------------------------
315          -- Check if DIST VAR hold is placed on this invoice.
316          -- DIST VAR is a special case because it could be placed
317          -- when no distributions exist and in this case, the invoice
318          -- status should be NEEDS REAPPROVAL.
319          --
320       SELECT count(*)
321       INTO   dist_var_hold
322       FROM   ap_holds_all
323       WHERE  invoice_id = p_invoice_id
324       AND    hold_lookup_code = 'DIST VARIANCE'
325       AND    release_lookup_code is NULL;
326 
327          ---------------------------------------------------------------------
328          -- If invoice is cancelled, return 'CANCELLED'.
329          --
330       SELECT count(*)
331       INTO   l_cancelled_count
332       FROM   ap_invoice_lines
333       WHERE  invoice_id = p_invoice_id
334         AND  line_number = p_line_number
335         AND  NVL(cancelled_flag, 'N' ) = 'Y';
336 
337       IF ( l_cancelled_count > 0 ) THEN
338         RETURN('CANCELLED');
339       END IF;
340 
341          ---------------------------------------------------------------------
342          -- Getting the count of distributions with
343          -- match_status_flag not null. We will open the approval_cursor
344          -- only if the count is more than 0.
345          --
346       SELECT count(*)
347       INTO match_flag_cnt
348       FROM ap_invoice_distributions_all aid
349       WHERE aid.invoice_id = p_invoice_id
350       AND aid.invoice_line_number = p_line_number
351       AND aid.match_status_flag IS NOT NULL
352       AND rownum < 2;
353 
354          ---------------------------------------------------------------------
355          -- Establish the invoice line level approval flag
356          --
357          -- Use the following ordering sequence to determine the invoice-level
358          -- approval flag:
359          --                     'N' - Needs Reapproval
360          --                     'T' - Tested
361          --                     'A' - Approved
362          --                     NULL  - Never Approved
363          --                     'X' - No Distributions Exist
364          --
365          -- Initialize invoice line level approval flag
366          --
367       invoice_line_approval_flag := 'X';
368 
369       IF match_flag_cnt > 0 THEN
370 
371         OPEN approval_cursor;
372 
373         LOOP
374         FETCH approval_cursor INTO distribution_approval_flag;
375         EXIT WHEN approval_cursor%NOTFOUND;
376 
377           IF (distribution_approval_flag IS NULL) THEN
378             invoice_line_approval_flag := NULL;
379           ELSIF (distribution_approval_flag = 'N') THEN
380             invoice_line_approval_flag := 'N';
381           ELSIF (distribution_approval_flag = 'T' AND
382                  (invoice_line_approval_flag <> 'N' or
383                   invoice_line_approval_flag is null)) THEN
384             invoice_line_approval_flag := 'T';
385           ELSIF (distribution_approval_flag = 'A' AND
386                  (invoice_line_approval_flag NOT IN ('N','T')
387                   or invoice_line_approval_flag is null)) THEN
388             invoice_line_approval_flag := 'A';
389           END IF;
390 
391         END LOOP;
392 
393         CLOSE approval_cursor;
394       END IF; -- end of match_flag_cnt
395 
396 
397          ---------------------------------------------------------------------
398          -- Derive the translated approval status from the approval flag
399          --
400       IF (encumbrance_flag = 'Y') THEN
401 
402         IF (invoice_line_approval_flag = 'A' AND invoice_holds = 0) THEN
403           invoice_line_approval_status := 'APPROVED';
404         ELSIF ((invoice_line_approval_flag in ('A') AND invoice_holds > 0)
405                OR (invoice_line_approval_flag IN ('T','N'))) THEN
406           invoice_line_approval_status := 'NEEDS REAPPROVAL';
407         ELSIF (dist_var_hold >= 1) THEN
408                  --It's assumed here that the user won't place this hold
409                  --manually before approving.  If he does, status will be
410                  --NEEDS REAPPROVAL.  dist_var_hold can result when there
411                  --are no distributions or there are but amounts don't
412                  --match.  It can also happen when an invoice is created with
413                  --no distributions, then approve the invoice, then create the
414                  --distribution.  So, in this case, although the match flag
415                  --is null, we still want to see the status as NEEDS REAPPR.
416           invoice_line_approval_status := 'NEEDS REAPPROVAL';
417         ELSIF (invoice_line_approval_flag is null
418                 OR (invoice_line_approval_flag = 'X' AND dist_var_hold = 0 )) THEN
419 		--Bug8414549: Undoing changes for bug8340784
420 		--AND invoice_holds = 0)) THEN  --Bug8340784
421 		--Added invoice_holds = 0 to above condition
422           invoice_line_approval_status := 'NEVER APPROVED';
423         END IF;
424 
425       ELSIF (encumbrance_flag = 'N') THEN
426         IF (invoice_line_approval_flag IN ('A','T') AND invoice_holds = 0) THEN
427           invoice_line_approval_status := 'APPROVED';
428         ELSIF ((invoice_line_approval_flag IN ('A','T') AND invoice_holds > 0)
429                 OR
430                (invoice_line_approval_flag = 'N')) THEN
431           invoice_line_approval_status := 'NEEDS REAPPROVAL';
432         ELSIF (dist_var_hold >= 1) THEN
433           invoice_line_approval_status := 'NEEDS REAPPROVAL';
434         ELSIF (invoice_line_approval_flag is null
435                OR (invoice_line_approval_flag = 'X' AND dist_var_hold = 0
436 			   AND invoice_holds = 0)) THEN  --Bug8340784
437 				 --Added invoice_holds = 0 to above condition
438                  -- A NULL flag indicate that APPROVAL has not
439                  -- been run for this invoice, therefore, even if manual
440                  -- holds exist, status should be NEVER APPROVED.
441           invoice_line_approval_status := 'NEVER APPROVED';
442         END IF;
443       END IF;
444 
445       RETURN(invoice_line_approval_status);
446     END get_approval_status;
447 
448 /*=============================================================================
449  |  Public PROCEDURE Is_Line_Discardable
450  |
451  |      Check if the line is discardable
452  |
453  |  PROGRAM FLOW
454  |
455  |      1. return FALSE - if discard flag is Y
456  |      2. return FALSE - if line contains distribution that does not have
457  |                        an OPEN reversal period name.
458  |      3. return FALSE - if line contain distributions which are PO/RCV
459  |                        matched whose reversal causes amount/qty billed less
460  |                        than 0
461  |      4. return FALSE - if line is final match
462  |      5. return FALSE - if line is referenced by an active correction
463  |      6. return FALSE - if line contains distributions witn invalid account
464  |      7. return FALSE - if line contains distributions refereced by active
465  |                        distributions which are not cancelled or reversed
466  |                        apply to FREIGHT/MISC allocated to Item Line
467  |      8. return FALSE - if line with outstanding allocation rule
468  |      9. return FALSE - if line is AWT line linked to AWT invoice
469  |     10. return FALSE - if prepayment line has been applied (same as Note 1)
470  |     14. return FALSE - if invoice is selected for payment
471  |
472  |  NOTES
473  |
474  |     1. If line is the prepay application/unapplication - we handle the
475  |        business rule on-line. Means from UI we will make sure that one
476  |        PREPAY type line can not be discarded unless it is being fully
477  |        unapplied.
478  |
479  |  MODIFICATION HISTORY
480  |  Date         Author               Description of Change
481  |  03/07/03     sfeng                Created
482  |
483  *============================================================================*/
484 
485   Function Is_Line_Discardable(
486                P_line_rec          IN  ap_invoice_lines%ROWTYPE,
487                P_error_code            OUT NOCOPY VARCHAR2,
488                P_calling_sequence  IN             VARCHAR2) RETURN BOOLEAN
489 
490   IS
491 
492     l_po_dist_count              NUMBER := 0;
493     l_rcv_dist_count             NUMBER := 0; --Bug5000472
494     l_reference_count            NUMBER := 0;
495     l_active_count               NUMBER := 0;
496     l_quick_credit_count         NUMBER := 0;
497     l_quick_credit_ref_count     NUMBER := 0;
498     l_invalid_acct_count         NUMBER := 0;
499     l_valid_alt_acct_exists      NUMBER := 0; /* Added for bug#12555194 */
500     l_final_close_count          NUMBER := 0;
501     l_pending_count              NUMBER := 0;
502     l_count                      NUMBER := 0;
503 
504     l_debug_info                 VARCHAR2(240);
505     l_curr_calling_sequence      VARCHAR2(2000);
506 
507     TYPE date_tab is TABLE OF DATE INDEX BY BINARY_INTEGER;
508     l_gl_date_list               date_tab;
509     i                            BINARY_INTEGER := 1;
510     l_open_gl_date               DATE :='';
511     l_open_period                gl_period_statuses.period_name%TYPE := '';
512 
513     l_prepay_amount_applied      NUMBER := 0;
514     l_enc_enabled                VARCHAR2(1);    --bug6009101
515     l_po_not_approved            VARCHAR2(1);    --bug6009101
516     l_org_id  ap_invoices_all.org_id%type;      -- for bug 5936290
517     CURSOR dist_gl_date_Cur IS
518     SELECT accounting_date
519       FROM ap_invoice_distributions AID
520      WHERE AID.invoice_id = p_line_rec.invoice_id
521        AND AID.invoice_line_number = p_line_rec.line_number
522        AND NVL(AID.reversal_flag, 'N') <> 'Y';
523 
524 
525   BEGIN
526 
527     l_curr_calling_sequence := 'AP_INVOICE_LINE_PKG.IS_Line_Discardable<-' ||
528                                P_calling_sequence;
529 
530     /*-----------------------------------------------------------------+
531      |  Step 0 - If line is discarded, return FALSE                    |
532      +-----------------------------------------------------------------*/
533 
534     l_debug_info := 'Check if line is already discarded';
535 
536     IF ( NVL(p_line_rec.discarded_flag, 'N') = 'Y' ) THEN
537       p_error_code := 'AP_INV_LINE_ALREADY_DISCARDED';
538       RETURN FALSE;
539     END IF;
540 
541     /*-----------------------------------------------------------------+
542      |  Step 1 - If line is CANCELLED, can not be discarded, return    |
543      |           FALSE                                                 |
544      +-----------------------------------------------------------------*/
545 
546     l_debug_info := 'Check if line is already cancelled';
547 
548     IF ( NVL(p_line_rec.cancelled_flag, 'N') = 'Y' ) THEN
549       p_error_code := 'AP_INV_CANCELLED';
550       RETURN FALSE;
551     END IF;
552 
553     /*-----------------------------------------------------------------+
554      |  Step 2 - If line contains distribution which has no open       |
555      |           period, can not be discarded, return FALSE            |
556      +-----------------------------------------------------------------*/
557 
558     l_debug_info := 'Check if distribution in this line has open period';
559 
560     OPEN dist_gl_date_Cur;
561     FETCH dist_gl_date_Cur
562     BULK COLLECT INTO l_gl_date_list;
563     CLOSE dist_gl_date_Cur;
564 
565   -- For bug 5936290
566   --  we call ap_utilities_pkg.get_current_gl_date
567   --  and in ap_utilities_pkg.get_open_gl_date for getting the gl date and
568   --  period below.For both these procedures one parameter is org_id
569   --  and it's default value is mo_global.get_current_org_id.we do
570   --  were not passing the org_id in these procedures calls so
571   --  the org_id was getting picked up from mo_global.get_current_org_id
572   --  and it's coming null when the Invoice batch option is ON.
573   --  So now we are passing the org_id also in these two calls.
574 
575     SELECT org_id
576     INTO   l_org_id
577     FROM   ap_invoices_all
578     WHERE  invoice_id = p_line_rec.invoice_id;
579 
580     FOR i in NVL(l_gl_date_list.FIRST,0)..NVL(l_gl_date_list.LAST,-1)
581     LOOP
582       l_open_period := ap_utilities_pkg.get_current_gl_date(l_gl_date_list(i),l_org_id); --added for bug 5936290
583 
584       IF ( l_open_period IS NULL ) THEN
585         ap_utilities_pkg.get_open_gl_date(
586                  l_gl_date_list(i),
587                  l_open_period,
588                  l_open_gl_date,
589                  l_org_id); --added for bug 5936290
590         IF ( l_open_period IS NULL ) THEN
591           p_error_code := 'AP_DISCARD_NO_FUTURE_PERIODS';
592           RETURN FALSE;
593         END IF;
594       END IF;
595     END LOOP;
596 
597 --Bug9871858 : Moved Step 3 and 3.1 after step 7.
598     /*-----------------------------------------------------------------+
599      |  Step 4. If invoice is matched to a Finally Closed PO, return   |
600      |          FALSE                                                  |
601      +-----------------------------------------------------------------*/
602 
603     l_debug_info := 'Check if invoice line is matched to a finally'
604                     ||'  closed PO shipment';
605 
606     SELECT count(*)
607     INTO   l_final_close_count
608     FROM   ap_invoice_lines AIL,
609            po_line_locations PLL
610     WHERE  AIL.invoice_id = p_line_rec.invoice_id
611     AND    AIL.line_number = p_line_rec.line_number
612     AND    AIL.po_line_location_id = PLL.line_location_id
613     AND    PLL.closed_code = 'FINALLY CLOSED';
614 
615     IF (l_final_close_count > 0) THEN
616       P_error_code := 'AP_INV_LINE_PO_FINALLY_CLOSED';
617       RETURN FALSE;
618     END IF;
619 
620     /*-----------------------------------------------------------------+
621      |  Step 4.1 If the encumbrance is on and the invoice is matched to
622      |           to an unapproved PO, then do not allow discard.(bug6009101)
623      +-----------------------------------------------------------------*/
624 
625       SELECT NVL(purch_encumbrance_flag,'N')
626       INTO   l_enc_enabled
627       FROM   financials_system_params_all FSP,
628              ap_invoices_all              AI
629       WHERE  AI.invoice_id  =  p_line_rec.invoice_id
630       AND    FSP.org_id     =  AI.org_id;
631 
632     if l_enc_enabled  = 'Y' then
633 
634        begin
635 
636           select 'Y'
637           into   l_po_not_approved
638           from   po_headers POH
639           where POH.po_header_id = p_line_rec.po_header_id
640           and   POH.approved_flag <> 'Y';    --bug6653070
641 
642           EXCEPTION
643              WHEN OTHERS THEN
644                   NULL;
645 
646        end;
647 
648        if l_po_not_approved = 'Y' then
649           p_error_code := 'AP_PO_UNRES_CANT_DISC_LINE';
650           return FALSE;
651        end if;
652    end if;
653 
654 
655     /*-----------------------------------------------------------------+
656      |  Step 5. If invoice is a quick credit, it can be cancelled at   |
657      |          at header level. can not discard individual line. so   |
658      |          return FALSE;                                          |
659      +-----------------------------------------------------------------*/
660     l_debug_info := 'Check if this invoice is a quick credit';
661 
662     SELECT count(*)
663       INTO l_quick_credit_count
664       FROM ap_invoices AI
665      WHERE AI.invoice_id = p_line_rec.invoice_id
666        AND NVL(AI.quick_credit, 'N') = 'Y';
667 
668     IF ( l_quick_credit_count > 0  ) THEN
669       P_error_code := 'AP_INV_IS_QUICK_CREDIT';
670       RETURN FALSE;
671     END IF;
672 
673     /*-----------------------------------------------------------------+
674      |  Step 6. Check If invoice line is actively referenced           |
675      |         If invoice line reference by an active                  |
676      |                  correction, return FALSE                       |
677      +-----------------------------------------------------------------*/
678     l_debug_info := 'Check if this line is refrenced by a correction';
679 
680     SELECT count(*)
681       INTO l_active_count
682       FROM ap_invoice_lines AIL
683      WHERE NVL( AIL.discarded_flag, 'N' ) <> 'Y'
684        AND NVL( AIL.cancelled_flag, 'N' ) <> 'Y'
685        AND AIL.corrected_inv_id = p_line_rec.invoice_id
686        AND AIL.corrected_line_number = p_line_rec.line_number;
687 
688     IF ( l_active_count > 0) THEN
689       P_error_code := 'AP_INV_LINE_REF_BY_CORRECTION';
690       RETURN FALSE;
691     END IF;
692 
693     /*-----------------------------------------------------------------+
694      |  Step 7. Check If invoice line is actively referenced           |
695      |          If one active quick credit is referencing this         |
696      |          invoice, return FALSE                                  |
697      +-----------------------------------------------------------------*/
698     l_debug_info := 'Check if this line is a refreced by a quick credit';
699 
700     -- Bug 5261908. Added rownum condition to improve performance
701     BEGIN
702     --bug 5475668 Added the if condition.
703     --bug 8208823 Added condition for line_type_lookup_code
704     if (p_line_rec.invoice_id is not NULL
705 	AND p_line_rec.line_type_lookup_code <> 'PREPAY') then
706       SELECT 1
707         INTO l_quick_credit_ref_count
708         FROM ap_invoices AI
709        WHERE AI.credited_invoice_id = p_line_rec.invoice_id
710          AND NVL(AI.quick_credit, 'N') = 'Y'
711          AND AI.cancelled_date is null
712          AND Rownum = 1;
713     end if;
714     EXCEPTION
715       WHEN no_data_found THEN
716            NULL;
717     END;
718 
719     IF (l_quick_credit_ref_count > 0  ) THEN
720       P_error_code := 'AP_INV_LINE_REF_BY_QCK_CREDIT';
721       RETURN FALSE;
722     END IF;
723 
724     --Bug9871858: Moved Step 3 and 3.1 after step 7
725     /*-----------------------------------------------------------------+
726      |  Step 3. if the quantity billed and amount on PO would be       |
727      |          reduced to less than zero then return FALSE            |
728      |          Always allow Reversal distributions to be cancelled    |
729      +-----------------------------------------------------------------*/
730 
731     l_debug_info := 'Check if quantity_billed on po_distribution is '
732                     || 'would be reduced to < 0';
733     --Bug5000472 added condition on po distribution id and rcv_transaction_id
734     --and commented GROUP BY in sub queries
735 
736     -- Modified the below select statment for the bug #6913924 to consider the
737     -- case when prepayment invoice matched to a PO and receipt and with
738      --different UOM for PO and receipt.
739 
740     BEGIN
741     SELECT count(*)
742     INTO   l_po_dist_count
743     FROM   po_distributions_all POD,
744            ap_invoice_distributions AID,
745            ap_invoices ai,
746            po_line_locations PLL,
747            po_lines PL
748     WHERE  POD.po_distribution_id = AID.po_distribution_id
749     AND    POD.line_location_id = PLL.line_location_id
750     AND    PLL.po_line_id = PL.po_line_id
751     AND    AID.invoice_id = ai.invoice_id
752     AND    AID.invoice_id = p_line_rec.invoice_id
753     AND    POD.org_id = AID.org_id
754     AND    AID.invoice_line_number = p_line_rec.line_number
755     AND    NVL(AID.reversal_flag,'N')<>'Y'
756     AND    aid.rcv_transaction_id is null  --Bug5000472
757     HAVING (
758             (DECODE(ai.invoice_type_lookup_code,'PREPAYMENT',
759                SUM(distinct NVL(POD.quantity_financed, 0)),			--bug15935245, added distinct keyword
760 	           SUM(distinct NVL(POD.quantity_billed, 0)))			--bug15935245, added distinct keyword
761                 -
762                 SUM(round(decode(AID.dist_match_type,
763                                 'PRICE_CORRECTION', 0,
764                                 'AMOUNT_CORRECTION', 0,
765                                  'ITEM_TO_SERVICE_PO', 0,
766                                  'ITEM_TO_SERVICE_RECEIPT', 0,
767                                   nvl( AID.quantity_invoiced, 0 ) +
768                                   nvl( AID.corrected_quantity,0 )
769                ) *
770                      po_uom_s.po_uom_convert(AID.matched_uom_lookup_code,
771                                    nvl(PLL.unit_meas_lookup_code,
772                      PL.unit_meas_lookup_code),
773                  PL.item_id), 15))
774               < 0)
775                OR (DECODE(ai.invoice_type_lookup_code,'PREPAYMENT',
776                   SUM(distinct NVL(POD.amount_financed, 0)),			--bug15935245, added distinct keyword
777 		     SUM(distinct NVL(POD.amount_billed, 0))) -			--bug15935245, added distinct keyword
778                   SUM(NVL(AID.amount, 0)) < 0 ))
779        GROUP BY ai.invoice_type_lookup_code,AID.po_distribution_id;
780 
781      EXCEPTION
782        WHEN NO_DATA_FOUND THEN
783          l_po_dist_count := 0;
784     END;
785       -- end of changes for bug #6913924
786 
787     IF (l_po_dist_count > 0  ) THEN
788       P_error_code := 'AP_INV_LINE_QTY_BILLED_NOT_NEG';
789       RETURN FALSE;
790     END IF;
791 
792 --Bug5000472  Added the following block of code
793     /*-----------------------------------------------------------------+
794      |  Step 3.1. if the quantity billed and amount on RCV would be    |
795      |          reduced to less than zero then return FALSE            |
796      |          Always allow Reversal distributions to be cancelled    |
797      +-----------------------------------------------------------------*/
798 
799     l_debug_info := 'Check if quantity_billed on rcv_transactions '
800                     || 'would be reduced to < 0';
801 
802     SELECT count(*)
803     INTO   l_rcv_dist_count
804     FROM   rcv_transactions RT,
805            ap_invoice_distributions_all AID
806     WHERE  RT.transaction_id = AID.rcv_transaction_id
807     AND    AID.invoice_id = p_line_rec.invoice_id
808     AND    AID.invoice_line_number = p_line_rec.line_number
809     AND    AID.rcv_transaction_id is not null
810     AND    NVL(AID.reversal_flag,'N')<>'Y'
811     AND    (NVL(rt.quantity_billed,0) <
812                (SELECT SUM(decode( AID1.dist_match_type,
813                                   'PRICE_CORRECTION', 0,
814                                   'AMOUNT_CORRECTION', 0,
815                                   'ITEM_TO_SERVICE_PO', 0,
816                                   'ITEM_TO_SERVICE_RECEIPT', 0,
817                                    nvl( AID1.corrected_quantity,0 ) +
818                                    nvl( AID1.quantity_invoiced,0 )
819                                                         )
820                                                     )
821                  FROM ap_invoice_distributions_all aid1
822                 WHERE aid1.invoice_id = aid.invoice_id
823                   AND aid1.invoice_line_number = aid.invoice_line_number
824                   AND aid1.rcv_transaction_id=aid.rcv_transaction_id
825                        )
826              OR
827              NVL(rt.amount_billed,0) <  (
828                        SELECT SUM(DECODE(AID2.dist_match_type,			--Bug11783854
829 				'OTHER_TO_RECEIPT',0,NVL(AID2.amount,0)))
830                          FROM ap_invoice_distributions_all aid2
831                         WHERE aid2.invoice_id = aid.invoice_id
832                          AND aid2.invoice_line_number = aid.invoice_line_number
833                          AND aid2.rcv_transaction_id=aid.rcv_transaction_id
834                           )
835              );
836 
837     IF (l_rcv_dist_count > 0  ) THEN
838       P_error_code := 'AP_INV_LINE_QTY_BILLED_NOT_NEG';
839       RETURN FALSE;
840     END IF;
841 --Bug5000472 End
842 --End of bug9871858
843 
844     /*-----------------------------------------------------------------+
845      |  Step 8. If line contain distributions which has invalid account |
846      |          return FALSE                                            |
847      +-----------------------------------------------------------------*/
848 
849     SELECT  count(*)
850     INTO    l_invalid_acct_count
851     FROM    ap_invoice_distributions D
852     WHERE   D.invoice_id = p_line_rec.invoice_id
853     AND     D.invoice_line_number = p_line_rec.line_number
854     AND     D.posted_flag IN ('N', 'P')
855     AND ((EXISTS (select 'x'
856                   from gl_code_combinations C
857                   where D.dist_code_combination_id = C.code_combination_id (+)
858                   and (C.code_combination_id is null
859                      or C.detail_posting_allowed_flag = 'N'
860                      or C.start_date_active > D.accounting_date
861                      or C.end_date_active < D.accounting_date
862                      or C.template_id is not null
863                      or C.enabled_flag <> 'Y'
864                      or C.summary_flag <> 'N'
865                      )))
866     OR (D.dist_code_combination_id = -1));
867 
868     IF (l_invalid_acct_count <> 0) THEN
869 
870        /* Added for bug#12555194 Start */
871         l_valid_alt_acct_exists := 0;
872 
873         SELECT count(1)
874           INTO l_valid_alt_acct_exists
875           FROM ap_invoice_distributions aid
876              , gl_code_combinations glcc
877          WHERE aid.invoice_id           = p_line_rec.invoice_id
878            AND aid.invoice_line_number  = p_line_rec.line_number
879            AND aid.posted_flag IN ('N', 'P')
880            AND dist_code_combination_id = glcc.code_combination_id
881            AND glcc.alternate_code_combination_id IS NOT NULL
882            AND EXISTS
883                (
884                SELECT 'Account Valid'
885                  FROM gl_code_combinations glcc1
886                 WHERE glcc1.code_combination_id         = glcc.alternate_code_combination_id
887                   AND glcc1.enabled_flag                = 'Y'
888                   AND glcc1.detail_posting_allowed_flag = 'Y'
889                   AND aid.accounting_date BETWEEN
890                           NVL(glcc1.start_date_active, aid.accounting_date)
891                       AND NVL(glcc1.end_date_active, aid.accounting_date)
892                );
893        IF l_valid_alt_acct_exists = 0 THEN
894        /* Added for bug#12555194 End */
895 
896       P_error_code := 'AP_INV_LINE_INVALID_DIST_ACCT';
897       RETURN FALSE;
898        END IF; /* Added for bug#12555194 */
899     END IF;
900 
901     /*-----------------------------------------------------------------+
902      |  Step 9. If line contain distributions referenced by active     |
903      |          distributions, return FALSE. This applies to all the   |
904      |          non-charge lines which have active charges lines       |
905      |          allocated to themselves. In case that a charge         |
906      |          distribution's parent line is not a charge line but    |
907      |          and ITEM/ACCRUAL line, we should allow line to be      |
908      |          discarded                                              |
909      +-----------------------------------------------------------------*/
910 -- Bug 5114543
911 -- Commented the following check to allow discard of item line
912 -- when it has allocated charges.
913 -- Bug 5386077. Recommenting again. Was checked incorrectly via bug 5000472 (120.20)
914 
915 /*
916     SELECT  count(*)
917     INTO    l_reference_count
918     FROM    ap_invoice_distributions AID
919     WHERE   NVL(AID.cancellation_flag, 'N') <> 'Y'
920     AND     NVL(AID.reversal_flag, 'N') <> 'Y'
921     AND     AID.invoice_id = p_line_rec.invoice_id
922     AND     AID.invoice_line_number <> p_line_rec.line_number
923     AND     AID.charge_applicable_to_dist_id IS NOT NULL
924     AND     AID.charge_applicable_to_dist_id IN
925             ( SELECT AID2.invoice_distribution_id
926                 FROM ap_invoice_distributions AID2
927                WHERE AID2.invoice_id = p_line_rec.invoice_id
928                  AND AID2.invoice_line_number = p_line_rec.line_number
929                  AND NVL(AID2.cancellation_flag, 'N') <> 'Y'
930                  AND NVL(AID2.reversal_flag, 'N') <> 'Y' );
931 
932     IF ( l_reference_count <> 0) THEN
933       P_error_code := 'AP_INV_LINE_ACTIVE_DIST';
934       RETURN FALSE;
935     END IF;
936 */
937     /*------------------------------------------------------------------+
938      |  Step 10. If this non-charge line contain active allocation rule |
939      |           which is not yet applied, return FALSE                 |
940      +------------------------------------------------------------------*/
941 -- Bug 5114543
942 -- Commented the following check to allow discard of item line
943 -- when it has allocated charges.
944 -- Bug 5386077. Recommenting again. Was checked incorrectly via bug 5000472 (120.20).
945 /*
946     SELECT  count(*)
947     INTO    l_pending_count
948     FROM    ap_allocation_rules  AR,
949             ap_allocation_rule_lines ARL
950     WHERE   AR.invoice_id = p_line_rec.invoice_id
951     AND     AR.invoice_id = ARL.invoice_id
952     AND     AR.chrg_invoice_line_number = ARL.chrg_invoice_line_number
953     AND     ARL.to_invoice_line_number = p_line_rec.line_number
954     AND     AR.status = 'PENDING';
955 
956     IF ( l_pending_count <> 0) THEN
957       P_error_code := 'AP_INV_LINE_HAS_ALLOC_RULE';
958       RETURN FALSE;
959     END IF;
960  */
961     /*-----------------------------------------------------------------+
962      |  Step 11. If line is  AWT line which invoice is fully or        |
963      |             partially paid, return FALSE                        |
964      +-----------------------------------------------------------------*/
965 
966     SELECT  count(*)
967     INTO    l_count
968     FROM    ap_invoice_lines AIL,
969             ap_invoices AI
970     WHERE   AIL.invoice_id = P_line_rec.invoice_id
971     AND     AIL.line_number = P_line_rec.line_number
972     AND     AIL.line_type_lookup_code  = 'AWT'
973     /*bug12865213, commented exists clause
974     AND     NOT EXISTS ( SELECT invoice_distribution_id
975                            FROM ap_invoice_distributions aid
976                           WHERE aid.invoice_id = AIL.invoice_id
977                             AND aid.invoice_line_number = AIL.line_number
978                             AND awt_flag = 'M' )
979     */
980     AND     AI.invoice_id = AIL.invoice_id
981     AND     AI.payment_status_flag in ('P', 'Y');
982 
983     IF ( l_count <> 0) THEN
984       P_error_code := 'AP_INV_LINE_IS_AWT';
985       RETURN FALSE;
986     END IF;
987 
988     /*--------------------------------------------------------------------+
989      |  Step 12. If line has some or entire retained amount
990      |           released, return FALSE
991      +--------------------------------------------------------------------*/
992 
993      SELECT count(*)
994        INTO l_count
995        FROM ap_invoice_lines AIL
996       WHERE AIL.invoice_id  = P_line_rec.invoice_id
997 	AND AIL.line_number = P_line_rec.line_number
998 	AND (ail.retained_amount           IS NOT NULL AND
999 	     ail.retained_amount_remaining IS NOT NULL AND
1000              abs(ail.retained_amount) <> abs(ail.retained_amount_remaining));
1001 
1002      IF ( l_count <> 0) THEN
1003          P_error_code := 'AP_INV_LINE_RELEASED';
1004          RETURN FALSE;
1005      END IF;
1006 
1007     /*-----------------------------------------------------------------+
1008      |  Step 13. Prepayment line cannot be discarded after prepayment  |
1009      |           is applied.  If so, return FALSE (Bug #5114854)       |
1010      +-----------------------------------------------------------------*/
1011     SELECT count(*)
1012       INTO l_count
1013       FROM ap_invoices_all ai
1014      WHERE invoice_id = p_line_rec.invoice_id
1015        AND invoice_type_lookup_code = 'PREPAYMENT';
1016 
1017     IF ( l_count > 0 ) THEN
1018 
1019       l_prepay_amount_applied :=
1020          ap_invoices_pkg.get_prepay_amount_applied(p_line_rec.invoice_id);
1021 
1022       if (l_prepay_amount_applied <> 0) then
1023          p_error_code := 'AP_INV_DEL_APPLIED_PREPAY';
1024          RETURN FALSE;
1025       end if;
1026     END IF;
1027     /*-----------------------------------------------------------------+
1028      |  Step 14. invoice is select for payment and payment is not done |
1029      |           so, return FALSE (Bug #8366177)                       |
1030      +-----------------------------------------------------------------*/
1031 --bug 10012646
1032    select  nvl(count(1),0)
1033       INTO l_count
1034       from ap_payment_schedules_all
1035       where invoice_id =p_line_rec.invoice_id
1036       and checkrun_id is not null
1037       and payment_status_flag <>'Y';
1038 
1039      IF ( l_count > 0 ) THEN
1040          p_error_code := 'AP_INV_SELECTED_INVOICE';
1041          RETURN FALSE;
1042       end if;
1043 
1044     P_error_code := null;
1045     RETURN TRUE;
1046 
1047   EXCEPTION
1048     WHEN OTHERS THEN
1049       IF (SQLCODE <> -20001) THEN
1050         FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1051         FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1052         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
1053         FND_MESSAGE.SET_TOKEN('PARAMETERS',
1054              ' P_invoice_id = '     || p_line_rec.invoice_id
1055           ||' P_line_number = '     || p_line_rec.line_number );
1056         FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
1057       END IF;
1058 
1059       IF ( dist_gl_date_Cur%ISOPEN ) THEN
1060         CLOSE dist_gl_date_Cur;
1061       END IF;
1062 
1063       APP_EXCEPTION.RAISE_EXCEPTION;
1064 
1065   END Is_Line_Discardable;
1066 
1067  /*=============================================================================
1068  |  Public FUNCTION Allocation_Exists
1069  |
1070  |      Check if the line has allocation rules and lines associated with it.
1071  |
1072  |  PROGRAM FLOW
1073  |
1074  |       return TRUE  - if allocation rules and lines exist
1075  |       return FALSE - otherwise.
1076  |
1077  |  MODIFICATION HISTORY
1078  |  Date         Author               Description of Change
1079  |  03/10/13     bghose               Created
1080  *============================================================================*/
1081 
1082   FUNCTION Allocation_Exists (p_Invoice_Id        Number,
1083                               p_Line_Number       Number,
1084                               p_Calling_Sequence  Varchar2) Return Boolean Is
1085     dummy number := 0;
1086     current_calling_sequence   Varchar2(2000);
1087     debug_info                 Varchar2(100);
1088 
1089   Begin
1090     -- Update the calling sequence
1091     --
1092     current_calling_sequence :=
1093         'AP_INVOICE_LINES_UTILITY_PKG.ALLOCATION_EXISTS<-'||p_Calling_Sequence;
1094 
1095     debug_info := 'Select from ap_allocation_rules';
1096 
1097     Select count(*)
1098     Into   dummy
1099     From   ap_allocation_rules  AR,
1100            ap_allocation_rule_lines ARL
1101     Where  AR.invoice_id = p_Invoice_Id
1102     And    AR.invoice_id = ARL.invoice_id
1103     And    AR.chrg_invoice_line_number = ARL.chrg_invoice_line_number
1104     And    ARL.to_invoice_line_number = p_line_number;
1105 
1106     If (dummy >= 1) Then
1107       return  TRUE;
1108     End If;
1109 
1110     return FALSE;
1111 
1112   Exception
1113     WHEN OTHERS THEN
1114       If (SQLCODE <> -20001) Then
1115         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1116         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1117         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1118         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1119                                      ||', line number = '|| p_Line_Number);
1120         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1121       End If;
1122       APP_EXCEPTION.RAISE_EXCEPTION;
1123   End Allocation_Exists;
1124 
1125  /*=============================================================================
1126  |  Public FUNCTION Inv_Reversed_Via_Qc
1127  |
1128  |      Check if the invoice has been reversed via Qucik Credit.
1129  |
1130  |  PROGRAM FLOW
1131  |
1132  |       return TRUE  - if reversed via Quick Credit
1133  |       return FALSE - otherwise.
1134  |
1135  |  MODIFICATION HISTORY
1136  |  Date         Author               Description of Change
1137  |  03/10/13     bghose               Created
1138  *=============================================================================*/
1139 
1140   Function Inv_Reversed_Via_Qc (p_Invoice_Id        Number,
1141                                 p_Calling_Sequence  Varchar2)  Return Boolean Is
1142     dummy number := 0;
1143     current_calling_sequence   Varchar2(2000);
1144     debug_info                 Varchar2(100);
1145 
1146     Begin
1147     -- Update the calling sequence
1148     --
1149      current_calling_sequence :=
1150        'AP_INVOICE_LINES_UTILITY_PKG.Inv_Reverse_Via_Qc<-'||p_Calling_Sequence;
1151 
1152      debug_info := 'Select from ap_invoics_all';
1153 
1154      -- Bug 5261908. Added rownum condition to improve performance
1155      BEGIN
1156      --bug 5475668 Added the if condition
1157       if (p_invoice_id is not null) then
1158        Select 1
1159        Into   dummy
1160        From   ap_invoices_all AI
1161        Where AI.credited_invoice_id = p_Invoice_Id
1162        AND NVL(AI.quick_credit, 'N') = 'Y'
1163        AND AI.cancelled_date is null
1164        AND Rownum = 1;
1165       end if;
1166      EXCEPTION
1167        WHEN no_data_found THEN
1168             dummy := 0;
1169      END;
1170 
1171      If (dummy >= 1) Then
1172        return  TRUE;
1173      End if;
1174 
1175      return FALSE;
1176 
1177    Exception
1178     WHEN OTHERS THEN
1179       If (SQLCODE <> -20001) Then
1180         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1181         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1182         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1183         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id);
1184         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1185       End If;
1186       APP_EXCEPTION.RAISE_EXCEPTION;
1187   End Inv_Reversed_Via_Qc;
1188 
1189  /*=============================================================================
1190  |  Public FUNCTION Is_Line_Dists_Trans_FA
1191  |
1192  |      Check if the line has associated distributions which has transfered to
1193  |      FA.
1194  |
1195  |  PROGRAM FLOW
1196  |
1197  |       return TRUE  - ifdistributions transferred to FA
1198  |       return FALSE - otherwise.
1199  |
1200  |  MODIFICATION HISTORY
1201  |  Date         Author               Description of Change
1202  |  03/10/13     bghose               Created
1203  *============================================================================*/
1204   FUNCTION Is_Line_Dists_Trans_FA (p_Invoice_Id        Number,
1205                               p_Line_Number       Number,
1206                               p_Calling_Sequence  Varchar2) Return Boolean Is
1207     dummy number := 0;
1208     current_calling_sequence   Varchar2(2000);
1209     debug_info                 Varchar2(100);
1210 
1211   Begin
1212     -- Update the calling sequence
1213     --
1214     current_calling_sequence :=
1215         'AP_INVOICE_LINES_UTILITY_PKG.IS_LINE_DISTS_TRANS_FA<-'
1216                       ||p_Calling_Sequence;
1217 
1218     debug_info := 'Select from ap_invoice_distributions_all';
1219 
1220     Select count(*)
1221     Into   dummy
1222     From   ap_invoice_distributions_all
1223     Where invoice_id = p_Invoice_Id
1224     And invoice_line_number = p_Line_Number
1225     And assets_addition_flag = 'Y';
1226 
1227     If (dummy >= 1) Then
1228       return  TRUE;
1229     End if;
1230 
1231     return FALSE;
1232 
1233   Exception
1234     WHEN OTHERS THEN
1235       If (SQLCODE <> -20001) Then
1236         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1237         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1238         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1239         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1240                               ||', line number = '|| p_Line_Number);
1241         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1242       End If;
1243       APP_EXCEPTION.RAISE_EXCEPTION;
1244   End Is_Line_Dists_Trans_FA;
1245 
1246  /*=============================================================================
1247  |  Public FUNCTION Line_Dists_Acct_Event_Created
1248  |
1249  |      Check if the line has associated distributions accounting event created
1250  |
1251  |  PROGRAM FLOW
1252  |
1253  |       return TRUE  - if distributions accounting event created
1254  |       return FALSE - otherwise.
1255  |
1256  |  MODIFICATION HISTORY
1257  |  Date         Author               Description of Change
1258  |  03/10/13     bghose               Created
1259  *============================================================================*/
1260 
1261   FUNCTION Line_Dists_Acct_Event_Created (p_Invoice_Id        Number,
1262                                p_Line_Number       Number,
1263                                p_Calling_Sequence  Varchar2) Return Boolean Is
1264     dummy number := 0;
1265     current_calling_sequence   Varchar2(2000);
1266     debug_info                 Varchar2(100);
1267 
1268   Begin
1269     -- Update the calling sequence
1270     --
1271     current_calling_sequence :=
1272         'AP_INVOICE_LINES_UTILITY_PKG.LINE_DISTS_ACCT_EVENT_CREATED<-'
1273                       ||p_Calling_Sequence;
1274 
1275     debug_info := 'Select from ap_invoice_distributions_all';
1276 
1277     Select count(*)
1278     Into   dummy
1279     From   ap_invoice_distributions_all
1280     Where invoice_id = p_Invoice_Id
1281     And invoice_line_number = p_Line_Number
1282     And accounting_event_id Is Not Null;
1283 
1284     If (dummy >= 1) Then
1285       return  TRUE;
1286     End if;
1287 
1288     return FALSE;
1289 
1290   Exception
1291     WHEN OTHERS THEN
1292       If (SQLCODE <> -20001) Then
1293         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1294         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1295         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1296         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1297                               ||', line number = '|| p_Line_Number);
1298         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1299       End If;
1300       APP_EXCEPTION.RAISE_EXCEPTION;
1301   End Line_Dists_Acct_Event_Created;
1302 
1303  /*=============================================================================
1304  |  Public FUNCTION Line_Referred_By_Corr
1305  |
1306  |      Check if the line has been referred by any correction
1307  |
1308  |  PROGRAM FLOW
1309  |
1310  |       return TRUE  - if line has been referred by any correction
1311  |       return FALSE - otherwise.
1312  |
1313  |  MODIFICATION HISTORY
1314  |  Date         Author               Description of Change
1315  |  03/10/13     bghose               Created
1316  *============================================================================*/
1317 
1318   FUNCTION Line_Referred_By_Corr (p_Invoice_Id        Number,
1319                             p_Line_Number       Number,
1320                             p_Calling_Sequence  Varchar2) Return Boolean Is
1321     dummy number := 0;
1322     current_calling_sequence   Varchar2(2000);
1323     debug_info                 Varchar2(100);
1324 
1325   Begin
1326     -- Update the calling sequence
1327     --
1328     current_calling_sequence :=
1329         'AP_INVOICE_LINES_UTILITY_PKG.LINE_REFERRED_BY_CORR<-'
1330                       ||p_Calling_Sequence;
1331 
1332     debug_info := 'Select from ap_invoice_lines_all';
1333 
1334     Select count(*)
1335     Into   dummy
1336     From   ap_invoice_lines_all AIL
1337     Where  NVL(AIL.discarded_flag, 'N' ) <> 'Y'
1338     And NVL( AIL.cancelled_flag, 'N' ) <> 'Y'
1339     And AIL.corrected_inv_id = p_Invoice_Id
1340     And AIL.corrected_line_number = p_Line_Number;
1341 
1342     If (dummy >= 1) Then
1343       return  TRUE;
1344     End if;
1345 
1346     return FALSE;
1347 
1348   Exception
1349     WHEN OTHERS THEN
1350       If (SQLCODE <> -20001) Then
1351         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1352         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1353         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1354         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1355                               ||', line number = '|| p_Line_Number);
1356         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1357       End If;
1358       APP_EXCEPTION.RAISE_EXCEPTION;
1359   End Line_Referred_By_Corr;
1360 
1361  /*=============================================================================
1362  |  Public FUNCTION Line_Dists_Referred_By_Other
1363  |
1364  |      Check if the particular invoice line contains distributions referenced
1365  |      by active distributions
1366  |
1367  |  PROGRAM FLOW
1368  |
1369  |       return TRUE  - if line has been referenced by active distributions
1370  |       return FALSE - otherwise.
1371  |
1372  |  MODIFICATION HISTORY
1373  |  Date         Author               Description of Change
1374  |  03/10/13     bghose               Created
1375  *============================================================================*/
1376 
1377   FUNCTION Line_Dists_Referred_By_Other(p_Invoice_Id        Number,
1378                             p_Line_Number       Number,
1379                             p_Calling_Sequence  Varchar2) Return Boolean Is
1380     dummy number := 0;
1381     current_calling_sequence   Varchar2(2000);
1382     debug_info                           Varchar2(100);
1383 
1384   Begin
1385     -- Update the calling sequence
1386     --
1387     current_calling_sequence :=
1388                'AP_INVOICE_LINES_UTILITY_PKG.Line_Dists_Referred_By_Other <-'||
1389                             p_Calling_Sequence;
1390     debug_info := 'Select from ap_invoic_distributions_all';
1391 
1392     Select count(*)
1393     Into   dummy
1394     From   ap_invoice_distributions_all AID
1395     Where   NVL(AID.cancellation_flag, 'N') <> 'Y'
1396     And     NVL(AID.reversal_flag, 'N') <> 'Y'
1397     And     AID.invoice_id = p_invoice_id
1398     --Bug9323585 : Commented line to check for inclusive tax also
1399     --And     AID.invoice_line_number <> p_line_number
1400     And     AID.charge_applicable_to_dist_id IS NOT NULL
1401     And     AID.charge_applicable_to_dist_id In
1402            (Select AID2.invoice_distribution_id
1403             From ap_invoice_distributions_all AID2
1404             Where AID2.invoice_id = p_Invoice_Id
1405             And AID2.invoice_line_number = p_Line_Number
1406             And NVL(AID2.cancellation_flag, 'N') <> 'Y'
1407             And NVL(AID2.reversal_flag, 'N') <> 'Y' );
1408 
1409     If (dummy >= 1) Then
1410       return  TRUE;
1411     End if;
1412 
1413     return FALSE;
1414 
1415   Exception
1416     WHEN OTHERS THEN
1417       If (SQLCODE <> -20001) Then
1418         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1419         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1420         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1421         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1422                               ||', line number = '|| p_Line_Number);
1423         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1424       End If;
1425       APP_EXCEPTION.RAISE_EXCEPTION;
1426   End Line_Dists_Referred_By_Other;
1427 
1428  /*=============================================================================
1429  |  Public FUNCTION Outstanding_Alloc_Exists
1430  |
1431  |      Check if the particular invoice line contains outstanding allocation
1432  |      rule exists (not yet applied)
1433  |
1434  |  PROGRAM FLOW
1435  |
1436  |       return TRUE  - if line contains outstanding allocations
1437  |       return FALSE - otherwise.
1438  |
1439  |  MODIFICATION HISTORY
1440  |  Date         Author               Description of Change
1441  |  03/10/13     bghose               Created
1442  *============================================================================*/
1443 
1444   FUNCTION Outstanding_Alloc_Exists (p_Invoice_Id        Number,
1445                             p_Line_Number       Number,
1446                             p_Calling_Sequence  Varchar2) Return Boolean Is
1447     dummy number := 0;
1448     current_calling_sequence   Varchar2(2000);
1449     debug_info                           Varchar2(100);
1450 
1451   Begin
1452     -- Update the calling sequence
1453     --
1454     current_calling_sequence :=
1455                'AP_INVOICE_LINES_UTILITY_PKG.Outstanding_Alloc_Exists <-'||
1456                             p_Calling_Sequence;
1457     debug_info := 'Select from ap_allocatin_rules';
1458 
1459     Select count(*)
1460     Into   dummy
1461     From   ap_allocation_rules  AR,
1462            ap_allocation_rule_lines ARL
1463     Where  AR.invoice_id = p_Invoice_Id
1464     And    AR.invoice_id = ARL.invoice_id (+)
1465     And    AR.chrg_invoice_line_number = ARL.chrg_invoice_line_number (+)
1466     --Commented below condition for bug #9143555 and introduced new conditions
1467     -- And ARL.to_invoice_line_number (+)  = p_line_number
1468     And    AR.chrg_invoice_line_number  = p_line_number
1469     And    AR.status = 'PENDING';
1470 
1471     If (dummy >= 1) Then
1472       return  TRUE;
1473     End if;
1474 
1475     return FALSE;
1476   Exception
1477     WHEN OTHERS THEN
1478       If (SQLCODE <> -20001) Then
1479         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1480         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1481         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1482         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1483                               ||', line number = '|| p_Line_Number);
1484         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1485       End If;
1486       APP_EXCEPTION.RAISE_EXCEPTION;
1487   End Outstanding_Alloc_Exists;
1488 
1489  /*=============================================================================
1490  |  Public FUNCTION Line_Dists_Trans_Pa
1491  |
1492  |      Check if the particular invoice line contains project related
1493  |      distributions
1494  |
1495  |  PROGRAM FLOW
1496  |
1497  |       return TRUE  - if line has been referred by any correction
1498  |       return FALSE - otherwise.
1499  |
1500  |  MODIFICATION HISTORY
1501  |  Date         Author               Description of Change
1502  |  03/10/13     bghose               Created
1503  *============================================================================*/
1504 
1505   FUNCTION Line_Dists_Trans_Pa (p_Invoice_Id        Number,
1506                             p_Line_Number       Number,
1507                             p_Calling_Sequence  Varchar2) Return Boolean Is
1508     dummy number := 0;
1509     current_calling_sequence   Varchar2(2000);
1510     debug_info                 Varchar2(100);
1511 
1512   Begin
1513     -- Update the calling sequence
1514     --
1515     current_calling_sequence :=
1516                'AP_INVOICE_LINES_UTILITY_PKG.Line_Dists_Trans_PA <-'||
1517                             p_Calling_Sequence;
1518     debug_info := 'Select from ap_invoic_distributions_all';
1519 
1520     Select count(*)
1521     Into   dummy
1522     From   ap_invoice_distributions_all
1523     Where invoice_id = p_Invoice_Id
1524     And invoice_line_number = p_Line_Number
1525     And pa_addition_flag In ('T', 'Y', 'Z') ;
1526 
1527     If (dummy >= 1) Then
1528       return  TRUE;
1529     End if;
1530 
1531     return FALSE;
1532 
1533   Exception
1534     WHEN OTHERS THEN
1535       If (SQLCODE <> -20001) Then
1536         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1537         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1538         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1539         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1540                               ||', line number = '|| p_Line_Number);
1541         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1542       End If;
1543       APP_EXCEPTION.RAISE_EXCEPTION;
1544   End Line_Dists_Trans_Pa;
1545 
1546  /*=============================================================================
1547  |  Public FUNCTION Can_Line_Be_Deleted
1548  |
1549  |      Check if the particular invoice line can be deleted
1550  |
1551  |  PROGRAM FLOW
1552  |
1553  |       return TRUE  - if line can be deleted
1554  |       return FALSE - otherwise and return error code.
1555  |
1556  |  MODIFICATION HISTORY
1557  |  Date         Author               Description of Change
1558  |  03/10/13     bghose               Created
1559  *============================================================================*/
1560 
1561   FUNCTION Can_Line_Be_Deleted (p_line_rec    IN ap_invoice_lines%ROWTYPE,
1562                               p_error_code  OUT NOCOPY Varchar2,
1563                               p_Calling_Sequence  Varchar2) Return Boolean Is
1564     current_calling_sequence   Varchar2(2000);
1565 
1566   Begin
1567     -- Update the calling sequence
1568     --
1569     current_calling_sequence :=
1570                'AP_INVOICE_LINES_UTILITY_PKG.Can_Line_Be_Deleted <-'||
1571                             p_Calling_Sequence;
1572 
1573     If (Ap_Invoice_Lines_Utility_Pkg.Line_Dists_Acct_Event_Created
1574                                    (p_Line_Rec.Invoice_Id,
1575                                     p_Line_Rec.Line_Number,
1576                                     Current_calling_sequence) = TRUE)  Then
1577        p_error_code := 'AP_INV_LINE_DELETE_VALIDATED';
1578        return False;
1579     ElsIf (Ap_Invoice_Lines_Utility_Pkg.Line_Referred_By_Corr
1580                                    (p_Line_Rec.Invoice_Id,
1581                                     p_Line_Rec.Line_Number,
1582                                     Current_calling_sequence) = TRUE)  Then
1583        p_error_code := 'AP_INV_LINE_DELETE_CORR';
1584        return False;
1585     ElsIf (NVL(Ap_Invoice_Lines_Utility_Pkg.Get_Encumbered_Flag
1586                                    (p_Line_Rec.Invoice_Id,
1587                                     p_Line_Rec.Line_Number), 'N')
1588                                        In ('Y', 'P'))  Then
1589        p_error_code := 'AP_INV_LINE_DELETE_ENCUMBERED';
1590        return False;
1591     ElsIf (Ap_Invoice_Lines_Utility_Pkg.Get_Posting_Status
1592                                    (p_Line_Rec.Invoice_Id,
1593                                     p_Line_Rec.Line_Number)
1594                                        In ('Y', 'P', 'S'))  Then
1595        p_error_code := 'AP_INV_LINE_DELETE_ACCOUNTED';
1596        return False;
1597     ElsIf (Ap_Invoice_Lines_Utility_Pkg.Line_Dists_Trans_PA
1598                                    (p_Line_Rec.Invoice_Id,
1599                                     p_Line_Rec.Line_Number,
1600                                     Current_calling_sequence) = TRUE)  Then
1601        p_error_code := 'AP_INV_LINE_DELETE_PA';
1602        return False;
1603     ElsIf (Ap_Invoice_Lines_Utility_Pkg.Line_Dists_Referred_By_Other
1604                                    (p_Line_Rec.Invoice_Id,
1605                                     p_Line_Rec.Line_Number,
1606                                     Current_calling_sequence) = TRUE)  Then
1607        p_error_code := 'AP_INV_LINE_REF_BY_DISTS';
1608        return False;
1609     ElsIf (Ap_Invoice_Lines_Utility_Pkg.Outstanding_Alloc_Exists
1610                                    (p_Line_Rec.Invoice_Id,
1611                                     p_Line_Rec.Line_Number,
1612                                     Current_calling_sequence) = TRUE)  Then
1613        p_error_code := 'AP_INV_LINE_HAS_ALLOC_RULE';
1614        return False;
1615     End If;
1616 
1617     p_error_code := null;
1618     return TRUE;
1619 
1620   Exception
1621     WHEN OTHERS THEN
1622       If (SQLCODE <> -20001) Then
1623         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1624         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1625         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1626         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||
1627                                 p_line_rec.Invoice_id
1628                               ||', line number = '|| p_line_rec.Line_Number);
1629       End If;
1630       APP_EXCEPTION.RAISE_EXCEPTION;
1631   End Can_Line_Be_Deleted;
1632 
1633  /*=============================================================================
1634  |  Public FUNCTION Get_Packet_Id
1635  |
1636  |      Get the Packet Id for a line
1637  |
1638  |  PROGRAM FLOW
1639  |
1640  |
1641  |  MODIFICATION HISTORY
1642  |  Date         Author               Description of Change
1643  |  03/10/13     bghose               Created
1644  *============================================================================*/
1645 
1646   FUNCTION Get_Packet_Id (p_invoice_id In Number,
1647                           p_Line_Number In Number)    Return Number Is
1648 
1649     l_packet_id number := '';
1650     Cursor packet_id_cursor Is
1651     Select decode(count(distinct(packet_id)),1,max(packet_id),'')
1652     From ap_invoice_distributions
1653     Where invoice_id = p_Invoice_Id
1654     And invoice_line_number = p_Line_Number
1655     And packet_id is not null;
1656 
1657     Begin
1658       Open packet_id_cursor;
1659       Fetch packet_id_cursor INTO l_packet_id;
1660       Close packet_id_cursor;
1661 
1662     Return(l_packet_id);
1663   End get_packet_id;
1664 
1665 
1666 /*=============================================================================
1667  |  FUNCTION - Is_Line_Fully_Distributed
1668  |
1669  |  DESCRIPTION
1670  |    This function returns TRUE if the line is completelly distributed.
1671  |    It returns FALSE otherwise.
1672  |
1673  |  PARAMETERS
1674  |      P_Invoice_Id - Invoice Id
1675  |      P_Line_number - line number
1676  |      P_Calling_Sequence - debug usage
1677  |
1678  |  KNOWN ISSUES:
1679  |
1680  |  NOTES:
1681  |
1682  |  MODIFICATION HISTORY
1683  |  Date         Author             Description of Change
1684  |  30-JUL-2003  SYIDNER            Creation
1685  |
1686  *============================================================================*/
1687 
1688   FUNCTION Is_Line_Fully_Distributed(
1689              P_Invoice_Id           IN NUMBER,
1690              P_Line_Number          IN NUMBER,
1691              P_Calling_sequence     IN VARCHAR2) RETURN BOOLEAN
1692 
1693   IS
1694 
1695   CURSOR Dist_Var_Cur IS
1696     SELECT 'Dist Total <> Invoice Line Amount'
1697     FROM   ap_invoice_lines AIL, ap_invoice_distributions D
1698     WHERE  AIL.invoice_id  = D.invoice_id
1699     AND    AIL.line_number = p_line_number
1700     AND    AIL.invoice_id  = p_invoice_id
1701     AND    AIL.line_number = D.invoice_line_number
1702     AND    (D.line_type_lookup_code <> 'RETAINAGE'
1703     	    OR (AIL.line_type_lookup_code = 'RETAINAGE RELEASE'
1704     	        and D.line_type_lookup_code = 'RETAINAGE'))
1705     AND    (AIL.line_type_lookup_code <> 'ITEM'
1706             or (AIL.line_type_lookup_code = 'ITEM'
1707                 and (D.prepay_distribution_id IS NULL
1708                      or (D.prepay_distribution_id IS NOT NULL
1709                          and D.line_type_lookup_code NOT IN ('PREPAY', 'REC_TAX', 'NONREC_TAX')))))
1710     GROUP BY AIL.invoice_id, AIL.line_number, AIL.amount
1711     HAVING AIL.amount <> nvl(SUM(nvl(D.amount,0)),0);
1712 
1713     current_calling_sequence   VARCHAR2(4000);
1714     debug_info                 VARCHAR2(240);
1715     l_test_var                 VARCHAR2(50);
1716 
1717   BEGIN
1718       -------------------------------------------------------------
1719       current_calling_sequence := 'AP_INVOICE_LINES_UTILITY_PKG - Is_Line_Fully_Distributed';
1720       debug_info := 'Is_Line_Fully_Distributed - Open cursor';
1721       -------------------------------------------------------------
1722 
1723       OPEN  Dist_Var_Cur;
1724       FETCH Dist_Var_Cur
1725        INTO l_test_var;
1726       CLOSE Dist_Var_Cur;
1727 
1728       RETURN (l_test_var IS NULL);
1729 
1730   EXCEPTION
1731     WHEN OTHERS THEN
1732       IF (SQLCODE <> -20001) then
1733         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1734         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1735         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1736         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||P_Invoice_Id);
1737         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1738       END IF;
1739 
1740       IF (Dist_Var_Cur%ISOPEN) THEN
1741         CLOSE Dist_Var_Cur;
1742       END IF;
1743 
1744       APP_EXCEPTION.RAISE_EXCEPTION;
1745 
1746   END Is_Line_Fully_Distributed;
1747 
1748 /*=============================================================================
1749  |  FUNCTION - Is_PO_RCV_Amount_Exceeded
1750  |
1751  |  DESCRIPTION
1752  |    This function returns TRUE if the reversal of the line makes the
1753  |    quantity or amount billed go below 0.  It returns FALSE otherwise.
1754  |
1755  |  PARAMETERS
1756  |      P_Invoice_Id - Invoice Id
1757  |      P_Line_Number - line number
1758  |      P_Calling_Sequence - debug usage
1759  |
1760  |  KNOWN ISSUES:
1761  |
1762  |  NOTES:
1763  |
1764  |  MODIFICATION HISTORY
1765  |  Date         Author             Description of Change
1766  |  30-JUL-2003  SYIDNER            Creation
1767  |
1768  *============================================================================*/
1769 
1770   FUNCTION Is_PO_RCV_Amount_Exceeded(
1771              P_Invoice_Id           IN NUMBER,
1772              P_Line_Number          IN NUMBER,
1773              P_Calling_sequence     IN VARCHAR2) RETURN BOOLEAN
1774 
1775   IS
1776     CURSOR Invoice_Validation IS
1777     SELECT count(*)
1778       FROM po_distributions_all POD,
1779            ap_invoice_distributions AID
1780      WHERE POD.po_distribution_id = AID.po_distribution_id
1781        AND AID.invoice_id = P_Invoice_Id
1782        AND POD.org_id = AID.org_id
1783        AND AID.invoice_line_number = P_Line_Number
1784        AND NVL(AID.reversal_flag,'N')<>'Y'
1785        AND ( NVL(POD.quantity_billed, 0) -
1786              decode( AID.dist_match_type,
1787                      'PRICE_CORRECTION',  0,
1788                      'AMOUNT_CORRECTION', 0,    /* Ampunt Based Matching */
1789                      'ITEM_TO_SERVICE_PO', 0,
1790                      'ITEM_TO_SERVICE_RECEIPT', 0,
1791                      nvl( AID.corrected_quantity,0 ) +
1792                      nvl( AID.quantity_invoiced,0 ) ) < 0
1793              OR
1794              NVL(POD.amount_billed, 0) - NVL(AID.amount, 0) < 0 );
1795 
1796     l_invoice_id               ap_invoices_all.invoice_id%TYPE;
1797     current_calling_sequence   VARCHAR2(4000);
1798     debug_info                 VARCHAR2(240);
1799     l_po_dist_count            NUMBER := 0;
1800     l_return_var               BOOLEAN := FALSE;
1801 
1802 
1803   BEGIN
1804       current_calling_sequence := 'AP_INVOICE_LINES_UTILITY_PKG - Is_PO_RCV_Amount_Exceeded';
1805       -------------------------------------------------------------
1806       debug_info := 'Is_PO_RCV_Amount_Exceeded - Open cursor';
1807       -------------------------------------------------------------
1808 
1809       OPEN invoice_validation;
1810       FETCH invoice_validation INTO l_po_dist_count;
1811       CLOSE invoice_validation;
1812 
1813       -------------------------------------------------------------
1814       debug_info := 'Check if quantity_billed on po_distribution is
1815                      brought to 0';
1816       -------------------------------------------------------------
1817       IF (l_po_dist_count > 0  ) THEN
1818         l_return_var := TRUE;
1819       END IF;
1820 
1821     RETURN l_return_var;
1822 
1823   EXCEPTION
1824     WHEN OTHERS THEN
1825       if (SQLCODE <> -20001) then
1826         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1827         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1828         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1829         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||P_Invoice_Id);
1830         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1831       end if;
1832       debug_info := debug_info || 'Error occurred';
1833 
1834       IF ( invoice_validation%ISOPEN ) THEN
1835         CLOSE invoice_validation;
1836       END IF;
1837 
1838       APP_EXCEPTION.RAISE_EXCEPTION;
1839 
1840   END Is_PO_RCV_Amount_Exceeded;
1841 
1842  /*=============================================================================
1843  |  Public FUNCTION Is_Invoice_Fully_Distributed
1844  |
1845  |    Check if an invoice is fully distributed or not. An invoice is
1846  |    fully distributed if all of its lines were distributed.
1847  |
1848  |  PROGRAM FLOW
1849  |
1850  |       return TRUE  - if invoice is fully distributed
1851  |       return FALSE - otherwise.
1852  |
1853  |  MODIFICATION HISTORY
1854  |  Date          Author               Description of Change
1855  |  24-FEB-2004   ISartawi             Created
1856  *============================================================================*/
1857 
1858 FUNCTION Is_Invoice_Fully_Distributed (
1859           P_invoice_id  IN NUMBER) RETURN BOOLEAN
1860 IS
1861   l_count NUMBER;
1862 BEGIN
1863 
1864   -- This function is used to determine if the invoice is fully
1865   -- distributed or not. The invoice is fully distributed if all
1866   -- its lines were distributed. In this case the line will have
1867   -- generate_dists = 'D'. If one line had generate_dists <> 'D'
1868   -- then the invoice is not fully distributed.
1869 
1870   SELECT COUNT(*)
1871     INTO l_count
1872     FROM ap_invoice_lines
1873    WHERE invoice_id      = p_invoice_id
1874      AND generate_dists <> 'D'
1875      AND ROWNUM = 1;
1876 
1877   IF l_count > 0 THEN
1878     RETURN (FALSE);  -- The Invoice is not fully distributed
1879   ELSE
1880     RETURN (TRUE);   -- The Invoice is fully distributed
1881   END IF;
1882 
1883 END Is_Invoice_Fully_Distributed;
1884 
1885 
1886 --Invoice Lines: Distributions
1887 /*=============================================================================
1888 |  Public FUNCTION Pending_Alloc_Exists_Chrg_Line
1889 |
1890 |  Check if the particular invoice charge line contains outstanding allocation
1891 |      rule exists (not yest applied)
1892 |
1893 |  PROGRAM FLOW
1894 |
1895 |       return TRUE  - if line contains outstanding allocations
1896 |       return FALSE - otherwise.
1897 |
1898 |  MODIFICATION HISTORY
1899 |  Date           Author               Description of Change
1900 |  01/27/2004     surekha myadam       Created
1901 *============================================================================*/
1902   FUNCTION Pending_Alloc_Exists_Chrg_Line
1903                            (p_Invoice_Id        Number,
1904                             p_Line_Number       Number,
1905                             p_Calling_Sequence  Varchar2) Return Boolean Is
1906     dummy number := 0;
1907     current_calling_sequence   Varchar2(2000);
1908     debug_info                           Varchar2(100);
1909   Begin
1910     -- Update the calling sequence
1911     --
1912     current_calling_sequence :=
1913     'AP_INVOICE_LINES_UTILITY_PKG.Pending_Alloc_Exists_Chrg_Line <-'||
1914                             p_Calling_Sequence;
1915     debug_info := 'Select from ap_allocatin_rules';
1916 
1917     Select count(*)
1918     Into   dummy
1919     From   ap_allocation_rules  AR
1920     Where  AR.invoice_id = p_Invoice_Id
1921     And    AR.chrg_invoice_line_number = p_line_number
1922     And    AR.status = 'PENDING';
1923 
1924     If (dummy >= 1) Then
1925       return  TRUE;
1926     End if;
1927 
1928     return FALSE;
1929   Exception
1930     WHEN OTHERS THEN
1931       If (SQLCODE <> -20001) Then
1932         FND_MESSAGE.SET_NAME('SQLAP', 'AP_DEBUG');
1933         FND_MESSAGE.SET_TOKEN('ERROR', SQLERRM);
1934         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', current_calling_sequence);
1935         FND_MESSAGE.SET_TOKEN('PARAMETERS', 'Invoice Id = '||p_Invoice_id
1936                               ||', line number = '|| p_Line_Number);
1937         FND_MESSAGE.SET_TOKEN('DEBUG_INFO', debug_info);
1938       End If;
1939       APP_EXCEPTION.RAISE_EXCEPTION;
1940 End Pending_Alloc_Exists_Chrg_Line;
1941 
1942 
1943 /*=============================================================================
1944 |  Public FUNCTION Is_Line_a_Correction
1945 |
1946 |  Check if the particular invoice line is correcting some other invoice line.
1947 |
1948 |  PROGRAM FLOW
1949 |
1950 |       return TRUE  - if line is a correction
1951 |       return FALSE - otherwise.
1952 |
1953 |  MODIFICATION HISTORY
1954 |  Date           Author               Description of Change
1955 |  01-JUL-2004    Surekha Myadam       Created
1956 *============================================================================*/
1957 FUNCTION Is_Line_a_Correction(
1958                 P_Invoice_Id           IN NUMBER,
1959 		P_Line_Number          IN NUMBER,
1960 		P_Calling_sequence     IN VARCHAR2) RETURN BOOLEAN IS
1961 
1962 is_correction varchar2(1) := 'N';
1963 BEGIN
1964 
1965    SELECT 'Y'
1966    INTO is_correction
1967    FROM ap_invoice_lines
1968    WHERE invoice_id = p_invoice_id
1969    AND line_number = p_line_number
1970    AND corrected_inv_id IS NOT NULL
1971    AND corrected_line_number IS NOT NULL;
1972 
1973 
1974    IF (is_correction = 'Y') THEN
1975     return (TRUE);
1976    ELSE
1977     return (FALSE);
1978    END IF;
1979 
1980 EXCEPTION WHEN OTHERS THEN
1981   RETURN(FALSE);
1982 
1983 END Is_Line_a_Correction;
1984 
1985 
1986 
1987 /*=============================================================================
1988 |  Public FUNCTION Line_Referred_By_Adjustment
1989 |
1990 |  Check if the particular invoice line has been adjusted by PO Price Adjustment
1991 |
1992 |  PROGRAM FLOW
1993 |
1994 |       return TRUE  - if line is adjusted by PO Price Adjustment
1995 |       return FALSE - otherwise.
1996 |
1997 |  MODIFICATION HISTORY
1998 |  Date           Author               Description of Change
1999 |  01-JUL-2004    Surekha Myadam       Created
2000 *============================================================================*/
2001 FUNCTION Line_Referred_By_Adjustment(
2002                 P_Invoice_Id           IN NUMBER,
2003                 P_Line_Number          IN NUMBER,
2004                 P_Calling_sequence     IN VARCHAR2) RETURN BOOLEAN IS
2005  l_count NUMBER := 0;
2006 BEGIN
2007 
2008   SELECT count(*)
2009   INTO l_count
2010   FROM ap_invoice_lines_all
2011   WHERE corrected_inv_id = p_invoice_id
2012   AND corrected_line_number = p_line_number
2013   AND line_type_lookup_code IN ('RETROITEM')
2014   AND line_source = 'PO PRICE ADJUSTMENT'
2015   AND match_type = 'RETRO PRICE ADJUSTMENT';
2016 
2017 
2018   IF (l_count > 0) THEN
2019     RETURN (TRUE);
2020   ELSE
2021     RETURN (FALSE);
2022   END IF;
2023 
2024 END Line_Referred_By_Adjustment;
2025 
2026 
2027 /*=============================================================================
2028 |  Public FUNCTION Is_Line_a_Adjustment
2029 |
2030 |  Check if the particular invoice line has adjusted (po price adjust)
2031 |  some other invoice line.
2032 |
2033 |  PROGRAM FLOW
2034 |
2035 |       return TRUE  - if line is a po price adjustment line.
2036 |       return FALSE - otherwise.
2037 |
2038 |  MODIFICATION HISTORY
2039 |  Date           Author               Description of Change
2040 |  01-JUL-2004    Surekha Myadam       Created
2041 *============================================================================*/
2042 FUNCTION Is_Line_a_Adjustment(
2043                 P_Invoice_Id           IN NUMBER,
2044                 P_Line_Number          IN NUMBER,
2045                 P_Calling_sequence     IN VARCHAR2) RETURN BOOLEAN IS
2046  is_po_price_adjustment VARCHAR2(1) := 'N';
2047 BEGIN
2048 
2049   SELECT 'Y'
2050   INTO is_po_price_adjustment
2051   FROM ap_invoice_lines_all
2052   WHERE invoice_id = p_invoice_id
2053   AND line_number = p_line_number
2054   AND line_type_lookup_code = 'RETROITEM'
2055   AND line_source = 'PO PRICE ADJUSTMENT'
2056   AND match_type = 'RETRO PRICE ADJUSTMENT';
2057 
2058   IF (is_po_price_adjustment = 'Y') THEN
2059     RETURN(TRUE);
2060   ELSE
2061     RETURN(FALSE);
2062   END IF;
2063 
2064  EXCEPTION WHEN OTHERS THEN
2065    RETURN(FALSE);
2066 
2067 END Is_Line_a_Adjustment;
2068 
2069 
2070 /*=============================================================================
2071 | Public FUNCTION Is_Line_a_Prepay
2072 |
2073 | Check if the particular invoice line is a prepayment application/unapplication
2074 |  (Normally this can be identified by looking at the line_type_lookup_code
2075 |   but from the place where this is called (etax windows) the line_type is not
2076 |   available, hence need to code this function.)
2077 |
2078 |  PROGRAM FLOW
2079 |
2080 |       return TRUE  - if line of type PREPAY.
2081 |       return FALSE - otherwise.
2082 |
2083 |  MODIFICATION HISTORY
2084 |  Date           Author               Description of Change
2085 |  01-JUL-2004    Surekha Myadam       Created
2086 *============================================================================*/
2087 FUNCTION Is_Line_a_Prepay(
2088                 P_Invoice_Id           IN NUMBER,
2089                 P_Line_Number          IN NUMBER,
2090                 P_Calling_sequence     IN VARCHAR2) RETURN BOOLEAN IS
2091  is_prepayment varchar2(1) := 'N';
2092 BEGIN
2093 
2094   SELECT 'Y'
2095   INTO is_prepayment
2096   FROM ap_invoice_lines
2097   WHERE invoice_id = p_invoice_id
2098   AND line_number = p_line_number
2099   AND line_type_lookup_code = 'PREPAY';
2100 
2101   IF (is_prepayment = 'Y') THEN
2102     return (TRUE);
2103   ELSE
2104     return (FALSE);
2105   END IF;
2106 
2107 EXCEPTION WHEN OTHERS THEN
2108 
2109   return(FALSE);
2110 
2111 END Is_Line_a_Prepay;
2112 
2113 Function Get_Retained_Amount
2114 		(p_line_location_id IN NUMBER,
2115 		 p_match_amount	    IN NUMBER) RETURN NUMBER IS
2116 
2117   l_ret_status		Varchar2(100);
2118   l_msg_data		Varchar2(4000);
2119 
2120   l_currency_code       PO_HEADERS_ALL.currency_code%type;
2121 
2122   l_line_loc_tab	PO_TBL_NUMBER;
2123   l_line_loc_amt_tab	PO_TBL_NUMBER;
2124   l_amt_to_retain_tab	PO_TBL_NUMBER;
2125 
2126   l_retained_amount     Number;
2127 
2128 Begin
2129 
2130   If p_line_location_id Is Not Null Then
2131 
2132      l_line_loc_tab := po_tbl_number();
2133      l_line_loc_tab.extend;
2134      l_line_loc_tab(l_line_loc_tab.last) := p_line_location_id;
2135 
2136      l_line_loc_amt_tab := po_tbl_number();
2137      l_line_loc_amt_tab.extend;
2138      l_line_loc_amt_tab(l_line_loc_amt_tab.last) := p_match_amount;
2139 
2140      -- bug6882900
2141      BEGIN
2142 
2143 	SELECT currency_code
2144 	INTO l_currency_code
2145 	FROM po_headers_all
2146 	WHERE po_header_id IN
2147 	  (SELECT po_header_id
2148 	   FROM po_line_locations_all
2149 	   WHERE line_location_id = p_line_location_id)
2150 	AND rownum < 2;
2151 
2152      EXCEPTION
2153         WHEN OTHERS THEN
2154 	  NULL;
2155 
2156      END;
2157 
2158 
2159      PO_AP_INVOICE_MATCH_GRP.get_amount_to_retain(
2160 		  p_api_version			=> 1.0
2161 		, p_line_location_id_tbl        => l_line_loc_tab
2162 		, p_line_loc_match_amt_tbl      => l_line_loc_amt_tab
2163 		, x_return_status		=> l_ret_status
2164 		, x_msg_data                    => l_msg_data
2165 		, x_amount_to_retain_tbl        => l_amt_to_retain_tab);
2166 
2167      IF l_amt_to_retain_tab.count > 0 THEN
2168 
2169         l_retained_amount := -1 * l_amt_to_retain_tab(l_amt_to_retain_tab.last);
2170 
2171      END IF;
2172 
2173   End If;
2174 
2175   -- bug6882900
2176   Return (ap_utilities_pkg.ap_round_currency(l_retained_amount, l_currency_code));
2177 
2178 End Get_Retained_Amount;
2179 
2180 /* ==========================================================================================
2181  *  Procedure manual_withhold_tax()
2182  *  Objective update ap_payment_schedules.remaining_amount for manual entry
2183  *  withholding lines
2184  *  This procedire has been moved from payment schedules library since it did
2185  *  not consider the
2186  *  ap lines model
2187  *  This PROCEDURE is added for Bug 6917289
2188  * =============================================================================================*/
2189 PROCEDURE Manual_Withhold_Tax(p_invoice_id IN number
2190                              ,p_manual_withhold_amount IN number
2191                              ) IS
2192 
2193  l_inv_amt_remaining  ap_payment_schedules.amount_remaining%TYPE := 0;
2194  l_gross_amount       ap_payment_schedules.gross_amount%TYPE := 0;
2195  l_payment_cross_rate ap_invoices_all.payment_cross_rate%TYPE :=0;
2196  l_payment_currency_code ap_invoices_all.payment_currency_code%TYPE;
2197 
2198  -- Debug variables
2199  l_debug_loc                   VARCHAR2(30) := 'Manual_Withhold_Tax';
2200  l_curr_calling_sequence       VARCHAR2(2000);
2201  l_debug_info                  VARCHAR2(2000);
2202 
2203 
2204 BEGIN
2205 
2206   l_curr_calling_sequence := 'AP_INVOICE_LINES_UTILITY_PKG.'||l_debug_loc;
2207 
2208   SELECT nvl(payment_cross_rate,0), payment_currency_code
2209     INTO l_payment_cross_rate, l_payment_currency_code
2210     FROM ap_invoices_all
2211    WHERE invoice_id = p_invoice_id;
2212 
2213   SELECT sum(nvl(amount_remaining,0)), sum(nvl(gross_amount,0))
2214     INTO l_inv_amt_remaining, l_gross_amount
2215     FROM ap_payment_schedules
2216    WHERE invoice_id = p_invoice_id;
2217 
2218   l_debug_info := 'Updating payment schedules due a manual withholding tax';
2219 
2220   IF ((l_inv_amt_remaining <> 0) AND (p_manual_withhold_amount is not null))
2221   THEN
2222           update ap_payment_schedules
2223              set amount_remaining = (amount_remaining +
2224                                      ap_utilities_pkg.ap_round_currency(
2225                         (amount_remaining * (p_manual_withhold_amount/l_inv_amt_remaining)
2226                          * l_payment_cross_rate), l_payment_currency_code))
2227            where invoice_id = p_invoice_id;
2228 
2229   ELSIF ((l_inv_amt_remaining = 0) and (p_manual_withhold_amount is not null))
2230      THEN
2231           update ap_payment_schedules
2232              set amount_remaining = (amount_remaining +
2233                                      ap_utilities_pkg.ap_round_currency(
2234                      (gross_amount * (p_manual_withhold_amount/l_gross_amount)
2235                       * l_payment_cross_rate), l_payment_currency_code)),
2236                  payment_status_flag = DECODE(payment_status_flag,'Y','P',payment_status_flag)
2237            where invoice_id = p_invoice_id;
2238 
2239           update ap_invoices
2240              set payment_status_flag = DECODE(payment_status_flag,'Y','P',payment_status_flag)
2241            where invoice_id = p_invoice_id ;
2242 
2243   END IF;
2244 
2245 EXCEPTION
2246   WHEN NO_DATA_FOUND THEN
2247        NULL;
2248   WHEN OTHERS THEN
2249        IF (SQLCODE <> -20001) THEN
2250            FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
2251            FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
2252            FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE', l_curr_calling_sequence);
2253            FND_MESSAGE.SET_TOKEN('PARAMETERS',
2254                           'P_Invoice_Id  = '|| p_invoice_id
2255                       ||', p_manual_withhold_amount= '|| to_char(p_manual_withhold_amount));
2256            FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
2257        END IF;
2258 
2259        APP_EXCEPTION.RAISE_EXCEPTION;
2260 
2261 END Manual_Withhold_Tax;
2262 
2263 /* ==================================================================================
2264  *  Function get_awt_flag()
2265  *  Objective Retrun the awt_flag for a given invoice_id and invoice_line_number
2266  *  This function is called from the invoice lines library
2267  *  Bug 6917289
2268  * ==================================================================================*/
2269 
2270 FUNCTION get_awt_flag(
2271              p_invoice_id  IN  NUMBER,
2272              p_line_number IN  NUMBER )
2273   RETURN VARCHAR2
2274   IS
2275       l_awt_flag ap_invoice_distributions_all.awt_flag%TYPE;
2276 
2277 BEGIN
2278 
2279   SELECT awt_flag
2280     INTO l_awt_flag
2281     FROM ap_invoice_distributions_all
2282    WHERE invoice_id = p_invoice_id
2283      AND invoice_line_number = p_line_number
2284      AND rownum = 1;
2285 
2286   IF l_awt_flag is null THEN
2287      RETURN ('Z');
2288   ELSE
2289      RETURN (l_awt_flag);
2290   END IF;
2291 
2292 EXCEPTION
2293   WHEN NO_DATA_FOUND THEN
2294        RETURN ('B');
2295   WHEN Others THEN
2296        RETURN ('Z');
2297 END get_awt_flag;
2298 
2299 END  AP_INVOICE_LINES_UTILITY_PKG;