DBA Data[Home] [Help]

PACKAGE BODY: APPS.AP_CANCEL_PKG

Source


1 PACKAGE BODY AP_CANCEL_PKG AS
2 /* $Header: apicancb.pls 120.58 2011/02/24 05:07:06 mayyalas ship $ */
3 
4   G_CURRENT_RUNTIME_LEVEL      NUMBER                := FND_LOG.G_CURRENT_RUNTIME_LEVEL;
5   G_LEVEL_UNEXPECTED           CONSTANT NUMBER       := FND_LOG.LEVEL_UNEXPECTED;
6   G_LEVEL_ERROR                CONSTANT NUMBER       := FND_LOG.LEVEL_ERROR;
7   G_LEVEL_EXCEPTION            CONSTANT NUMBER       := FND_LOG.LEVEL_EXCEPTION;
8   G_LEVEL_EVENT                CONSTANT NUMBER       := FND_LOG.LEVEL_EVENT;
9   G_LEVEL_PROCEDURE            CONSTANT NUMBER       := FND_LOG.LEVEL_PROCEDURE;
10   G_LEVEL_STATEMENT            CONSTANT NUMBER       := FND_LOG.LEVEL_STATEMENT;
11   G_MODULE_NAME                CONSTANT VARCHAR2(50) := 'AP.PLSQL.AP_CANCEL_PKG.';
12 
13 -- Forward declaration of Payment Request Cancellation Subscription event
14 -- procedure. This will be only called if Payment Request is being cancelled
15 -- From Oracle Payables.
16 PROCEDURE Subscribe_To_Cancel_Event
17                       (P_Event_Type         IN             VARCHAR2,
18                        P_Invoice_ID         IN             NUMBER,
19                        P_Application_ID     IN             NUMBER,
20                        P_Return_Status      OUT     NOCOPY VARCHAR2,
21                        P_Msg_Count          OUT     NOCOPY NUMBER,
22                        P_Msg_Data           OUT     NOCOPY VARCHAR2,
23                        P_Calling_Sequence   IN             VARCHAR2);
24 
25 /*=============================================================================
26  |  PROCEDURE Is_Invoice_Cancellable
27  |
28  |      Check if the line is cancellable
29  |
30  |  PROGRAM FLOW
31  |      0. If invoice contains distribution that does not have open GL period
32  |         return FALSE
33  |      1. If invoice has an effective payment, return FALSE
34  |      2. If invoice is selected for payment, return FALSE
35  |      3. If invoice is already cancelled, return FALSE
36  |      4. If invoice is credited invoice, return FALSE
37  |      5. If invoices have been applied against this invoice, return FALSE
38  |      6. If invoice is matched to Finally Closed PO's, return FALSE
39  |      7. If project related invoices have pending adjustments, return FALSE
40  |      8. If cancelling will cause qty_billed or amount_billed to less
41  |         than 0, return FALSE
42  |      9. If none of above, invoice is cancellable return Ture
43  |  NOTES
44  |
45  |  MODIFICATION HISTORY
46  |  Date         Author             Description of Change
47  |
48  *============================================================================*/
49   Function Is_Invoice_Cancellable(
50                P_invoice_id        IN NUMBER,
51                P_error_code           OUT NOCOPY VARCHAR2,   /* Bug 5300712 */
52                P_debug_info        IN OUT NOCOPY VARCHAR2,
53                P_calling_sequence  IN            VARCHAR2) RETURN BOOLEAN
54   IS
55 
56     CURSOR verify_no_pay_batch IS
57     SELECT checkrun_id
58       FROM ap_payment_schedules
59      WHERE invoice_id = P_invoice_id
60      FOR UPDATE NOWAIT;
61 
62    -- Bug5497058
63    CURSOR qty_per_dist_negtive_count_cur IS
64    SELECT count(*)
65    FROM ap_invoice_distributions AID,
66           po_distributions_ap_v POD,
67 	  po_line_locations PLL,
68 	  po_lines PL,
69           ap_invoices AIV
70     WHERE POD.po_distribution_id = AID.po_distribution_id
71       AND POD.line_location_id = PLL.line_location_id
72       AND PLL.po_line_id = PL.po_line_id
73       AND AIV.invoice_id=AID.invoice_id
74       AND NVL(AID.reversal_flag, 'N') <> 'Y'
75       AND AID.invoice_id = P_invoice_id
76        -- Bug 5590826. For amount related decode
77       AND AID.line_type_lookup_code IN ('ITEM', 'ACCRUAL', 'IPV')
78    HAVING (DECODE(AIV.invoice_type_lookup_code,'PREPAYMENT',
79              SUM(NVL(POD.quantity_financed, 0)),SUM(NVL(POD.quantity_billed, 0))
80 	   ) -
81              SUM(round(decode(AID.dist_match_type,
82                              'PRICE_CORRECTION', 0,
83                              'AMOUNT_CORRECTION', 0,
84                              'ITEM_TO_SERVICE_PO', 0,
85                              'ITEM_TO_SERVICE_RECEIPT', 0,
86                               nvl( AID.quantity_invoiced, 0 ) +
87                               nvl( AID.corrected_quantity,0 )
88 			     ) *
89 	               po_uom_s.po_uom_convert(AID.matched_uom_lookup_code,         --bug5844328
90 		                           nvl(PLL.unit_meas_lookup_code,
91 					       PL.unit_meas_lookup_code),
92 					   PL.item_id), 15)
93 	        ) < 0
94            OR DECODE(AIV.invoice_type_lookup_code,'PREPAYMENT',
95               SUM(NVL(POD.amount_financed, 0)),SUM(NVL(POD.amount_billed, 0))) -
96               SUM(NVL(AID.amount, 0)) < 0 )
97     GROUP BY AIV.invoice_type_lookup_code,AID.po_distribution_id;
98 
99 
100     CURSOR dist_gl_date_cur IS
101     SELECT accounting_date
102       FROM ap_invoice_distributions AID
103      WHERE AID.invoice_id = P_invoice_id
104        AND NVL(AID.reversal_flag, 'N') <> 'Y';
105 
106     TYPE date_tab is TABLE OF DATE INDEX BY BINARY_INTEGER;
107     l_gl_date_list              date_tab;
108     i                           BINARY_INTEGER := 1;
109     l_open_gl_date              DATE :='';
110     l_open_period               gl_period_statuses.period_name%TYPE := '';
111 
112     l_curr_calling_sequence     VARCHAR2(2000);
113     l_debug_info                VARCHAR2(100):= 'Is_Invoice_Cancellable';
114 
115     l_checkrun_id               NUMBER;
116     l_cancel_count              NUMBER := 0;
117     l_project_related_count     NUMBER := 0;
118     l_payment_count             NUMBER := 0;
119     l_final_close_count         NUMBER := 0;
120     l_prepay_applied_flag       VARCHAR2(1);
121     l_po_dist_count             NUMBER := 0;
122     l_credited_inv_flag         BOOLEAN := FALSE;
123     l_pa_message_name           VARCHAR2(50);
124     l_org_id                    NUMBER;
125     l_final_closed_shipment_count NUMBER;
126     l_allow_cancel              VARCHAR2(1) := 'Y';
127     l_return_code               VARCHAR2(30);
128     l_enc_enabled               VARCHAR2(1);  --Bug6009101
129     l_po_not_approved           VARCHAR2(1);  --Bug6009101
130 
131 
132   BEGIN
133     l_curr_calling_sequence := 'AP_INVOICE_PKG.IS_INVOICE_CANCELLABLE<-' ||
134                                P_calling_sequence;
135 
136     /*-----------------------------------------------------------------+
137      |  Step 0 - If invoice contain distribtuion which does not have   |
138      |           OPEN gl period name, return FALSE                     |
139      +-----------------------------------------------------------------*/
140     /* bug 4942638. Move the next select here */
141     l_debug_info := 'Get the org_id for the invoice';
142 
143     SELECT org_id
144     INTO   l_org_id
145     FROM   ap_invoices_all
146     WHERE  invoice_id = p_invoice_id;
147 
148     l_debug_info := 'Check if inv distribution has open period';
149 
150     OPEN dist_gl_date_Cur;
151     FETCH dist_gl_date_Cur
152     BULK COLLECT INTO l_gl_date_list;
153     CLOSE dist_gl_date_Cur;
154 
155     /* Bug 5354259. Added the following IF condition as for
156        For unvalidated invoice case most of the cases there wil be no distributions */
157     IF l_gl_date_list.count > 0 THEN
158     FOR i in l_gl_date_list.FIRST..l_gl_date_list.LAST
159     LOOP
160       /* bug 4942638. Added l_org_id in the next two function call */
161       l_open_period := ap_utilities_pkg.get_current_gl_date(l_gl_date_list(i), l_org_id);
162       IF ( l_open_period IS NULL ) THEN
163         ap_utilities_pkg.get_open_gl_date(
164                  l_gl_date_list(i),
165                  l_open_period,
166                  l_open_gl_date,
167                  l_org_id);
168         IF ( l_open_period IS NULL ) THEN
169           p_error_code := 'AP_DISTS_NO_OPEN_FUT_PERIOD';
170           p_debug_info := l_debug_info;
171           RETURN FALSE;
172         END IF;
173       END IF;
174     END LOOP;
175     END IF;
176 
177     /*-----------------------------------------------------------------+
178      |  Step 1 - If invoice has an effective payment, return FALSE     |
179      |           This include the check of if invoice itself is a      |
180      |           PREPAYMENT type invoice - Actively referenced         |
181      |           prepayment type invoice has to be fully paid when it  |
182      |           is applied.                                           |
183      +-----------------------------------------------------------------*/
184 
185     l_debug_info := 'Check if invoice has an effective payment';
186 	--Bug10034598: Commected below query
187     /* SELECT   count(*)
188       INTO   l_payment_count
189       FROM   ap_invoice_payments P,ap_payment_schedules PS
190      WHERE   P.invoice_id=PS.invoice_id
191        AND   P.invoice_id = P_invoice_id
192        AND   PS.payment_status_flag <> 'N'
193        AND   nvl(P.reversal_flag,'N') <> 'Y'
194        AND   P.amount is not NULL
195        AND   exists ( select 'non void check'
196                       from ap_checks A
197                       where A.check_id = P.check_id
198                         and void_date is null);*/--Bug 6135172
199 	--Bug10034598 : Removed join with ap_payment_schedules
200 	SELECT COUNT(*)
201 	INTO   l_payment_count
202 	FROM ap_invoice_payments P
203 	WHERE P.invoice_id            = P_invoice_id
204 	AND NVL(P.reversal_flag,'N') <> 'Y'
205 	AND P.amount                 IS NOT NULL
206 	AND EXISTS
207 		(SELECT 'non void check'
208 		  FROM ap_checks A
209 		  WHERE A.check_id = P.check_id
210 		  AND void_date   IS NULL
211 		  );
212 
213     IF ( l_payment_count <> 0 ) THEN
214       P_error_code := 'AP_INV_CANCEL_EFF_PAYMENT';
215       P_debug_info := l_debug_info;
216       RETURN FALSE;
217     END IF;
218 
219     /*-----------------------------------------------------------------+
220      |  Step 2. If invoice is selected for payment, return FALSE       |
221      +-----------------------------------------------------------------*/
222 
223     l_debug_info := 'Check if invoice is selected for payment';
224 
225     BEGIN
226       OPEN verify_no_pay_batch;
227       LOOP
228       FETCH verify_no_pay_batch
229        INTO l_checkrun_id;
230       EXIT WHEN verify_no_pay_batch%NOTFOUND;
231         IF l_checkrun_id IS NOT NULL THEN
232           P_error_code := 'AP_INV_CANCEL_SEL_PAYMENT';
233           P_debug_info := l_debug_info || 'with no check run id';
234           COMMIT;
235           RETURN FALSE;
236         END IF;
237       END LOOP;
238 
239     EXCEPTION
240       WHEN OTHERS THEN
241         IF ( verify_no_pay_batch%ISOPEN ) THEN
242           CLOSE verify_no_pay_batch;
243         END IF;
244         P_error_code := 'AP_INV_CANCEL_PS_LOCKED';
245         P_debug_info := l_debug_info || 'With exceptions';
246         COMMIT;
247         RETURN FALSE;
248     END;
249 
250     /*-----------------------------------------------------------------+
251      |  Step 3. If invoice is already cancelled, return FALSE          |
252      +-----------------------------------------------------------------*/
253 
254     l_debug_info := 'Check if invoice is already cancelled';
255 
256     SELECT count(*)
257     INTO   l_cancel_count
258     FROM   ap_invoices
259     WHERE  invoice_id = P_invoice_id
260     AND    cancelled_date IS NOT NULL;
261 
262     IF (l_cancel_count > 0) THEN
263       P_error_code := 'AP_INV_CANCEL_ALREADY_CNCL';
264       P_debug_info := l_debug_info;
265       RETURN FALSE;
266     END IF;
267 
268     /*-----------------------------------------------------------------+
269      |  Step 4. If invoice is a credited invoice return FALSE          |
270      +-----------------------------------------------------------------*/
271     l_debug_info := 'Check if invoice is a credited invoice';
272 
273     l_credited_inv_flag := AP_INVOICES_UTILITY_PKG.Is_Inv_Credit_Referenced(
274                                P_invoice_id);
275 
276     IF (l_credited_inv_flag <> FALSE ) THEN
277       P_error_code := 'AP_INV_IS_CREDITED_INV';
278       P_debug_info := l_debug_info;
279       RETURN FALSE;
280     END IF;
281 
282     /*-----------------------------------------------------------------+
283      |  Step 5. If invoices have been applied against this invoice     |
284      |          return FALSE                                           |
285      +-----------------------------------------------------------------*/
286 
287     l_debug_info := 'Check if invoices have been applied against this invoice';
288 
289     l_prepay_applied_flag :=
290         AP_INVOICES_UTILITY_PKG.get_prepayments_applied_flag(P_invoice_id);
291 
292     IF (nvl(l_prepay_applied_flag,'N') = 'Y') THEN
293       P_error_code := 'AP_INV_PP_NO_CANCEL';
294       P_debug_info := l_debug_info;
295       RETURN FALSE;
296     END IF;
297 
298     /*-----------------------------------------------------------------+
299      |  Step 6. If invoice is matched to a Finally Closed PO, return   |
300      |          FALSE                                                  |
301      +-----------------------------------------------------------------*/
302 
303     l_debug_info := 'Check if invoice is matched to a finally closed PO';
304 
305     -- Bug fix:3488316
306     -- Following code in this step has been added for JFMIP related work.
307     -- This code has been modified only for federal customers, before modifying
308     -- this code please get the code verified with the developer/manager
309     -- who added this code.
310     /* bug 4942638. Move the next select for l_org_id at the begining */
311 
312     IF (FV_INSTALL.ENABLED (l_org_id)) THEN
313 
314        BEGIN
315 
316           SELECT 'N'
317           INTO l_allow_cancel
318           FROM ap_invoice_distributions AID,
319                po_distributions PD,
320                po_line_locations pll
321           WHERE aid.invoice_id = p_invoice_id
322           --AND aid.final_match_flag in ('N','Y')  For Bug 3489536
323           AND aid.po_distribution_id = pd.po_distribution_id
324           AND pll.line_location_id = pd.line_location_id
325           AND decode(pll.final_match_flag, 'Y', 'D', aid.final_match_flag) in ('N','Y') --Bug 3489536
326           AND pll.closed_code = 'FINALLY CLOSED'
327           AND rownum = 1;
328 
329           IF (l_allow_cancel = 'N') THEN
330              P_error_code := 'AP_INV_CANNOT_OPEN_SHIPMENT';
331              P_debug_info := l_debug_info;
332 	      RETURN(FALSE);
333           END IF;
334 
335        EXCEPTION
336         WHEN NO_DATA_FOUND THEN
337 
338           SELECT count(distinct pll.line_location_id)
339           INTO l_final_closed_shipment_count
340           FROM ap_invoice_distributions aid,
341                po_line_locations pll,
342                po_distributions pd
343           WHERE aid.invoice_id = p_invoice_id
344           AND aid.po_distribution_id = pd.po_distribution_id
345           AND pd.line_location_id = pll.line_location_id
346           --AND aid.final_match_flag = 'D' For bug 3489536
347           AND decode(pll.final_match_flag, 'Y', 'D', aid.final_match_flag) = 'D' --Bug 3489536
348           AND pll.closed_code = 'FINALLY CLOSED';
349 
350        END ;
351 
352        IF (l_final_closed_shipment_count > 1) THEN
353 
354             P_error_code := 'AP_INV_MUL_SHIP_FINALLY_CLOSED' ;
355 	        P_debug_info := l_debug_info;
356             RETURN(FALSE);
357 
358         END IF;
359 
360         IF (l_final_closed_shipment_count = 1) THEN
361 
362           l_debug_info := 'Open the Finally Closed PO Shipment ';
363           IF(NOT(FV_AP_CANCEL_PKG.OPEN_PO_SHIPMENT(p_invoice_id,
364                                                   l_return_code))) THEN
365 
366             P_error_code := 'AP_INV_CANNOT_OPEN_SHIPMENT';
367             P_debug_info := l_debug_info;
368             RETURN(FALSE);
369 
370           END IF;
371 
372         END IF;
373 
374     ELSE
375 
376 
377     SELECT count(*)
378     INTO   l_final_close_count
379     FROM   ap_invoice_lines AIL,
380            po_line_locations_ALL PL
381     WHERE  AIL.invoice_id = P_invoice_id
382     AND    AIL.po_line_location_id = PL.line_location_id
383     AND    AIL.org_id = PL.org_id
384     AND    PL.closed_code = 'FINALLY CLOSED';
385 
386     IF (l_final_close_count > 0) THEN
387       P_error_code := 'AP_INV_PO_FINALLY_CLOSED';
388       P_debug_info := l_debug_info;
389       RETURN FALSE;
390     END IF;
391     END IF;
392     /*-----------------------------------------------------------------+
393      |  Step 7. If projects have pending adjustments then return FALSE |
394      +-----------------------------------------------------------------*/
395     --
396     -- Bug 5349193
397     -- As suggested in the bug, this validation is commented in R12.
398     --
399 
400     /* SELECT count(*)
401     INTO   l_project_related_count
402     FROM   ap_invoices AI
403     WHERE  AI.invoice_id = P_invoice_id
404     AND    (AI.project_id is not null OR
405             exists (select 'X'
406                     from   ap_invoice_distributions AIL
407                     where  AIL.invoice_id = AI.invoice_id
408                     and    project_id is not null) OR
409             exists (select 'X'
410                     from   ap_invoice_distributions AID
411                     where  AID.invoice_id = AI.invoice_id
412                     and    project_id is not null));
413 
414     IF (l_project_related_count <> 0) THEN
415       l_pa_message_name := pa_integration.pending_vi_adjustments_exists(
416                                    P_invoice_id);
417       IF (l_pa_message_name <> 'N') THEN
418         P_error_code := l_pa_message_name;
419         P_debug_info := l_debug_info;
420         RETURN FALSE;
421       END IF;
422     END IF; */
423 
424     /*-----------------------------------------------------------------+
425      |  Step 8. if the quantity billed and amount on PO would be       |
426      |          reduced to less than zero then return FALSE            |
427      |          Always allow Reversal distributions to be cancelled    |
428      +-----------------------------------------------------------------*/
429 
430     BEGIN
431 
432       OPEN qty_per_dist_negtive_count_cur;
433       FETCH qty_per_dist_negtive_count_cur
434       INTO l_po_dist_count;
435       CLOSE qty_per_dist_negtive_count_cur;
436 
437     END;
438 
439     IF ( l_po_dist_count > 0 ) THEN
440       P_error_code := 'AP_INV_PO_CANT_CANCEL';
441       P_debug_info := l_debug_info;
442       RETURN FALSE;
443     END IF;
444 
445     /*-----------------------------------------------------------------+
446      |  Step 9. if the invoice is matched to an unapproved PO, if the
447      |          encumbrance is on, then do not allow the invoice
448      |		cancellation (bug6009101)
449      *-----------------------------------------------------------------*/
450 
451   l_debug_info := 'Check if the PO is unapproved';
452 
453    SELECT NVL(purch_encumbrance_flag,'N')
454    INTO   l_enc_enabled
455    FROM   financials_system_params_all
456    WHERE  NVL(org_id, -99) = NVL(l_org_id, -99);
457 
458     if l_enc_enabled = 'Y' then
459 
460        begin
461 
462           select 'Y'
463           into   l_po_not_approved
464           from   po_headers POH,
465                  po_distributions POD,
466                  ap_invoice_distributions AID,
467                  ap_invoices AI
468           where  AI.invoice_id = AID.invoice_id
469           and    AI.invoice_id = P_invoice_id
470           and    AID.po_distribution_id = POD.po_distribution_id
471           and    POD.po_header_id = POH.po_header_id
472           and    POH.approved_flag <> 'Y'
473           and    rownum = 1;
474 
475           EXCEPTION
476              WHEN OTHERS THEN
477                   NULL;
478 
479       end;
480 
481       if l_po_not_approved = 'Y' then
482          p_error_code := 'AP_PO_UNRES_CANT_CANCEL';
483          p_debug_info := l_debug_info;
484          return FALSE;
485        end if;
486     end if;
487 
488 
489     p_error_code := null;
490     P_debug_info := l_debug_info;
491     RETURN TRUE;
492 
493   EXCEPTION
494     WHEN OTHERS THEN
495       IF (SQLCODE <> -20001) THEN
496         FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
497         FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
498         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
499         FND_MESSAGE.SET_TOKEN('PARAMETERS',
500              ' P_invoice_id = '     || P_invoice_id );
501         FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
502       END IF;
503 
504       IF (qty_per_dist_negtive_count_cur%ISOPEN ) THEN
505         CLOSE qty_per_dist_negtive_count_cur;
506       END IF;
507 
508       IF ( dist_gl_date_cur%ISOPEN ) THEN
509         CLOSE dist_gl_date_cur;
510       END IF;
511 
512       P_debug_info := l_debug_info || 'With exceptions';
513       RETURN FALSE;
514 
515   END Is_Invoice_Cancellable;
516 
517 
518 /*=============================================================================
519  |  Function Ap_Cancel_Single_Invoice
520  |
521  |      cancels one invoice by executing the following sequence of steps,
522  |      returning TRUE if successful and FALSE otherwise.
523  |
524  |  PROGRAM FLOW
525  |
526  |      1. check if invoice cancellable, if yes, proceed otherwise return false
527  |      3.(If invoice has had tax withheld, undo withholding) - commented
528  |      4. Clear out payment schedules
529  |      5. Cancel all the non-discard lines
530  |          a. reverse matching
531  |          b. fetch the maximum distribution line number
532  |          c. Set encumbered flags to 'N'
533  |          d. Accounting event generation
534  |          e. reverse the distributions
535  |          f. update Line level Cancelled information
536  |      6. Zero out the Invoice
537  |      7. Run AutoApproval for this invoice
538  |      8. check posting holds remain on this canncelled invoice
539  |          a. if NOT exist - complete the cancellation by updating header
540  |             level information set return value to TRUE
541  |          b. if exist - no update, set the return valuse to FALSE, NO
542  |             DATA rollback.
543  |      9. Commit Data
544  |      10. Populate the out parameters.
545  |
546  |  NOTES
547  |      1. bug2328225 case of Matching a special charge only invoice to
548  |         receipt so we check if the quantity invoiced is not null too
549  |      2. Events Project
550  |         We no longer need to prevent the cancellation of an invoice
551  |         just because the accounting of related payments has not been
552  |         created. Therefore, bug fixes 902110 and 2237152 are removed.
553  |
554  |  MODIFICATION HISTORY
555  |  Date         Author             Description of Change
556  |
557  *============================================================================*/
558 
559   FUNCTION Ap_Cancel_Single_Invoice(
560                P_invoice_id                 IN  NUMBER,
561                P_last_updated_by            IN  NUMBER,
562                P_last_update_login          IN  NUMBER,
563                P_accounting_date            IN  DATE,
564                P_message_name               OUT NOCOPY VARCHAR2,
565                P_invoice_amount             OUT NOCOPY NUMBER,
566                P_base_amount                OUT NOCOPY NUMBER,
567                P_temp_cancelled_amount      OUT NOCOPY NUMBER,
568                P_cancelled_by               OUT NOCOPY NUMBER,
569                P_cancelled_amount           OUT NOCOPY NUMBER,
570                P_cancelled_date             OUT NOCOPY DATE,
571                P_last_update_date           OUT NOCOPY DATE,
572                P_original_prepayment_amount OUT NOCOPY NUMBER,
573                P_pay_curr_invoice_amount    OUT NOCOPY NUMBER,
574 	       P_Token			    OUT NOCOPY VARCHAR2,
575                P_calling_sequence           IN  VARCHAR2) RETURN BOOLEAN
576   IS
577 
578     CURSOR Invoice_Lines_cur IS
579     SELECT *
580      FROM ap_invoice_lines
581     WHERE invoice_id = P_invoice_id
582       AND (NVL(discarded_flag, 'N' ) <> 'Y'
583            AND NVL(cancelled_flag, 'N') <> 'Y') -- Bug 6669048
584   ORDER BY line_type_lookup_code;
585 
586    CURSOR Tax_Holds_Cur IS
587     SELECT AH.hold_lookup_code
588     FROM AP_HOLDS AH,
589 	 AP_HOLD_CODES AHC
590     WHERE AH.invoice_id = P_invoice_id
591         AND AH.hold_lookup_code = AHC.hold_lookup_code
592         AND AH.release_lookup_code IS NULL
593         AND AH.hold_lookup_code IN ('TAX AMOUNT RANGE','TAX VARIANCE');
594 
595    -- Cursor added for Payment Request Cancellation from Payables and
596    -- notifying the calling product.
597 
598     CURSOR c_reg_products  IS
599     SELECT Reg_Application_ID
600     FROM   AP_Invoices_All AI,
601            AP_Product_Registrations APR
602     WHERE  AI.Invoice_ID = P_Invoice_ID
603     AND    AI.Application_ID = APR.Reg_Application_ID
604     AND    APR.Registration_Event_Type = 'INVOICE_CANCELLED';
605 
606     cursor dist_debug_cur is
607     Select *
608     FROM   ap_invoice_distributions_all aid
609     WHERE  aid.invoice_id = p_invoice_id;
610 
611     l_inv_line_rec_list         Inv_Line_Tab_Type;
612     l_ok_to_cancel              BOOLEAN := FALSE;
613     l_discard_line_ok           BOOLEAN := FALSE;
614     l_count                     NUMBER;
615     l_holds_count               NUMBER := 0;
616     l_success                   BOOLEAN;
617     l_approval_status           VARCHAR2(25);
618     l_result_string             VARCHAR2(240);
619     l_error_code                VARCHAR2(4000);
620     l_approval_return_message   VARCHAR2(2000);
621     l_debug_info                VARCHAR2(240);
622     l_curr_calling_sequence     VARCHAR2(2000);
623     l_tax_already_calculated    BOOLEAN;
624     i                           BINARY_INTEGER := 1;
625     l_tax_holds_count 		NUMBER := 0;
626     l_hold_code_tab		AP_ETAX_SERVICES_PKG.REL_HOLD_CODES_TYPE;
627     l_token			VARCHAR2(4000);
628     l_invoice_amount            AP_INVOICES_ALL.INVOICE_AMOUNT%TYPE;
629     l_invoice_validation_status VARCHAR2(100);
630     l_payment_status_flag       AP_INVOICES_ALL.PAYMENT_STATUS_FLAG%TYPE;
631     l_invoice_type_lookup_code  AP_INVOICES_ALL.INVOICE_TYPE_LOOKUP_CODE%TYPE;
632     Tax_Exception		EXCEPTION;
633     --Bug 4539462 DBI logging
634     l_dbi_key_value_list        ap_dbi_pkg.r_dbi_key_value_arr;
635 
636     -- Bug 6669048
637     l_tax_lines_count           NUMBER := 0;
638     l_self_assess_tax_count     NUMBER := 0 ; -- Bug 6694536
639     l_tax_dist_count            NUMBER := 0;  -- Bug 6815172
640 
641     -- Bug 4748638
642     l_Accounting_event_ID      AP_INVOICE_DISTRIBUTIONS_ALL.accounting_event_id%TYPE;
643     l_cancel_dist_exists       NUMBER := 0;
644     l_open_gl_date             AP_INVOICES_ALL.gl_date%type;
645     l_funds_return_code        VARCHAR2(30); -- 4276409 (3462325)
646 
647     -- Payment request Cancellation Subscription
648     l_return_status        varchar2(1);
649     l_msg_count            number;
650     l_msg_data             varchar2(2000);
651     l_application_id       number;
652 
653     l_chk_encum       NUMBER := 0;             ---7264524
654     l_check_encumbrance  NUMBER := 0;          ---7428195
655     p_holds                       AP_APPROVAL_PKG.HOLDSARRAY;      --7264524
656     p_hold_count                  AP_APPROVAL_PKG.COUNTARRAY;      --7264524
657     p_release_count               AP_APPROVAL_PKG.COUNTARRAY;      --7264524
658     l_procedure_name CONSTANT VARCHAR2(50) := 'cancel_single_invoice';
659     prob_dist_list            varchar2(1000):=NULL; --9100425
660     prob_dist_count           number :=0;           --9100425
661     l_cancel_proactive_flag   varchar2(1);          --9100425
662 
663     -- Bug 9497953 : Start
664     l_max_inv_dist_acc_date	DATE ;
665     l_max_pmt_acc_date	        DATE ;
666     l_org_id			NUMBER ;
667     l_open_period		gl_period_statuses.period_name%TYPE ;
668     l_accounting_date           DATE ;
669     -- Bug 9497953 : End
670 
671     l_unsuccessful_cancel 	NUMBER := 0 ; 			-- Bug 9362054
672     l_inv_num			AP_INVOICES.invoice_num%TYPE ;	-- Bug 9362054
673   BEGIN
674     l_curr_calling_sequence := 'AP_CANCEL_PKG.AP_CANCEL_SINGLE_INVOICE<-' ||
675                                P_calling_sequence;
676 
677     /*-----------------------------------------------------------------+
678      |  Step 1. Check if invoice is cancellable                        |
679      +-----------------------------------------------------------------*/
680 
681     l_debug_info := 'Check if invoice is cancellable';
682 
683     l_ok_to_cancel := Is_Invoice_Cancellable(
684                           P_invoice_id       => p_invoice_id,
685                           P_error_code       => p_message_name,
686                           P_debug_info       => l_debug_info,
687                           P_calling_sequence => l_curr_calling_sequence);
688 
689     IF ( l_ok_to_cancel = FALSE ) THEN
690       RETURN FALSE;
691     END IF;
692 
693     -- Bug 9497953 : Start
694     SELECT TRUNC( NVL( MAX( AID.accounting_date ) , P_accounting_date ) )
695       INTO l_max_inv_dist_acc_date
696       FROM ap_invoice_distributions AID
697      WHERE AID.invoice_id             = P_invoice_id
698        AND AID.awt_invoice_payment_id IS NULL ;
699 
700     SELECT TRUNC( NVL( MAX( AIP.accounting_date ) , P_accounting_date ) )
701       INTO l_max_pmt_acc_date
702       FROM ap_invoice_payments AIP
703      WHERE AIP.invoice_id = P_invoice_id ;
704 
705     SELECT org_id
706       INTO l_org_id
707       FROM ap_invoices
708      WHERE invoice_id = P_invoice_id ;
709 
710     IF l_max_pmt_acc_date >  l_max_inv_dist_acc_date THEN
711        l_accounting_date := l_max_pmt_acc_date ;
712     ELSE
713        l_accounting_date := l_max_inv_dist_acc_date ;
714     END IF ;
715 
716     IF TRUNC( P_accounting_date ) > l_accounting_date THEN
717        l_accounting_date := TRUNC( P_accounting_date );
718     END IF ;
719 
720     IF l_accounting_date IS NOT NULL THEN
721        l_open_period := AP_UTILITIES_PKG.Get_Current_GL_Date_No_Cache( P_Date   => l_accounting_date,
722                                                                        P_Org_Id => l_org_id );
723 
724        IF (l_open_period is null) THEN
725           AP_UTILITIES_PKG.get_open_gl_date_no_cache( l_accounting_date, l_open_period, l_open_gl_date );
726           if (l_open_gl_date is null) then
727              p_message_name := 'AP_CANCEL_NO_OPEN_FUT_PERIOD' ;
728              RETURN FALSE ;
729           else
730              l_accounting_date := l_open_gl_date;
731           end if;
732        END IF;
733     END IF ;
734     -- Bug 9497953 : End
735 
736      SAVEPOINT CANCEL_CHECK_1; --9100425
737     /*-----------------------------------------------------------------+
738      |  Step 2. If invoice has had tax withheld, undo withholding      |
739      |                                                                 |
740      +-----------------------------------------------------------------*/
741 
742     l_debug_info := 'Check if AWT has been performed by AutoApproval';
743 
744     SELECT count(*)
745     INTO   l_count
746     FROM   ap_invoice_distributions
747     WHERE  invoice_id = P_invoice_id
748     AND    NVL(awt_flag,'N') = 'A'  --bug 9702328
749     AND    NVL(reversal_flag,'N') <> 'Y';
750 
751     IF (l_count > 0) THEN
752 
753       AP_WITHHOLDING_PKG.AP_UNDO_WITHHOLDING(
754               P_invoice_id,
755               'CANCEL INVOICE',
756               l_accounting_date, -- Bug 9497953 P_accounting_date,
757               NULL,
758               P_Last_Updated_By,
759               P_Last_Update_Login,
760               NULL,
761               NULL,
762               NULL,
763               l_result_string);
764     END IF;
765 
766     IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
767          FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
768     END IF;
769 
770     /*-----------------------------------------------------------------+
771      |  Step 3.  Clear out payment schedules                           |
772      |            1. Set hold_flag to 'N' to make cancelled invoice    |
773      |               does not show up on 'Invoice on Hold report'.     |
774      +-----------------------------------------------------------------*/
775 
776     l_debug_info := 'Clear out payment schedules';
777 
778     UPDATE    ap_payment_schedules
779     SET       gross_amount         = 0
780               ,amount_remaining    = 0
781               ,payment_status_flag = 'N'
782               ,hold_flag           = 'N'
783               ,last_updated_by     = P_last_updated_by
784               ,last_update_date    = sysdate
785 	          ,inv_curr_gross_amount =0 --Bug5446999
786     WHERE     invoice_id = P_invoice_id;
787 
788     --Bug 4539462 DBI logging
789     AP_DBI_PKG.Maintain_DBI_Summary
790               (p_table_name => 'AP_PAYMENT_SCHEDULES',
791                p_operation => 'U',
792                p_key_value1 => P_invoice_id,
793                 p_calling_sequence => l_curr_calling_sequence);
794 
795    /*-----------------------------------------------------------------+
796      |  Step 4a. Delete all unprocessed bc events and update the        |
797 	 |          encumbered flag to 'R' 								   |
798      +-----------------------------------------------------------------*/
799 
800     --Start of bug 8733916
801 
802      AP_FUNDS_CONTROL_PKG.Encum_Unprocessed_Events_Del
803                          (p_invoice_id       => p_invoice_id,
804                           p_calling_sequence => l_curr_calling_sequence);
805 
806      UPDATE ap_invoice_distributions aid
807         SET aid.encumbered_flag = 'R'
808       WHERE aid.invoice_id = p_invoice_id
809         AND nvl(aid.match_status_flag,'N') <> 'A'
810         AND nvl(aid.encumbered_flag,'N') <> 'Y'
811         AND aid.parent_reversal_id is null
812         AND aid.line_type_lookup_code NOT IN ('REC_TAX','NONREC_TAX','TRV','TERV','TIPV')
813         AND nvl(aid.reversal_flag,'N')<>'Y'
814 	AND EXISTS (SELECT 1
815                       FROM financials_system_params_all fsp
816                      WHERE fsp.org_id = aid.org_id
817                        AND nvl(fsp.purch_encumbrance_flag, 'N') = 'Y');
818 
819       --End of bug 8733916
820 
821     /*-----------------------------------------------------------------+
822      |  Step 4b. Discard Line in Cancel Mode for each line of invoice   |
823      +-----------------------------------------------------------------*/
824 
825      IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
826           l_debug_info := 'step4 - Now call Discard Lines for the invoice';
827          FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
828      END IF;
829 
830 
831     BEGIN
832       OPEN Invoice_Lines_Cur;
833       FETCH Invoice_Lines_Cur
834       BULK COLLECT INTO l_inv_line_rec_list;
835       CLOSE Invoice_Lines_Cur;
836     END;
837 
838     SELECT invoice_type_lookup_code,
839            payment_status_flag,
840 	   invoice_amount
841     INTO   l_invoice_type_lookup_code,
842            l_payment_status_flag,
843            l_invoice_amount
844     FROM ap_invoices
845     WHERE invoice_id =p_invoice_id;
846 
847     l_invoice_validation_status := ap_invoices_pkg.get_approval_status(
848                                             l_invoice_id => p_invoice_id,
849                                             l_invoice_amount => l_invoice_amount,
850                                             l_payment_status_flag => l_payment_status_flag,
851                                             l_invoice_type_lookup_code => l_invoice_type_lookup_code );
852 
853     l_debug_info := 'Dicard Lines for the invoice: Calling etax for Validated Invoice';
854 
855     IF (NVL(l_invoice_validation_status,'NEVER APPROVED') IN
856 			              ('APPROVED','AVAILABLE','UNPAID','FULL')) THEN
857 
858         l_success := ap_etax_pkg.calling_etax(
859                                P_Invoice_id => p_invoice_id,
860                                P_Calling_Mode => 'UNFREEZE INVOICE',
861                                P_All_Error_Messages => 'N',
862                                P_error_code => l_error_code,
863                                P_Calling_Sequence => l_curr_calling_sequence);
864 
865         IF (not l_success) THEN
866             p_message_name := 'AP_ETX_CANCEL_UNFRZ_INV_FAILED';
867             p_token := l_error_code;
868             RETURN(FALSE);
869         END IF;
870 
871     END IF;
872 
873 
874     l_debug_info := 'Dicard Lines for the invoice: Discarding Individual line';
875     --Bug 5585992
876     IF l_inv_line_rec_list.count > 0 THEN
877 
878       FOR i in l_inv_line_rec_list.FIRST..l_inv_line_rec_list.LAST
879       LOOP
880         -- Bug 5585992
881         IF l_inv_line_rec_list.exists(i) THEN
882 
883            /* Added nvl condition to p_accounting_date for bug #6627060 */
884           -- Bug 5584997
885           l_inv_line_rec_list(i).accounting_date :=
886 	                  nvl(l_accounting_date,l_inv_line_rec_list(i).accounting_date);    -- Bug 9497953
887 
888           l_discard_line_ok := AP_INVOICE_LINES_PKG.Discard_Inv_Line(
889                                P_line_rec          => l_inv_line_rec_list(i),
890                                P_calling_mode      => 'CANCEL',
891                                P_inv_cancellable   => 'Y',
892                                P_last_updated_by   => p_last_updated_by,
893                                P_last_update_login => p_last_update_login,
894                                P_error_code        => l_error_code,
895 			       P_Token		   => l_token,
896                                P_calling_sequence  => l_curr_calling_sequence);
897 
898           IF ( l_discard_line_ok = FALSE ) THEN
899             P_Message_Name := l_error_code;
900             P_Token := l_token;
901             RETURN FALSE;
902           END IF;
903 
904         END IF;
905 
906       END LOOP;
907 
908     l_inv_line_rec_list.DELETE;
909 
910     ELSE
911 
912       l_discard_line_ok := TRUE;
913 
914     END IF;
915 
916     --ETAX:
917     l_tax_already_calculated := AP_ETAX_UTILITY_PKG.Is_Tax_Already_Calc_Inv(
918 				P_Invoice_Id => p_invoice_id,
919 			 	P_Calling_Sequence => l_curr_calling_sequence);
920 
921     IF (l_tax_already_calculated) THEN
922 
923       --Commented below 3 SELECT and checking all types of tax lines count
924       --together in single SELECT, which needs to cancel. Bug#9244765
925 
926       /*
927        -- Bug 6669048. Get the count of tax lines that have not been cancelled.
928        SELECT count(*)
929        INTO   l_tax_lines_count
930        FROM   ap_invoice_lines
931        WHERE  invoice_id = p_invoice_id
932        AND    line_type_lookup_code = 'TAX'
933        AND    NVL(cancelled_flag,'N') <> 'Y'
934        AND rownum =1;
935 
936       -- Bug 6694536. Need to call the etax api to reverse the self assessed tax lines.
937 
938         SELECT count(*)
939        INTO l_self_assess_tax_count
940        FROM ap_self_assessed_tax_dist_all asat,
941             zx_rec_nrec_dist zx_dist
942        WHERE invoice_id = p_invoice_id
943         AND asat.detail_tax_dist_id = zx_dist.rec_nrec_tax_dist_id
944         AND zx_dist.self_assessed_flag = 'Y'
945         AND nvl(zx_dist.reverse_flag, 'N') <> 'Y'
946         AND line_type_lookup_code IN ('REC_TAX', 'NONREC_TAX')
947         AND rownum =1;
948 
949         -- Bug 	6815172. Get the count of tax distribution lines that
950         --  have not been cancelled in case of inclusive tax.
951 
952         SELECT count(*)
953         INTO l_tax_dist_count
954         FROM zx_rec_nrec_dist zx_dist,
955              ap_invoice_distributions ap_dist
956         WHERE ap_dist.invoice_id = p_invoice_id
957         AND ap_dist.detail_tax_dist_id = zx_dist.rec_nrec_tax_dist_id
958         AND nvl(zx_dist.reverse_flag, 'N') <> 'Y'
959         AND nvl(zx_dist.inclusive_flag, 'N') = 'Y'
960         AND ap_dist.line_type_lookup_code IN ('REC_TAX', 'NONREC_TAX')
961         AND rownum =1;  */
962 
963 
964         SELECT count(*)
965         INTO l_tax_lines_count
966         FROM zx_lines_summary zls
967         WHERE zls.trx_id = p_invoice_id
968           and zls.application_id = 200
969           and zls.entity_code = 'AP_INVOICES'
970 	  and zls.event_class_code In ('STANDARD INVOICES',
971                                        'PREPAYMENT INVOICES',
972                                        'EXPENSE REPORTS')
973           and NVL(zls.reporting_only_flag, 'N') = 'N'
974           and nvl(zls.cancel_flag, 'N') <> 'Y'
975           and  rownum =1;
976 
977       --End of 9244765
978 
979 
980       -- Bug 7553603
981       -- cancelled_flag needs to be set prior to calling the tax api as
982       -- the line_level_action needs to be sent as DISCARD. This was
983       -- a regression from bug 6669048.
984 
985       UPDATE ap_invoice_lines
986       SET    cancelled_flag = 'Y'
987       WHERE  invoice_id = P_invoice_id
988       AND    NVL(discarded_flag, 'N' ) <> 'Y';
989 
990 
991          --Bug# 9244765. Commented all counts check and now checking with
992 	 --only correct count
993 
994        /*
995        -- Bug 6669048. We should not be calling the etax API if all the tax
996        -- lines have already been cancelled.
997            IF l_tax_lines_count > 0  OR l_self_assess_tax_count > 0
998              OR l_tax_dist_count > 0   -- Bug 6815172    THEN */
999 
1000 	  IF l_tax_lines_count > 0  THEN
1001 
1002 	  --End of 9244765
1003 
1004 
1005           l_success := ap_etax_pkg.calling_etax(p_invoice_id => p_invoice_id,
1006 			     p_calling_mode => 'CANCEL INVOICE',
1007 			     p_all_error_Messages => 'N',
1008 			     p_error_code => l_error_code,
1009 			     p_calling_sequence => l_curr_calling_sequence);
1010 
1011           IF NOT(l_success) THEN
1012      	     Raise Tax_Exception;
1013           END IF;
1014 
1015        END IF;
1016 
1017     END IF;
1018 
1019 
1020     /*-----------------------------------------------------------------+
1021      |  Step 4.5 Proactive Cancellation Check ->fires Based on profile |
1022      +-----------------------------------------------------------------*/
1023     -- 9100425
1024  BEGIN
1025    fnd_profile.get('AP_ENHANCED_DEBUGGING', l_cancel_proactive_flag);
1026 
1027    IF nvl(l_cancel_proactive_flag,'N') ='C' then
1028 
1029     For I in(select invoice_distribution_id
1030      from ap_invoice_distributions aid1
1031      where aid1.invoice_id=P_invoice_id
1032      and aid1.parent_reversal_id is  null --original dist
1033      --for original dists there is no reversal dist created
1034      and ( not exists (select 1 from ap_invoice_distributions aid2
1035      where aid1.invoice_id=aid2.invoice_id
1036      and aid2.invoice_id=P_invoice_id
1037      and aid2.invoice_line_number=aid1.invoice_line_number
1038      and aid2.parent_reversal_id =aid1.invoice_distribution_id)
1039      --the reversal dist does not reverse the amount correctly
1040      or  exists (select 1 from ap_invoice_distributions aid2
1041      where aid1.invoice_id=aid2.invoice_id
1042      and aid2.invoice_id=P_invoice_id
1043      and aid2.invoice_line_number=aid1.invoice_line_number
1044      and aid2.parent_reversal_id =aid1.invoice_distribution_id
1045      and -1 * aid2.amount <> aid1.amount)))
1046 
1047      LOOP
1048        prob_dist_list := prob_dist_list||','||i.invoice_distribution_id;
1049        prob_dist_count:=prob_dist_count+1;
1050 
1051      end loop;
1052 
1053            IF prob_dist_count > 0 then
1054            P_message_name := 'AP_INV_DIS_CAN_FAIL';
1055            P_Token := prob_dist_list;
1056            ROLLBACK TO SAVEPOINT CANCEL_CHECK_1;
1057 
1058             RETURN (FALSE);
1059            end if;
1060 
1061    END IF;
1062 
1063  EXCEPTION WHEN OTHERS THEN
1064  NULL;
1065 END;
1066 --9100425
1067 
1068 
1069     /*-----------------------------------------------------------------+
1070      |  Step 5. Zero out the invoice for main invoice table            |
1071      +-----------------------------------------------------------------*/
1072 
1073     IF ( l_discard_line_ok )  and prob_dist_count =0 THEN --9100425
1074       l_debug_info := 'Zero out the invoice';
1075 
1076       UPDATE ap_invoices
1077       SET    invoice_amount = 0
1078              ,base_amount = 0
1079              ,temp_cancelled_amount = DECODE(temp_cancelled_amount, NULL,
1080                                             invoice_amount,
1081                                             DECODE(invoice_amount, 0,
1082                                                    temp_cancelled_amount,
1083                                                    invoice_amount))
1084              ,pay_curr_invoice_amount = 0
1085              ,last_updated_by = P_last_updated_by
1086              ,last_update_date = sysdate
1087       WHERE  invoice_id = P_invoice_id;
1088 
1089       -- Bug 6669048. Update the cancelled_flag for all the lines to 'Y' since
1090       -- at this point all the invoice lines have been discarded including the
1091       -- tax lines and AWT lines
1092       UPDATE ap_invoice_lines
1093       SET    cancelled_flag = 'Y'
1094       WHERE  invoice_id = P_invoice_id
1095       AND    NVL(discarded_flag, 'N' ) <> 'Y';
1096 
1097       --Bug 4539462 DBI logginG
1098       AP_DBI_PKG.Maintain_DBI_Summary
1099               (p_table_name => 'AP_INVOICES',
1100                p_operation => 'U',
1101                p_key_value1 => P_Invoice_Id,
1102                 p_calling_sequence => l_curr_calling_sequence);
1103 
1104      IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
1105          l_debug_info := 'Before call approval pkg again ';
1106          FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
1107 
1108          FOR l_inv_dist_rec IN dist_debug_cur
1109          loop
1110            l_debug_info :='invoice distribution looks like'||
1111                          'l_dist_type = ' || l_inv_dist_rec.line_type_lookup_code||
1112                          'l_amount=' || l_inv_dist_rec.amount ||
1113                          'l_base_amount =' || l_inv_dist_rec.base_amount ||
1114                          'l_match_status_flag=' ||l_inv_dist_rec.match_status_flag ;
1115            FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
1116          end loop;
1117 
1118      END IF;
1119 
1120     /*-----------------------------------------------------------------+
1121      |  Step 7. Run Approval again for this cancelled invoice          |
1122      |           Ignore message returned from APPROVE process          |
1123      +-----------------------------------------------------------------*/
1124 
1125       IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
1126          l_debug_info := 'Run Approval for this invoice again';
1127          FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
1128       END IF;
1129 
1130       --SMYADAM: Approve procedure calls 4 etax apis (calculate, distribute, validate, freeze).
1131       --Do we need to call these apis when the invoice is being cancelled also (looks unnecessary)
1132       --, if we decide not to call these apis for cancellation case,
1133       --what if the invoice cancellation doesn't go thru due to postable holds which
1134       --we will know only after the validation has been done, and then since we did not
1135       --call the etax apis during the approve call and the invoice is not cancelled , won't
1136       --the tax data on this invoice be stale. ??
1137 
1138       AP_APPROVAL_PKG.APPROVE(
1139            P_RUN_OPTION         => '',
1140            P_INVOICE_BATCH_ID   => '',
1141            P_BEGIN_INVOICE_DATE => '',
1142            P_END_INVOICE_DATE   => '',
1143            P_VENDOR_ID          => '',
1144            P_PAY_GROUP          => '',
1145            P_INVOICE_ID         => P_invoice_id,
1146            P_ENTERED_BY         => '',
1147            P_SET_OF_BOOKS_ID    => '',
1148            P_TRACE_OPTION       => '',
1149            P_CONC_FLAG          => 'N',
1150            P_HOLDS_COUNT        => l_holds_count,
1151            P_APPROVAL_STATUS    => l_approval_status,
1152            P_FUNDS_RETURN_CODE  => l_funds_return_code, -- 4276409 (3462325)
1153 	   P_CALLING_MODE	=> 'CANCEL',
1154            P_CALLING_SEQUENCE   => l_curr_calling_sequence,
1155            P_COMMIT             => 'N');
1156 
1157       l_approval_return_message := FND_MESSAGE.GET;
1158 
1159       -- Bug Fixes for 7264524, 7428195 and 9465105 have been relocated
1160       -- to apaprvlb.pls for the bug9553683
1161       --
1162 
1163 
1164     /*-----------------------------------------------------------------+
1165      |  Step 8. Check if there are posting hold exist                  |
1166      +-----------------------------------------------------------------*/
1167 
1168       l_debug_info := 'Get the number of posting holds for invoice';
1169 
1170       BEGIN
1171         SELECT count(*)
1172           INTO l_holds_count
1173           FROM ap_holds       AH
1174                ,ap_hold_codes AHC
1175          WHERE AH.invoice_id = P_invoice_id
1176            AND AH.hold_lookup_code = AHC.hold_lookup_code
1177            AND AH.release_lookup_code IS NULL
1178            AND AHC.postable_flag = 'N';
1179       EXCEPTION
1180         WHEN OTHERS THEN
1181           l_holds_count := 0;
1182       END;
1183 
1184 
1185       IF (l_holds_count = 0)  THEN
1186 
1187     /*-----------------------------------------------------------------+
1188      |  Step 9A. Complete Cancel process if no postable hold           |
1189      |		  1. Check if any tax holds,if so call etax to 	       |
1190      |		     release tax holds.				       |
1191      |            2. Update the invoice header information             |
1192      |            3. Release all the holds                             |
1193      |            4. set return value to TRUE - indicate success       |
1194      +-----------------------------------------------------------------*/
1195         l_debug_info := 'Check if invoice has any tax holds';
1196 
1197         SELECT count(*)
1198         INTO l_tax_holds_count
1199         FROM ap_holds       AH
1200             ,ap_hold_codes AHC
1201         WHERE AH.invoice_id = P_invoice_id
1202         AND AH.hold_lookup_code = AHC.hold_lookup_code
1203         AND AH.release_lookup_code IS NULL
1204         AND AH.hold_lookup_code IN ('TAX AMOUNT RANGE','TAX VARIANCE');
1205 
1206         IF (l_tax_holds_count <> 0) THEN
1207 
1208 	  OPEN Tax_Holds_Cur;
1209 	  FETCH Tax_Holds_Cur bulk collect into l_hold_code_tab;
1210 	  CLOSE Tax_Holds_Cur;
1211 
1212           l_debug_info := 'Call Etax to release tax holds';
1213 
1214 	  l_success:= ap_etax_services_pkg.release_tax_holds(
1215                              p_invoice_id => p_invoice_id,
1216                              p_calling_mode => 'RELEASE TAX HOLDS',
1217                              p_tax_hold_code => l_hold_code_tab,
1218                              p_all_error_messages => 'N',
1219                              p_error_code => l_error_code,
1220                              p_calling_sequence => l_curr_calling_sequence);
1221 
1222           IF NOT(l_success) THEN
1223 	     Raise Tax_Exception;
1224 	  END IF;
1225 
1226         END IF;
1227 
1228     /*-----------------------------------------------------------------+
1229      |  Step 9A. Complete Cancel process if no postable hold           |
1230      |		       Create single invoice cancelled accounting event	     |
1231      |		       This is a code fix combined with the following bugs   |
1232      |		       3574680, 2993905 while fixing 4748638                 |
1233      +-----------------------------------------------------------------*/
1234 
1235       -- Start Bug fix 4748638 (4881719)
1236       --Bug#3574680, determine if cancelled distributions exists
1237       SELECT COUNT(invoice_distribution_id)
1238       INTO l_cancel_dist_exists
1239       FROM ap_invoice_distributions
1240       WHERE invoice_id=p_invoice_id
1241       AND cancellation_flag='Y'
1242       AND rownum=1;
1243 
1244       IF NVL(l_cancel_dist_exists,0) <> 0  THEN
1245 
1246         AP_ACCOUNTING_EVENTS_PKG.Create_Events (
1247               'INVOICE CANCELLATION'
1248               ,NULL   -- p_doc_type
1249               ,p_invoice_id
1250               ,l_accounting_date           -- Bug 9497953 p_accounting_date
1251               ,l_Accounting_event_ID
1252               ,NULL    -- checkrun_name
1253               ,P_calling_sequence);
1254       END IF;
1255 
1256       -- BUG fix 4748638 END
1257 
1258 
1259         l_debug_info := 'Cancelling the invoice if no postable holds';
1260 
1261         UPDATE ap_invoices
1262         SET    cancelled_by      = P_last_updated_by
1263                ,cancelled_amount = temp_cancelled_amount
1264                ,cancelled_date   = sysdate
1265                ,last_updated_by  = P_last_updated_by
1266                ,last_update_date = sysdate
1267         WHERE  invoice_id = P_invoice_id;
1268 
1269 	-- Bug 9362054 : Begin
1270 	SELECT COUNT(1)
1271 	  INTO l_unsuccessful_cancel
1272 	  FROM ap_invoice_distributions     AID,
1273 	       financials_system_params_all FSP
1274 	 WHERE AID.invoice_id      = P_invoice_id
1275 	   AND FSP.org_id          = AID.org_id
1276            AND FSP.set_of_books_id = AID.set_of_books_id
1277            AND ( ( NVL( FSP.purch_encumbrance_flag, 'N' ) = 'Y'
1278 	           AND NVL( AID.match_status_flag, 'N' ) <> 'A'
1279 	         )
1280 		 OR ( NVL( FSP.purch_encumbrance_flag, 'N' ) = 'N'
1281 		      AND NVL( AID.match_status_flag, 'N' ) NOT IN ( 'A', 'T' )
1282 		    )
1283 	       )
1284 	   AND ROWNUM = 1 ;
1285 
1286 	IF l_unsuccessful_cancel <> 0 THEN
1287 	   SELECT invoice_num
1288 	     INTO P_Token
1289 	     FROM ap_invoices
1290             WHERE invoice_id = p_invoice_id ;
1291 
1292 	   ROLLBACK TO SAVEPOINT CANCEL_CHECK_1 ;
1293 	   P_message_name := 'AP_UNSUCCESSFUL_CANCELLATION' ;
1294 	   RETURN FALSE ;
1295 	END IF ;
1296 	-- Bug 9362054 : End
1297 
1298         -- bug9322013
1299         AP_ACCOUNTING_EVENTS_PKG.Set_Prepay_Event_Noaction
1300               (p_invoice_id,
1301                l_curr_calling_sequence);
1302 
1303         -- Bug 9691312 : Begin
1304         FOR c_wf_status IN ( SELECT hold_id
1305                              FROM   ap_holds
1306                              WHERE  invoice_id = p_invoice_id
1307                              AND    release_lookup_code IS NULL
1308                              AND    wf_status IN ( 'STARTED', 'NEGOTIATE' )
1309                            )
1310         LOOP
1311            AP_WORKFLOW_PKG.abort_holds_workflow( c_wf_status.hold_id ) ;
1312         END LOOP ;
1313 	-- Bug 9691312 : End
1314 
1315         UPDATE ap_holds
1316         SET    release_lookup_code  = 'APPROVED'
1317                ,release_reason      = ( SELECT description
1318                                           FROM ap_hold_codes
1319                                          WHERE hold_lookup_code = 'APPROVED')
1320                ,last_update_date    = SYSDATE
1321                ,last_updated_by     = P_last_updated_by
1322                ,last_update_login   = P_last_update_login
1323         WHERE  invoice_id           = P_invoice_id
1324         AND  release_lookup_code IS NULL ;
1325 
1326         l_success := TRUE;
1327 
1328 	--Bug 4539462 DBI logging
1329 	AP_DBI_PKG.Maintain_DBI_Summary
1330               (p_table_name => 'AP_INVOICES',
1331                p_operation => 'U',
1332                p_key_value1 => P_Invoice_id,
1333                 p_calling_sequence => l_curr_calling_sequence);
1334 
1335        AP_DBI_PKG.Maintain_DBI_Summary
1336               (p_table_name => 'AP_HOLDS',
1337                p_operation => 'U',
1338                p_key_value1 => P_Invoice_id,
1339                 p_calling_sequence => l_curr_calling_sequence);
1340 
1341         COMMIT;
1342 
1343       ELSE
1344 
1345     /*-----------------------------------------------------------------+
1346      |  Step 9B. Special treatment for an invoice with POSTABLE HOLD   |
1347      |            During Cancellation.                                 |
1348      |            1. populate returned error message                   |
1349      |            2. set return value to FALSE                         |
1350      |            Invoice Header Level data will not be marked as      |
1351      |            CANCELLED to allow user to release any hold when they|
1352      |            review. We also need to commit data because the      |
1353      |            postable holds if any will be depending on the       |
1354      |            reversed data                                        |
1355      +-----------------------------------------------------------------*/
1356 
1357         l_debug_info := 'Special treatment for an invoice with POSTABLE HOLDS';
1358 
1359         P_message_name := 'AP_INV_CANCEL_POSTING_HOLDS';
1360         l_success := FALSE;
1361 
1362       END IF;  -- end of check l_hold_count of postable hold
1363 
1364     /*-----------------------------------------------------------------+
1365      |  Step 10. Commit Data for success cancelled invoice and invoice |
1366      |           with postable hold                                    |
1367      +-----------------------------------------------------------------*/
1368 
1369       l_debug_info := 'Committing changes to database';
1370 
1371      /*----------------------------------------------------------------+
1372      |  Step 10.5. Calling API for Payment Request Cancellation        |
1373      |             Subscribe Event                                     |
1374      +-----------------------------------------------------------------*/
1375 
1376       l_debug_info := 'Calling Payment Request Cancellation Subscription API';
1377      -- Payment request Cancellation from Payables
1378        IF p_calling_sequence not in ('ar_refund_pvt.cancel_refund','IGS_FI_PRC_APINT.CANCEL_INVOICE')  THEN
1379            /* added 'IGS_FI_PRC_APINT.CANCEL_INVOICE' for bug 5948586 as we need not call
1380               the Subscribe_To_Cancel_Event if ap_cancel_single invoice is called from SF module.
1381               plz see the bug for details. */
1382 
1383           OPEN c_reg_products;
1384           LOOP
1385           FETCH c_reg_products INTO l_application_id;
1386           EXIT WHEN c_reg_products%NOTFOUND;
1387 
1388           AP_CANCEL_PKG.Subscribe_To_Cancel_Event(
1389                P_Event_Type       => 'INVOICE_CANCELLED',
1390                P_Invoice_ID       => P_invoice_id,
1391                P_Application_ID   => l_application_id,
1392                P_Return_Status    => l_return_status,
1393                P_Msg_Count        => l_msg_count,
1394                P_Msg_Data         => l_msg_data,
1395                P_Calling_Sequence => l_curr_calling_sequence);
1396 
1397           IF l_Return_Status <> FND_API.G_RET_STS_SUCCESS THEN
1398              FND_MSG_PUB.Count_And_Get
1399                            (p_encoded => FND_API.G_FALSE,
1400                             p_count   => l_msg_count,
1401                             p_data    => l_msg_data);
1402              l_debug_info := l_msg_data;
1403              RETURN FALSE;
1404           END IF;
1405 
1406           END LOOP;
1407         END IF;
1408 
1409     /*-----------------------------------------------------------------+
1410      |  Step 11. Populate the Out parameter                            |
1411      +-----------------------------------------------------------------*/
1412 
1413       l_debug_info := 'Populate OUT parameters';
1414 
1415       SELECT invoice_amount
1416              ,base_amount
1417              ,temp_cancelled_amount
1418              ,cancelled_by
1419              ,cancelled_amount
1420              ,cancelled_date
1421              ,last_update_date
1422              ,original_prepayment_amount
1423              ,pay_curr_invoice_amount
1424         INTO P_invoice_amount
1425              ,P_base_amount
1426              ,P_temp_cancelled_amount
1427              ,P_cancelled_by
1428              ,P_cancelled_amount
1429              ,P_cancelled_date
1430              ,P_last_update_date
1431              ,P_original_prepayment_amount
1432              ,P_pay_curr_invoice_amount
1433         FROM ap_invoices
1434        WHERE invoice_id = P_invoice_id;
1435 
1436       RETURN l_success;
1437 
1438     ELSE
1439       l_debug_info := 'Discard line(s) is not successful';
1440       RETURN FALSE;
1441     END IF; -- end of check l_discard_line_ok flag
1442 
1443   EXCEPTION
1444     WHEN TAX_EXCEPTION THEN
1445       IF ( Invoice_Lines_Cur%ISOPEN ) THEN
1446         CLOSE Invoice_Lines_Cur;
1447       END IF;
1448       IF (Tax_Holds_Cur%ISOPEN) THEN
1449 	CLOSE Tax_Holds_Cur;
1450       END IF;
1451       APP_EXCEPTION.RAISE_EXCEPTION;
1452       RETURN FALSE;
1453     WHEN OTHERS THEN
1454       IF (SQLCODE <> -20001) THEN
1455         FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1456         FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1457         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
1458         FND_MESSAGE.SET_TOKEN('PARAMETERS',
1459             ' P_invoice_id = '   || P_invoice_id
1460           ||' P_last_updated_by = '   || P_last_updated_by
1461           ||' P_last_update_login = ' || P_last_update_login
1462           ||' P_accounting_date = '   || P_accounting_date);
1463         FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
1464       END IF;
1465 
1466       IF ( Invoice_Lines_Cur%ISOPEN ) THEN
1467         CLOSE Invoice_Lines_Cur;
1468       END IF;
1469       IF (Tax_Holds_Cur%ISOPEN) THEN
1470 	CLOSE Tax_Holds_Cur;
1471       END IF;
1472       APP_EXCEPTION.RAISE_EXCEPTION;
1473       RETURN FALSE;
1474 
1475   END Ap_Cancel_Single_Invoice;
1476 
1477 /*=============================================================================
1478  |  PROCEDURE Ap_Cancel_Invoices
1479  |
1480  |      Cancels all invoices associated with the payment given by P_check_id
1481  |
1482  |  PROGRAM FLOW
1483  |
1484  |      Invoices that are not eligible for cancellation:
1485  |      1. invoices associated with an effective payment,
1486  |      2. invoices that are selected for payment,
1487  |      3. invoices that are already cancelled
1488  |      4. invoices (prepayments) that have been used by other invoices
1489  |      5. invoices that are matched to Finally Closed PO's)
1490  |      6. invoices which were paid originally by check but whose payment
1491  |         was removed prior to the voiding of the check i.e. through an
1492  |         invoice adjustment are left unaffected.
1493  |
1494  |  NOTES
1495  |      1. AutoApproval is run for each invoice.  If the invoice has posting
1496  |         holds, it is zeroed out by reversing all invoice distributions and
1497  |         PO matching, but the invoice is not cancelled.
1498  |
1499  |  MODIFICATION HISTORY
1500  |  Date         Author             Description of Change
1501  |
1502  *============================================================================*/
1503 
1504   PROCEDURE Ap_Cancel_Invoices(
1505                 P_check_id          IN  NUMBER,
1506                 P_last_updated_by   IN  NUMBER,
1507                 P_last_update_login IN  NUMBER,
1508                 P_accounting_date   IN  DATE,
1509                 P_num_cancelled     OUT NOCOPY NUMBER,
1510                 P_num_not_cancelled OUT NOCOPY NUMBER,
1511                 P_calling_sequence  IN  VARCHAR2)
1512   IS
1513     l_num_cancelled              NUMBER := 0;
1514     l_num_not_cancelled          NUMBER := 0;
1515     l_success                    BOOLEAN;
1516     l_message_name               VARCHAR2(30);
1517     l_invoice_amount             NUMBER;
1518     -- bug 6883407
1519     l_invoice_gl_date            DATE;
1520 
1521     l_base_amount                NUMBER;
1522     l_temp_cancelled_amount      NUMBER;
1523     l_cancelled_by               NUMBER;
1524     l_cancelled_amount           NUMBER;
1525     l_pay_curr_invoice_amount    NUMBER;
1526     l_cancelled_date             DATE;
1527     l_last_update_date           DATE;
1528     l_debug_info                 VARCHAR2(240);
1529     l_original_prepayment_amount NUMBER;
1530     l_curr_calling_sequence      VARCHAR2(2000);
1531     l_token			 VARCHAR2(4000);
1532 
1533     /*-----------------------------------------------------------------+
1534      |  Declare cursor to select all invoices associated with the      |
1535      |  payment given by P_check_id and ensuring that the invoice was  |
1536      |  effectively being paid by the check i.e. the invoice payment   |
1537      |  wasn't already reversed.                                       |
1538      +-----------------------------------------------------------------*/
1539 
1540     --bug 5182311 Modified the cursor to ignore already cancelled invoices
1541     -- Bug 8257752. Commented out the reversal_flag condition.
1542 
1543     CURSOR invoices_cursor IS
1544     SELECT DISTINCT aip.invoice_id
1545     FROM   ap_invoice_payments aip,ap_invoices ai
1546     WHERE  aip.check_id = P_check_id
1547     --AND    nvl(aip.reversal_flag, 'N') <> 'Y'
1548     AND    ai.invoice_id=aip.invoice_id
1549     AND    ai.cancelled_date is null;
1550 
1551     TYPE inv_ib_tab_Type IS TABLE OF ap_invoices.invoice_id%TYPE;
1552 
1553     l_invoice_id_list          inv_ib_tab_Type;
1554     i                          BINARY_INTEGER :=1;
1555 
1556   BEGIN
1557     l_curr_calling_sequence := 'AP_CANCEL_PKG.AP_CANCEL_INVOICES<-' ||
1558                                P_calling_sequence;
1559 
1560     l_debug_info := 'Open invoices_cursor and do bulk fetch';
1561 
1562     OPEN invoices_cursor;
1563     FETCH invoices_cursor
1564     BULK COLLECT INTO l_invoice_id_list;
1565     CLOSE invoices_cursor;
1566 
1567   IF l_invoice_id_list.COUNT > 0 THEN  --bug 11781836
1568     FOR i IN l_invoice_id_list.FIRST..l_invoice_id_list.LAST
1569     LOOP
1570 
1571     /* Bug 9497953
1572     -- bug 6883407
1573     l_debug_info := 'Fetch Invoice GL Date.';
1574     SELECT ai.gl_date
1575     INTO   l_invoice_gl_date
1576     FROM   ap_invoices ai
1577     WHERE  ai.invoice_id = l_invoice_id_list(i); */
1578 
1579 
1580       l_success := AP_Cancel_Single_Invoice(
1581                        l_invoice_id_list(i),
1582                        P_last_updated_by,
1583                        P_last_update_login,
1584                        P_accounting_date,        -- Bug 9497953 l_invoice_gl_date, --P_accounting_date,-- bug 6883407
1585                        l_message_name,
1586                        l_invoice_amount,
1587                        l_base_amount,
1588                        l_temp_cancelled_amount,
1589                        l_cancelled_by,
1590                        l_cancelled_amount,
1591                        l_cancelled_date,
1592                        l_last_update_date,
1593                        l_original_prepayment_amount,
1594                        l_pay_curr_invoice_amount,
1595 		       l_token,
1596                        l_curr_calling_sequence);
1597 
1598       IF (l_success) THEN
1599         l_num_cancelled := l_num_cancelled + 1;
1600       ELSE
1601         l_num_not_cancelled := l_num_not_cancelled + 1;
1602       END IF;
1603 
1604     END LOOP;
1605   END IF; --bug 11781836
1606     l_invoice_id_list.DELETE;
1607 
1608     P_num_cancelled := l_num_cancelled;
1609     P_num_not_cancelled := l_num_not_cancelled;
1610 
1611   EXCEPTION
1612     WHEN OTHERS THEN
1613       IF (SQLCODE <> -20001) THEN
1614         FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1615         FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1616         FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
1617         FND_MESSAGE.SET_TOKEN('PARAMETERS',
1618                               ' P_check_id = '     || P_check_id
1619           ||' P_last_updated_by = '   || P_last_updated_by
1620           ||' P_last_update_login = ' || P_last_update_login
1621           ||' P_accounting_date = '   || P_accounting_date);
1622         FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
1623       END IF;
1624 
1625       IF ( invoices_cursor%ISOPEN ) THEN
1626         CLOSE invoices_cursor;
1627       END IF;
1628       APP_EXCEPTION.RAISE_EXCEPTION;
1629 
1630   END Ap_Cancel_Invoices;
1631 
1632   -- Added for Payment Request Cancellation from Payables.
1633   -- Procedure to subscribe to the invoice cancellation event by other products
1634   -- This procedure checks the product registry table for all the product that have
1635   -- subscribed to cancellation event and calls the product API.
1636   ---------------------------------------------------------------------------------
1637   PROCEDURE Subscribe_To_Cancel_Event
1638                       (P_Event_Type         IN             VARCHAR2,
1639                        P_Invoice_ID         IN             NUMBER,
1640                        P_Application_ID     IN             NUMBER,
1641                        P_Return_Status      OUT     NOCOPY VARCHAR2,
1642                        P_Msg_Count          OUT     NOCOPY NUMBER,
1643                        P_Msg_Data           OUT     NOCOPY VARCHAR2,
1644                        P_Calling_Sequence   IN             VARCHAR2) IS
1645 
1646 
1647   current_calling_sequence    VARCHAR2(2000);
1648   debug_info                  VARCHAR2(100);
1649 
1650   l_stmt                      VARCHAR2(1000);
1651   l_return_status             VARCHAR2(1);
1652   l_msg_count                 NUMBER;
1653   l_msg_data                  VARCHAR2(2000);
1654 
1655 
1656   CURSOR c_products_registered IS
1657   SELECT Reg_Application_ID,
1658          Registration_API
1659   FROM   AP_Product_Registrations
1660   WHERE  Reg_Application_ID = P_Application_ID
1661   AND    Registration_Event_Type = P_Event_Type;
1662 
1663    BEGIN
1664 
1665     -- Update the calling sequence
1666     --
1667     current_calling_sequence := 'AP_Cancel_PKG.Subscribe_To_Cancel_Event<-' ||
1668                                            P_calling_sequence;
1669 
1670     debug_info := 'Calling the subscribe payment event API';
1671 
1672     FOR c_product_rec IN c_products_registered
1673     LOOP
1674 
1675         l_stmt := 'Begin ' ||
1676                    c_product_rec.Registration_API ||
1677                           '(:P_Event_Type,' ||
1678                            ':P_Invoice_ID,' ||
1679                            ':l_return_Status,' ||
1680                            ':l_msg_count,' ||
1681                            ':l_msg_data);' ||
1682                   'End;';
1683 
1684         EXECUTE IMMEDIATE l_stmt
1685                   USING IN  P_Event_Type,
1686                         IN  P_Invoice_ID,
1687                         OUT l_return_status,
1688                         OUT l_msg_count,
1689                         OUT l_msg_data;
1690 
1691         P_Return_Status := l_return_status;
1692         P_Msg_Count := l_msg_count;
1693         P_Msg_Data := l_msg_data;
1694 
1695 
1696     END LOOP;
1697 
1698   EXCEPTION
1699 
1700     WHEN OTHERS THEN
1701          IF (SQLCODE <> -20001) THEN
1702              FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1703              FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1704              FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',current_calling_sequence);
1705              FND_MESSAGE.SET_TOKEN('PARAMETERS','Invoice_id = ' || to_char(P_Invoice_ID));
1706              FND_MESSAGE.SET_TOKEN('DEBUG_INFO',debug_info);
1707          END IF;
1708     APP_EXCEPTION.RAISE_EXCEPTION;
1709 
1710   END Subscribe_To_Cancel_Event;
1711 
1712 END AP_CANCEL_PKG;