1 PACKAGE BODY AP_CANCEL_PKG AS
2 /* $Header: apicancb.pls 120.35.12010000.6 2009/02/20 06:57:10 ppodhiya 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
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
200 IF ( l_payment_count <> 0 ) THEN
201 P_error_code := 'AP_INV_CANCEL_EFF_PAYMENT';
202 P_debug_info := l_debug_info;
203 RETURN FALSE;
204 END IF;
205
206 /*-----------------------------------------------------------------+
207 | Step 2. If invoice is selected for payment, return FALSE |
208 +-----------------------------------------------------------------*/
209
210 l_debug_info := 'Check if invoice is selected for payment';
211
212 BEGIN
213 OPEN verify_no_pay_batch;
214 LOOP
215 FETCH verify_no_pay_batch
216 INTO l_checkrun_id;
217 EXIT WHEN verify_no_pay_batch%NOTFOUND;
218 IF l_checkrun_id IS NOT NULL THEN
219 P_error_code := 'AP_INV_CANCEL_SEL_PAYMENT';
220 P_debug_info := l_debug_info || 'with no check run id';
221 COMMIT;
222 RETURN FALSE;
223 END IF;
224 END LOOP;
225
226 EXCEPTION
227 WHEN OTHERS THEN
228 IF ( verify_no_pay_batch%ISOPEN ) THEN
229 CLOSE verify_no_pay_batch;
230 END IF;
231 P_error_code := 'AP_INV_CANCEL_PS_LOCKED';
232 P_debug_info := l_debug_info || 'With exceptions';
233 COMMIT;
234 RETURN FALSE;
235 END;
236
237 /*-----------------------------------------------------------------+
238 | Step 3. If invoice is already cancelled, return FALSE |
239 +-----------------------------------------------------------------*/
240
241 l_debug_info := 'Check if invoice is already cancelled';
242
243 SELECT count(*)
244 INTO l_cancel_count
245 FROM ap_invoices
246 WHERE invoice_id = P_invoice_id
247 AND cancelled_date IS NOT NULL;
248
249 IF (l_cancel_count > 0) THEN
250 P_error_code := 'AP_INV_CANCEL_ALREADY_CNCL';
251 P_debug_info := l_debug_info;
252 RETURN FALSE;
253 END IF;
254
255 /*-----------------------------------------------------------------+
256 | Step 4. If invoice is a credited invoice return FALSE |
257 +-----------------------------------------------------------------*/
258 l_debug_info := 'Check if invoice is a credited invoice';
259
260 l_credited_inv_flag := AP_INVOICES_UTILITY_PKG.Is_Inv_Credit_Referenced(
261 P_invoice_id);
262
263 IF (l_credited_inv_flag <> FALSE ) THEN
264 P_error_code := 'AP_INV_IS_CREDITED_INV';
265 P_debug_info := l_debug_info;
266 RETURN FALSE;
267 END IF;
268
269 /*-----------------------------------------------------------------+
270 | Step 5. If invoices have been applied against this invoice |
271 | return FALSE |
272 +-----------------------------------------------------------------*/
273
274 l_debug_info := 'Check if invoices have been applied against this invoice';
275
276 l_prepay_applied_flag :=
277 AP_INVOICES_UTILITY_PKG.get_prepayments_applied_flag(P_invoice_id);
278
279 IF (nvl(l_prepay_applied_flag,'N') = 'Y') THEN
280 P_error_code := 'AP_INV_PP_NO_CANCEL';
281 P_debug_info := l_debug_info;
282 RETURN FALSE;
283 END IF;
284
285 /*-----------------------------------------------------------------+
286 | Step 6. If invoice is matched to a Finally Closed PO, return |
287 | FALSE |
288 +-----------------------------------------------------------------*/
289
290 l_debug_info := 'Check if invoice is matched to a finally closed PO';
291
292 -- Bug fix:3488316
293 -- Following code in this step has been added for JFMIP related work.
294 -- This code has been modified only for federal customers, before modifying
295 -- this code please get the code verified with the developer/manager
296 -- who added this code.
297 /* bug 4942638. Move the next select for l_org_id at the begining */
298
299 IF (FV_INSTALL.ENABLED (l_org_id)) THEN
300
301 BEGIN
302
303 SELECT 'N'
304 INTO l_allow_cancel
305 FROM ap_invoice_distributions AID,
306 po_distributions PD,
307 po_line_locations pll
308 WHERE aid.invoice_id = p_invoice_id
309 --AND aid.final_match_flag in ('N','Y') For Bug 3489536
310 AND aid.po_distribution_id = pd.po_distribution_id
311 AND pll.line_location_id = pd.line_location_id
312 AND decode(pll.final_match_flag, 'Y', 'D', aid.final_match_flag) in ('N','Y') --Bug 3489536
313 AND pll.closed_code = 'FINALLY CLOSED'
314 AND rownum = 1;
315
316 IF (l_allow_cancel = 'N') THEN
317 P_error_code := 'AP_INV_CANNOT_OPEN_SHIPMENT';
318 P_debug_info := l_debug_info;
319 RETURN(FALSE);
320 END IF;
321
322 EXCEPTION
323 WHEN NO_DATA_FOUND THEN
324
325 SELECT count(distinct pll.line_location_id)
326 INTO l_final_closed_shipment_count
327 FROM ap_invoice_distributions aid,
328 po_line_locations pll,
329 po_distributions pd
330 WHERE aid.invoice_id = p_invoice_id
331 AND aid.po_distribution_id = pd.po_distribution_id
332 AND pd.line_location_id = pll.line_location_id
333 --AND aid.final_match_flag = 'D' For bug 3489536
334 AND decode(pll.final_match_flag, 'Y', 'D', aid.final_match_flag) = 'D' --Bug 3489536
335 AND pll.closed_code = 'FINALLY CLOSED';
336
337 END ;
338
339 IF (l_final_closed_shipment_count > 1) THEN
340
341 P_error_code := 'AP_INV_MUL_SHIP_FINALLY_CLOSED' ;
342 P_debug_info := l_debug_info;
343 RETURN(FALSE);
344
345 END IF;
346
347 IF (l_final_closed_shipment_count = 1) THEN
348
349 l_debug_info := 'Open the Finally Closed PO Shipment ';
350 IF(NOT(FV_AP_CANCEL_PKG.OPEN_PO_SHIPMENT(p_invoice_id,
351 l_return_code))) THEN
352
353 P_error_code := 'AP_INV_CANNOT_OPEN_SHIPMENT';
354 P_debug_info := l_debug_info;
355 RETURN(FALSE);
356
357 END IF;
358
359 END IF;
360
361 ELSE
362
363
364 SELECT count(*)
365 INTO l_final_close_count
366 FROM ap_invoice_lines AIL,
367 po_line_locations_ALL PL
368 WHERE AIL.invoice_id = P_invoice_id
369 AND AIL.po_line_location_id = PL.line_location_id
370 AND AIL.org_id = PL.org_id
371 AND PL.closed_code = 'FINALLY CLOSED';
372
373 IF (l_final_close_count > 0) THEN
374 P_error_code := 'AP_INV_PO_FINALLY_CLOSED';
375 P_debug_info := l_debug_info;
376 RETURN FALSE;
377 END IF;
378 END IF;
379 /*-----------------------------------------------------------------+
380 | Step 7. If projects have pending adjustments then return FALSE |
381 +-----------------------------------------------------------------*/
382 --
383 -- Bug 5349193
384 -- As suggested in the bug, this validation is commented in R12.
385 --
386
387 /* SELECT count(*)
388 INTO l_project_related_count
389 FROM ap_invoices AI
390 WHERE AI.invoice_id = P_invoice_id
391 AND (AI.project_id is not null OR
392 exists (select 'X'
393 from ap_invoice_distributions AIL
394 where AIL.invoice_id = AI.invoice_id
395 and project_id is not null) OR
396 exists (select 'X'
397 from ap_invoice_distributions AID
398 where AID.invoice_id = AI.invoice_id
399 and project_id is not null));
400
401 IF (l_project_related_count <> 0) THEN
402 l_pa_message_name := pa_integration.pending_vi_adjustments_exists(
403 P_invoice_id);
404 IF (l_pa_message_name <> 'N') THEN
405 P_error_code := l_pa_message_name;
406 P_debug_info := l_debug_info;
407 RETURN FALSE;
408 END IF;
409 END IF; */
410
411 /*-----------------------------------------------------------------+
412 | Step 8. if the quantity billed and amount on PO would be |
413 | reduced to less than zero then return FALSE |
414 | Always allow Reversal distributions to be cancelled |
415 +-----------------------------------------------------------------*/
416
417 BEGIN
418
419 OPEN qty_per_dist_negtive_count_cur;
420 FETCH qty_per_dist_negtive_count_cur
421 INTO l_po_dist_count;
422 CLOSE qty_per_dist_negtive_count_cur;
423
424 END;
425
426 IF ( l_po_dist_count > 0 ) THEN
427 P_error_code := 'AP_INV_PO_CANT_CANCEL';
428 P_debug_info := l_debug_info;
429 RETURN FALSE;
430 END IF;
431
432 /*-----------------------------------------------------------------+
433 | Step 9. if the invoice is matched to an unapproved PO, if the
434 | encumbrance is on, then do not allow the invoice
435 | cancellation (bug6009101)
436 *-----------------------------------------------------------------*/
437
438 l_debug_info := 'Check if the PO is unapproved';
439
440 SELECT NVL(purch_encumbrance_flag,'N')
441 INTO l_enc_enabled
442 FROM financials_system_params_all
443 WHERE NVL(org_id, -99) = NVL(l_org_id, -99);
444
445 if l_enc_enabled = 'Y' then
446
447 begin
448
449 select 'Y'
450 into l_po_not_approved
451 from po_headers POH,
452 po_distributions POD,
453 ap_invoice_distributions AID,
454 ap_invoices AI
455 where AI.invoice_id = AID.invoice_id
456 and AI.invoice_id = P_invoice_id
457 and AID.po_distribution_id = POD.po_distribution_id
458 and POD.po_header_id = POH.po_header_id
459 and POH.approved_flag <> 'Y'
460 and rownum = 1;
461
462 EXCEPTION
463 WHEN OTHERS THEN
464 NULL;
465
466 end;
467
468 if l_po_not_approved = 'Y' then
469 p_error_code := 'AP_PO_UNRES_CANT_CANCEL';
470 p_debug_info := l_debug_info;
471 return FALSE;
472 end if;
473 end if;
474
475
476 p_error_code := null;
477 P_debug_info := l_debug_info;
478 RETURN TRUE;
479
480 EXCEPTION
481 WHEN OTHERS THEN
482 IF (SQLCODE <> -20001) THEN
483 FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
484 FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
485 FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
486 FND_MESSAGE.SET_TOKEN('PARAMETERS',
487 ' P_invoice_id = ' || P_invoice_id );
488 FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
489 END IF;
490
491 IF (qty_per_dist_negtive_count_cur%ISOPEN ) THEN
492 CLOSE qty_per_dist_negtive_count_cur;
493 END IF;
494
495 IF ( dist_gl_date_cur%ISOPEN ) THEN
496 CLOSE dist_gl_date_cur;
497 END IF;
498
499 P_debug_info := l_debug_info || 'With exceptions';
500 RETURN FALSE;
501
502 END Is_Invoice_Cancellable;
503
504
505 /*=============================================================================
506 | Function Ap_Cancel_Single_Invoice
507 |
508 | cancels one invoice by executing the following sequence of steps,
509 | returning TRUE if successful and FALSE otherwise.
510 |
511 | PROGRAM FLOW
512 |
513 | 1. check if invoice cancellable, if yes, proceed otherwise return false
514 | 3.(If invoice has had tax withheld, undo withholding) - commented
515 | 4. Clear out payment schedules
516 | 5. Cancel all the non-discard lines
517 | a. reverse matching
518 | b. fetch the maximum distribution line number
519 | c. Set encumbered flags to 'N'
520 | d. Accounting event generation
521 | e. reverse the distributions
522 | f. update Line level Cancelled information
523 | 6. Zero out the Invoice
524 | 7. Run AutoApproval for this invoice
525 | 8. check posting holds remain on this canncelled invoice
526 | a. if NOT exist - complete the cancellation by updating header
527 | level information set return value to TRUE
528 | b. if exist - no update, set the return valuse to FALSE, NO
529 | DATA rollback.
530 | 9. Commit Data
531 | 10. Populate the out parameters.
532 |
533 | NOTES
534 | 1. bug2328225 case of Matching a special charge only invoice to
535 | receipt so we check if the quantity invoiced is not null too
536 | 2. Events Project
537 | We no longer need to prevent the cancellation of an invoice
538 | just because the accounting of related payments has not been
539 | created. Therefore, bug fixes 902110 and 2237152 are removed.
540 |
541 | MODIFICATION HISTORY
542 | Date Author Description of Change
543 |
544 *============================================================================*/
545
546 FUNCTION Ap_Cancel_Single_Invoice(
547 P_invoice_id IN NUMBER,
548 P_last_updated_by IN NUMBER,
549 P_last_update_login IN NUMBER,
550 P_accounting_date IN DATE,
551 P_message_name OUT NOCOPY VARCHAR2,
552 P_invoice_amount OUT NOCOPY NUMBER,
553 P_base_amount OUT NOCOPY NUMBER,
554 P_temp_cancelled_amount OUT NOCOPY NUMBER,
555 P_cancelled_by OUT NOCOPY NUMBER,
556 P_cancelled_amount OUT NOCOPY NUMBER,
557 P_cancelled_date OUT NOCOPY DATE,
558 P_last_update_date OUT NOCOPY DATE,
559 P_original_prepayment_amount OUT NOCOPY NUMBER,
560 P_pay_curr_invoice_amount OUT NOCOPY NUMBER,
561 P_Token OUT NOCOPY VARCHAR2,
562 P_calling_sequence IN VARCHAR2) RETURN BOOLEAN
563 IS
564
565 CURSOR Invoice_Lines_cur IS
566 SELECT *
567 FROM ap_invoice_lines
568 WHERE invoice_id = P_invoice_id
569 AND (NVL(discarded_flag, 'N' ) <> 'Y'
570 AND NVL(cancelled_flag, 'N') <> 'Y') -- Bug 6669048
571 ORDER BY line_type_lookup_code;
572
573 CURSOR Tax_Holds_Cur IS
574 SELECT AH.hold_lookup_code
575 FROM AP_HOLDS AH,
576 AP_HOLD_CODES AHC
577 WHERE AH.invoice_id = P_invoice_id
578 AND AH.hold_lookup_code = AHC.hold_lookup_code
579 AND AH.release_lookup_code IS NULL
580 AND AH.hold_lookup_code IN ('TAX AMOUNT RANGE','TAX VARIANCE');
581
582 -- Cursor added for Payment Request Cancellation from Payables and
583 -- notifying the calling product.
584
585 CURSOR c_reg_products IS
586 SELECT Reg_Application_ID
587 FROM AP_Invoices_All AI,
588 AP_Product_Registrations APR
589 WHERE AI.Invoice_ID = P_Invoice_ID
590 AND AI.Application_ID = APR.Reg_Application_ID
591 AND APR.Registration_Event_Type = 'INVOICE_CANCELLED';
592
593 cursor dist_debug_cur is
594 Select *
595 FROM ap_invoice_distributions_all aid
596 WHERE aid.invoice_id = p_invoice_id;
597
598 l_inv_line_rec_list Inv_Line_Tab_Type;
599 l_ok_to_cancel BOOLEAN := FALSE;
600 l_discard_line_ok BOOLEAN := FALSE;
601 l_count NUMBER;
602 l_holds_count NUMBER := 0;
603 l_success BOOLEAN;
604 l_approval_status VARCHAR2(25);
605 l_result_string VARCHAR2(240);
606 l_error_code VARCHAR2(4000);
607 l_approval_return_message VARCHAR2(2000);
608 l_debug_info VARCHAR2(240);
609 l_curr_calling_sequence VARCHAR2(2000);
610 l_tax_already_calculated BOOLEAN;
611 i BINARY_INTEGER := 1;
612 l_tax_holds_count NUMBER := 0;
613 l_hold_code_tab AP_ETAX_SERVICES_PKG.REL_HOLD_CODES_TYPE;
614 l_token VARCHAR2(4000);
615 l_invoice_amount AP_INVOICES_ALL.INVOICE_AMOUNT%TYPE;
616 l_invoice_validation_status VARCHAR2(100);
617 l_payment_status_flag AP_INVOICES_ALL.PAYMENT_STATUS_FLAG%TYPE;
618 l_invoice_type_lookup_code AP_INVOICES_ALL.INVOICE_TYPE_LOOKUP_CODE%TYPE;
619 Tax_Exception EXCEPTION;
620 --Bug 4539462 DBI logging
621 l_dbi_key_value_list ap_dbi_pkg.r_dbi_key_value_arr;
622
623 -- Bug 6669048
624 l_tax_lines_count NUMBER := 0;
625 l_self_assess_tax_count NUMBER := 0 ; -- Bug 6694536
626 l_tax_dist_count NUMBER := 0; -- Bug 6815172
627
628 -- Bug 4748638
629 l_Accounting_event_ID AP_INVOICE_DISTRIBUTIONS_ALL.accounting_event_id%TYPE;
630 l_cancel_dist_exists NUMBER := 0;
631 l_open_gl_date AP_INVOICES_ALL.gl_date%type;
632 l_funds_return_code VARCHAR2(30); -- 4276409 (3462325)
633
634 -- Payment request Cancellation Subscription
635 l_return_status varchar2(1);
636 l_msg_count number;
637 l_msg_data varchar2(2000);
638 l_application_id number;
639
640 l_chk_encum NUMBER := 0; ---7264524
641 l_check_encumbrance NUMBER := 0; ---7428195
642 p_holds AP_APPROVAL_PKG.HOLDSARRAY; --7264524
643 p_hold_count AP_APPROVAL_PKG.COUNTARRAY; --7264524
644 p_release_count AP_APPROVAL_PKG.COUNTARRAY; --7264524
645 l_procedure_name CONSTANT VARCHAR2(50) := 'cancel_single_invoice';
646
647 BEGIN
648 l_curr_calling_sequence := 'AP_CANCEL_PKG.AP_CANCEL_SINGLE_INVOICE<-' ||
649 P_calling_sequence;
650
651 /*-----------------------------------------------------------------+
652 | Step 1. Check if invoice is cancellable |
653 +-----------------------------------------------------------------*/
654
655 l_debug_info := 'Check if invoice is cancellable';
656
657 l_ok_to_cancel := Is_Invoice_Cancellable(
658 P_invoice_id => p_invoice_id,
659 P_error_code => p_message_name,
660 P_debug_info => l_debug_info,
661 P_calling_sequence => l_curr_calling_sequence);
662
663 IF ( l_ok_to_cancel = FALSE ) THEN
664 RETURN FALSE;
665 END IF;
666
667 /*-----------------------------------------------------------------+
668 | Step 2. If invoice has had tax withheld, undo withholding |
669 | |
670 +-----------------------------------------------------------------*/
671
672 l_debug_info := 'Check if AWT has been performed by AutoApproval';
673
674 SELECT count(*)
675 INTO l_count
676 FROM ap_invoices
677 WHERE invoice_id = P_invoice_id
678 AND NVL(awt_flag,'N') = 'Y';
679
680 IF (l_count > 0) THEN
681
682 AP_WITHHOLDING_PKG.AP_UNDO_WITHHOLDING(
683 P_invoice_id,
684 'CANCEL INVOICE',
685 P_accounting_date,
686 NULL,
687 P_Last_Updated_By,
688 P_Last_Update_Login,
689 NULL,
690 NULL,
691 NULL,
692 l_result_string);
693 END IF;
694
695 IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
696 FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
697 END IF;
698
699 /*-----------------------------------------------------------------+
700 | Step 3. Clear out payment schedules |
701 | 1. Set hold_flag to 'N' to make cancelled invoice |
702 | does not show up on 'Invoice on Hold report'. |
703 +-----------------------------------------------------------------*/
704
705 l_debug_info := 'Clear out payment schedules';
706
707 UPDATE ap_payment_schedules
708 SET gross_amount = 0
709 ,amount_remaining = 0
710 ,payment_status_flag = 'N'
711 ,hold_flag = 'N'
712 ,last_updated_by = P_last_updated_by
713 ,last_update_date = sysdate
714 ,inv_curr_gross_amount =0 --Bug5446999
715 WHERE invoice_id = P_invoice_id;
716
717 --Bug 4539462 DBI logging
718 AP_DBI_PKG.Maintain_DBI_Summary
719 (p_table_name => 'AP_PAYMENT_SCHEDULES',
720 p_operation => 'U',
721 p_key_value1 => P_invoice_id,
722 p_calling_sequence => l_curr_calling_sequence);
723
724 /*-----------------------------------------------------------------+
725 | Step 4. Discard Line in Cancel Mode for each line of invoice |
726 +-----------------------------------------------------------------*/
727
728 IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
729 l_debug_info := 'step4 - Now call Discard Lines for the invoice';
730 FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
731 END IF;
732
733
734 BEGIN
735 OPEN Invoice_Lines_Cur;
736 FETCH Invoice_Lines_Cur
737 BULK COLLECT INTO l_inv_line_rec_list;
738 CLOSE Invoice_Lines_Cur;
739 END;
740
741 SELECT invoice_type_lookup_code,
742 payment_status_flag,
743 invoice_amount
744 INTO l_invoice_type_lookup_code,
745 l_payment_status_flag,
746 l_invoice_amount
747 FROM ap_invoices
748 WHERE invoice_id =p_invoice_id;
749
750 l_invoice_validation_status := ap_invoices_pkg.get_approval_status(
751 l_invoice_id => p_invoice_id,
752 l_invoice_amount => l_invoice_amount,
753 l_payment_status_flag => l_payment_status_flag,
754 l_invoice_type_lookup_code => l_invoice_type_lookup_code );
755
756 l_debug_info := 'Dicard Lines for the invoice: Calling etax for Validated Invoice';
757
758 IF (NVL(l_invoice_validation_status,'NEVER APPROVED') IN
759 ('APPROVED','AVAILABLE','UNPAID','FULL')) THEN
760
761 l_success := ap_etax_pkg.calling_etax(
762 P_Invoice_id => p_invoice_id,
763 P_Calling_Mode => 'UNFREEZE INVOICE',
764 P_All_Error_Messages => 'N',
765 P_error_code => l_error_code,
766 P_Calling_Sequence => l_curr_calling_sequence);
767
768 IF (not l_success) THEN
769 p_message_name := 'AP_ETX_CANCEL_UNFRZ_INV_FAILED';
770 p_token := l_error_code;
771 RETURN(FALSE);
772 END IF;
773
774 END IF;
775
776
777 l_debug_info := 'Dicard Lines for the invoice: Discarding Individual line';
778 --Bug 5585992
779 IF l_inv_line_rec_list.count > 0 THEN
780
781 FOR i in l_inv_line_rec_list.FIRST..l_inv_line_rec_list.LAST
782 LOOP
783 -- Bug 5585992
784 IF l_inv_line_rec_list.exists(i) THEN
785
786 /* Added nvl condition to p_accounting_date for bug #6627060 */
787 -- Bug 5584997
788 l_inv_line_rec_list(i).accounting_date :=
789 nvl(p_accounting_date,l_inv_line_rec_list(i).accounting_date);
790
791 l_discard_line_ok := AP_INVOICE_LINES_PKG.Discard_Inv_Line(
792 P_line_rec => l_inv_line_rec_list(i),
793 P_calling_mode => 'CANCEL',
794 P_inv_cancellable => 'Y',
795 P_last_updated_by => p_last_updated_by,
796 P_last_update_login => p_last_update_login,
797 P_error_code => l_error_code,
798 P_Token => l_token,
799 P_calling_sequence => l_curr_calling_sequence);
800
801 IF ( l_discard_line_ok = FALSE ) THEN
802 P_Message_Name := l_error_code;
803 P_Token := l_token;
804 RETURN FALSE;
805 END IF;
806
807 END IF;
808
809 END LOOP;
810
811 l_inv_line_rec_list.DELETE;
812
813 ELSE
814
815 l_discard_line_ok := TRUE;
816
817 END IF;
818
819 --ETAX:
820 l_tax_already_calculated := AP_ETAX_UTILITY_PKG.Is_Tax_Already_Calc_Inv(
821 P_Invoice_Id => p_invoice_id,
822 P_Calling_Sequence => l_curr_calling_sequence);
823
824 IF (l_tax_already_calculated) THEN
825
826 -- Bug 6669048. Get the count of tax lines that have not been cancelled.
827 SELECT count(*)
828 INTO l_tax_lines_count
829 FROM ap_invoice_lines
830 WHERE invoice_id = p_invoice_id
831 AND line_type_lookup_code = 'TAX'
832 AND NVL(cancelled_flag,'N') <> 'Y'
833 AND rownum =1;
834
835 -- Bug 6694536. Need to call the etax api to reverse the self assessed tax lines.
836
837 SELECT count(*)
838 INTO l_self_assess_tax_count
839 FROM ap_self_assessed_tax_dist_all asat,
840 zx_rec_nrec_dist zx_dist
841 WHERE invoice_id = p_invoice_id
842 AND asat.detail_tax_dist_id = zx_dist.rec_nrec_tax_dist_id
843 AND zx_dist.self_assessed_flag = 'Y'
844 AND nvl(zx_dist.reverse_flag, 'N') <> 'Y'
845 AND line_type_lookup_code IN ('REC_TAX', 'NONREC_TAX')
846 AND rownum =1;
847
848 -- Bug 6815172. Get the count of tax distribution lines that
849 -- have not been cancelled in case of inclusive tax.
850
851 SELECT count(*)
852 INTO l_tax_dist_count
853 FROM zx_rec_nrec_dist zx_dist,
854 ap_invoice_distributions ap_dist
855 WHERE ap_dist.invoice_id = p_invoice_id
856 AND ap_dist.detail_tax_dist_id = zx_dist.rec_nrec_tax_dist_id
857 AND nvl(zx_dist.reverse_flag, 'N') <> 'Y'
858 AND nvl(zx_dist.inclusive_flag, 'N') = 'Y'
859 AND ap_dist.line_type_lookup_code IN ('REC_TAX', 'NONREC_TAX')
860 AND rownum =1;
861
862 -- Bug 7553603
863 -- cancelled_flag needs to be set prior to calling the tax api as
864 -- the line_level_action needs to be sent as DISCARD. This was
865 -- a regression from bug 6669048.
866
867 UPDATE ap_invoice_lines
868 SET cancelled_flag = 'Y'
869 WHERE invoice_id = P_invoice_id
870 AND NVL(discarded_flag, 'N' ) <> 'Y';
871
872 -- Bug 6669048. We should not be calling the etax API if all the tax
873 -- lines have already been cancelled.
874 IF l_tax_lines_count > 0 OR l_self_assess_tax_count > 0
875 OR l_tax_dist_count > 0 -- Bug 6815172
876 THEN
877
878 l_success := ap_etax_pkg.calling_etax(p_invoice_id => p_invoice_id,
879 p_calling_mode => 'CANCEL INVOICE',
880 p_all_error_Messages => 'N',
881 p_error_code => l_error_code,
882 p_calling_sequence => l_curr_calling_sequence);
883
884 IF NOT(l_success) THEN
885 Raise Tax_Exception;
886 END IF;
887
888 END IF;
889
890 END IF;
891
892 /*-----------------------------------------------------------------+
893 | Step 5. Zero out the invoice for main invoice table |
894 +-----------------------------------------------------------------*/
895
896 IF ( l_discard_line_ok ) THEN
897 l_debug_info := 'Zero out the invoice';
898
899 UPDATE ap_invoices
900 SET invoice_amount = 0
901 ,base_amount = 0
902 ,temp_cancelled_amount = DECODE(temp_cancelled_amount, NULL,
903 invoice_amount,
904 DECODE(invoice_amount, 0,
905 temp_cancelled_amount,
906 invoice_amount))
907 ,pay_curr_invoice_amount = 0
908 ,last_updated_by = P_last_updated_by
909 ,last_update_date = sysdate
910 WHERE invoice_id = P_invoice_id;
911
912 -- Bug 6669048. Update the cancelled_flag for all the lines to 'Y' since
913 -- at this point all the invoice lines have been discarded including the
914 -- tax lines and AWT lines
915 UPDATE ap_invoice_lines
916 SET cancelled_flag = 'Y'
917 WHERE invoice_id = P_invoice_id
918 AND NVL(discarded_flag, 'N' ) <> 'Y';
919
920 --Bug 4539462 DBI logginG
921 AP_DBI_PKG.Maintain_DBI_Summary
922 (p_table_name => 'AP_INVOICES',
923 p_operation => 'U',
924 p_key_value1 => P_Invoice_Id,
925 p_calling_sequence => l_curr_calling_sequence);
926
927 IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
928 l_debug_info := 'Before call approval pkg again ';
929 FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
930
931 FOR l_inv_dist_rec IN dist_debug_cur
932 loop
933 l_debug_info :='invoice distribution looks like'||
934 'l_dist_type = ' || l_inv_dist_rec.line_type_lookup_code||
935 'l_amount=' || l_inv_dist_rec.amount ||
936 'l_base_amount =' || l_inv_dist_rec.base_amount ||
937 'l_match_status_flag=' ||l_inv_dist_rec.match_status_flag ;
938 FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
939 end loop;
940
941 END IF;
942
943 /*-----------------------------------------------------------------+
944 | Step 7. Run Approval again for this cancelled invoice |
945 | Ignore message returned from APPROVE process |
946 +-----------------------------------------------------------------*/
947
948 IF (G_LEVEL_PROCEDURE >= G_CURRENT_RUNTIME_LEVEL ) THEN
949 l_debug_info := 'Run Approval for this invoice again';
950 FND_LOG.STRING(G_LEVEL_PROCEDURE, G_MODULE_NAME||l_procedure_name, l_debug_info);
951 END IF;
952
953 --SMYADAM: Approve procedure calls 4 etax apis (calculate, distribute, validate, freeze).
954 --Do we need to call these apis when the invoice is being cancelled also (looks unnecessary)
955 --, if we decide not to call these apis for cancellation case,
956 --what if the invoice cancellation doesn't go thru due to postable holds which
957 --we will know only after the validation has been done, and then since we did not
958 --call the etax apis during the approve call and the invoice is not cancelled , won't
959 --the tax data on this invoice be stale. ??
960
961 AP_APPROVAL_PKG.APPROVE(
962 P_RUN_OPTION => '',
963 P_INVOICE_BATCH_ID => '',
964 P_BEGIN_INVOICE_DATE => '',
965 P_END_INVOICE_DATE => '',
966 P_VENDOR_ID => '',
967 P_PAY_GROUP => '',
968 P_INVOICE_ID => P_invoice_id,
969 P_ENTERED_BY => '',
970 P_SET_OF_BOOKS_ID => '',
971 P_TRACE_OPTION => '',
972 P_CONC_FLAG => 'N',
973 P_HOLDS_COUNT => l_holds_count,
974 P_APPROVAL_STATUS => l_approval_status,
975 P_FUNDS_RETURN_CODE => l_funds_return_code, -- 4276409 (3462325)
976 P_CALLING_MODE => 'CANCEL',
977 P_CALLING_SEQUENCE => l_curr_calling_sequence,
978 P_COMMIT => 'N');
979
980 l_approval_return_message := FND_MESSAGE.GET;
981
982 ----7264524 STARTS
983
984 l_debug_info := 'Check for INSUFFICIENT HOLDS and CANT FUNDS CHECK Holds';
985
986 BEGIN
987
988 SELECT count(*)
989 INTO l_chk_encum
990 FROM ap_holds AH
991 ,ap_hold_codes AHC
992 WHERE AH.invoice_id = P_invoice_id
993 AND AH.hold_lookup_code = AHC.hold_lookup_code
994 AND AH.release_lookup_code IS NULL
995 AND AHC.postable_flag = 'N'
996 AND AH.hold_lookup_code IN ('INSUFFICIENT FUNDS','CANT FUNDS CHECK');
997
998
999 ---7428195 starts
1000 SELECT 1
1001 INTO l_check_encumbrance
1002 FROM ap_invoice_distributions_all
1003 WHERE invoice_id = P_invoice_id
1004 AND encumbered_flag = 'Y'
1005 AND rownum < 2;
1006
1007 IF (l_chk_encum<>0 AND l_check_encumbrance = 0 ) THEN
1008
1009
1010
1011
1012 AP_APPROVAL_PKG.Process_Inv_Hold_Status(
1013 P_invoice_id,
1014 null,
1015 null,
1016 'INSUFFICIENT FUNDS',
1017 'N',
1018 null,
1019 7264524,
1020 p_holds,
1021 p_hold_count,
1022 p_release_count,
1023 'release before cancel');
1024
1025
1026 AP_APPROVAL_PKG.Process_Inv_Hold_Status(
1027 P_invoice_id,
1028 null,
1029 null,
1030 'CANT FUNDS CHECK',
1031 'N',
1032 null,
1033 7264524,
1034 p_holds,
1035 p_hold_count,
1036 p_release_count,
1037 'release before cancel');
1038
1039 END IF;
1040
1041
1042 EXCEPTION
1043 WHEN OTHERS THEN
1044 l_chk_encum := 0;
1045
1046 END;
1047
1048 ---7428195 ends
1049 ---7264524 ENDS
1050 /*-----------------------------------------------------------------+
1051 | Step 8. Check if there are posting hold exist |
1052 +-----------------------------------------------------------------*/
1053
1054 l_debug_info := 'Get the number of posting holds for invoice';
1055
1056 BEGIN
1057 SELECT count(*)
1058 INTO l_holds_count
1059 FROM ap_holds AH
1060 ,ap_hold_codes AHC
1061 WHERE AH.invoice_id = P_invoice_id
1062 AND AH.hold_lookup_code = AHC.hold_lookup_code
1063 AND AH.release_lookup_code IS NULL
1064 AND AHC.postable_flag = 'N';
1065 EXCEPTION
1066 WHEN OTHERS THEN
1067 l_holds_count := 0;
1068 END;
1069
1070
1071 IF (l_holds_count = 0) THEN
1072
1073 /*-----------------------------------------------------------------+
1074 | Step 9A. Complete Cancel process if no postable hold |
1075 | 1. Check if any tax holds,if so call etax to |
1076 | release tax holds. |
1077 | 2. Update the invoice header information |
1078 | 3. Release all the holds |
1079 | 4. set return value to TRUE - indicate success |
1080 +-----------------------------------------------------------------*/
1081 l_debug_info := 'Check if invoice has any tax holds';
1082
1083 SELECT count(*)
1084 INTO l_tax_holds_count
1085 FROM ap_holds AH
1086 ,ap_hold_codes AHC
1087 WHERE AH.invoice_id = P_invoice_id
1088 AND AH.hold_lookup_code = AHC.hold_lookup_code
1089 AND AH.release_lookup_code IS NULL
1090 AND AH.hold_lookup_code IN ('TAX AMOUNT RANGE','TAX VARIANCE');
1091
1092 IF (l_tax_holds_count <> 0) THEN
1093
1094 OPEN Tax_Holds_Cur;
1095 FETCH Tax_Holds_Cur bulk collect into l_hold_code_tab;
1096 CLOSE Tax_Holds_Cur;
1097
1098 l_debug_info := 'Call Etax to release tax holds';
1099
1100 l_success:= ap_etax_services_pkg.release_tax_holds(
1101 p_invoice_id => p_invoice_id,
1102 p_calling_mode => 'RELEASE TAX HOLDS',
1103 p_tax_hold_code => l_hold_code_tab,
1104 p_all_error_messages => 'N',
1105 p_error_code => l_error_code,
1106 p_calling_sequence => l_curr_calling_sequence);
1107
1108 IF NOT(l_success) THEN
1109 Raise Tax_Exception;
1110 END IF;
1111
1112 END IF;
1113
1114 /*-----------------------------------------------------------------+
1115 | Step 9A. Complete Cancel process if no postable hold |
1116 | Create single invoice cancelled accounting event |
1117 | This is a code fix combined with the following bugs |
1118 | 3574680, 2993905 while fixing 4748638 |
1119 +-----------------------------------------------------------------*/
1120
1121 -- Start Bug fix 4748638 (4881719)
1122 --Bug#3574680, determine if cancelled distributions exists
1123 SELECT COUNT(invoice_distribution_id)
1124 INTO l_cancel_dist_exists
1125 FROM ap_invoice_distributions
1126 WHERE invoice_id=p_invoice_id
1127 AND cancellation_flag='Y'
1128 AND rownum=1;
1129
1130 IF NVL(l_cancel_dist_exists,0) <> 0 THEN
1131
1132 AP_ACCOUNTING_EVENTS_PKG.Create_Events (
1133 'INVOICE CANCELLATION'
1134 ,NULL -- p_doc_type
1135 ,p_invoice_id
1136 ,p_accounting_date
1137 ,l_Accounting_event_ID
1138 ,NULL -- checkrun_name
1139 ,P_calling_sequence);
1140 END IF;
1141
1142 -- BUG fix 4748638 END
1143
1144
1145 l_debug_info := 'Cancelling the invoice if no postable holds';
1146
1147 UPDATE ap_invoices
1148 SET cancelled_by = P_last_updated_by
1149 ,cancelled_amount = temp_cancelled_amount
1150 ,cancelled_date = sysdate
1151 ,last_updated_by = P_last_updated_by
1152 ,last_update_date = sysdate
1153 WHERE invoice_id = P_invoice_id;
1154
1155 UPDATE ap_holds
1156 SET release_lookup_code = 'APPROVED'
1157 ,release_reason = ( SELECT description
1158 FROM ap_hold_codes
1159 WHERE hold_lookup_code = 'APPROVED')
1160 ,last_update_date = SYSDATE
1161 ,last_updated_by = P_last_updated_by
1162 ,last_update_login = P_last_update_login
1163 WHERE invoice_id = P_invoice_id
1164 AND release_lookup_code IS NULL ;
1165
1166 l_success := TRUE;
1167
1168 --Bug 4539462 DBI logging
1169 AP_DBI_PKG.Maintain_DBI_Summary
1170 (p_table_name => 'AP_INVOICES',
1171 p_operation => 'U',
1172 p_key_value1 => P_Invoice_id,
1173 p_calling_sequence => l_curr_calling_sequence);
1174
1175 AP_DBI_PKG.Maintain_DBI_Summary
1176 (p_table_name => 'AP_HOLDS',
1177 p_operation => 'U',
1178 p_key_value1 => P_Invoice_id,
1179 p_calling_sequence => l_curr_calling_sequence);
1180
1181 COMMIT;
1182
1183 ELSE
1184
1185 /*-----------------------------------------------------------------+
1186 | Step 9B. Special treatment for an invoice with POSTABLE HOLD |
1187 | During Cancellation. |
1188 | 1. populate returned error message |
1189 | 2. set return value to FALSE |
1190 | Invoice Header Level data will not be marked as |
1191 | CANCELLED to allow user to release any hold when they|
1192 | review. We also need to commit data because the |
1193 | postable holds if any will be depending on the |
1194 | reversed data |
1195 +-----------------------------------------------------------------*/
1196
1197 l_debug_info := 'Special treatment for an invoice with POSTABLE HOLDS';
1198
1199 P_message_name := 'AP_INV_CANCEL_POSTING_HOLDS';
1200 l_success := FALSE;
1201
1202 END IF; -- end of check l_hold_count of postable hold
1203
1204 /*-----------------------------------------------------------------+
1205 | Step 10. Commit Data for success cancelled invoice and invoice |
1206 | with postable hold |
1207 +-----------------------------------------------------------------*/
1208
1209 l_debug_info := 'Committing changes to database';
1210
1211 /*----------------------------------------------------------------+
1212 | Step 10.5. Calling API for Payment Request Cancellation |
1213 | Subscribe Event |
1214 +-----------------------------------------------------------------*/
1215
1216 l_debug_info := 'Calling Payment Request Cancellation Subscription API';
1217 -- Payment request Cancellation from Payables
1218 IF p_calling_sequence not in ('ar_refund_pvt.cancel_refund','IGS_FI_PRC_APINT.CANCEL_INVOICE') THEN
1219 /* added 'IGS_FI_PRC_APINT.CANCEL_INVOICE' for bug 5948586 as we need not call
1220 the Subscribe_To_Cancel_Event if ap_cancel_single invoice is called from SF module.
1221 plz see the bug for details. */
1222
1223 OPEN c_reg_products;
1224 LOOP
1225 FETCH c_reg_products INTO l_application_id;
1226 EXIT WHEN c_reg_products%NOTFOUND;
1227
1228 AP_CANCEL_PKG.Subscribe_To_Cancel_Event(
1229 P_Event_Type => 'INVOICE_CANCELLED',
1230 P_Invoice_ID => P_invoice_id,
1231 P_Application_ID => l_application_id,
1232 P_Return_Status => l_return_status,
1233 P_Msg_Count => l_msg_count,
1234 P_Msg_Data => l_msg_data,
1235 P_Calling_Sequence => l_curr_calling_sequence);
1236
1237 IF l_Return_Status <> FND_API.G_RET_STS_SUCCESS THEN
1238 FND_MSG_PUB.Count_And_Get
1239 (p_encoded => FND_API.G_FALSE,
1240 p_count => l_msg_count,
1241 p_data => l_msg_data);
1242 l_debug_info := l_msg_data;
1243 RETURN FALSE;
1244 END IF;
1245
1246 END LOOP;
1247 END IF;
1248
1249 /*-----------------------------------------------------------------+
1250 | Step 11. Populate the Out parameter |
1251 +-----------------------------------------------------------------*/
1252
1253 l_debug_info := 'Populate OUT parameters';
1254
1255 SELECT invoice_amount
1256 ,base_amount
1257 ,temp_cancelled_amount
1258 ,cancelled_by
1259 ,cancelled_amount
1260 ,cancelled_date
1261 ,last_update_date
1262 ,original_prepayment_amount
1263 ,pay_curr_invoice_amount
1264 INTO P_invoice_amount
1265 ,P_base_amount
1266 ,P_temp_cancelled_amount
1267 ,P_cancelled_by
1268 ,P_cancelled_amount
1269 ,P_cancelled_date
1270 ,P_last_update_date
1271 ,P_original_prepayment_amount
1272 ,P_pay_curr_invoice_amount
1273 FROM ap_invoices
1274 WHERE invoice_id = P_invoice_id;
1275
1276 RETURN l_success;
1277
1278 ELSE
1279 l_debug_info := 'Discard line(s) is not successful';
1280 RETURN FALSE;
1281 END IF; -- end of check l_discard_line_ok flag
1282
1283 EXCEPTION
1284 WHEN TAX_EXCEPTION THEN
1285 IF ( Invoice_Lines_Cur%ISOPEN ) THEN
1286 CLOSE Invoice_Lines_Cur;
1287 END IF;
1288 IF (Tax_Holds_Cur%ISOPEN) THEN
1289 CLOSE Tax_Holds_Cur;
1290 END IF;
1291 APP_EXCEPTION.RAISE_EXCEPTION;
1292 RETURN FALSE;
1293 WHEN OTHERS THEN
1294 IF (SQLCODE <> -20001) THEN
1295 FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1296 FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1297 FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
1298 FND_MESSAGE.SET_TOKEN('PARAMETERS',
1299 ' P_invoice_id = ' || P_invoice_id
1300 ||' P_last_updated_by = ' || P_last_updated_by
1301 ||' P_last_update_login = ' || P_last_update_login
1302 ||' P_accounting_date = ' || P_accounting_date);
1303 FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
1304 END IF;
1305
1306 IF ( Invoice_Lines_Cur%ISOPEN ) THEN
1307 CLOSE Invoice_Lines_Cur;
1308 END IF;
1309 IF (Tax_Holds_Cur%ISOPEN) THEN
1310 CLOSE Tax_Holds_Cur;
1311 END IF;
1312 APP_EXCEPTION.RAISE_EXCEPTION;
1313 RETURN FALSE;
1314
1315 END Ap_Cancel_Single_Invoice;
1316
1317 /*=============================================================================
1318 | PROCEDURE Ap_Cancel_Invoices
1319 |
1320 | Cancels all invoices associated with the payment given by P_check_id
1321 |
1322 | PROGRAM FLOW
1323 |
1324 | Invoices that are not eligible for cancellation:
1325 | 1. invoices associated with an effective payment,
1326 | 2. invoices that are selected for payment,
1327 | 3. invoices that are already cancelled
1328 | 4. invoices (prepayments) that have been used by other invoices
1329 | 5. invoices that are matched to Finally Closed PO's)
1330 | 6. invoices which were paid originally by check but whose payment
1331 | was removed prior to the voiding of the check i.e. through an
1332 | invoice adjustment are left unaffected.
1333 |
1334 | NOTES
1335 | 1. AutoApproval is run for each invoice. If the invoice has posting
1336 | holds, it is zeroed out by reversing all invoice distributions and
1337 | PO matching, but the invoice is not cancelled.
1338 |
1339 | MODIFICATION HISTORY
1340 | Date Author Description of Change
1341 |
1342 *============================================================================*/
1343
1344 PROCEDURE Ap_Cancel_Invoices(
1345 P_check_id IN NUMBER,
1346 P_last_updated_by IN NUMBER,
1347 P_last_update_login IN NUMBER,
1348 P_accounting_date IN DATE,
1349 P_num_cancelled OUT NOCOPY NUMBER,
1350 P_num_not_cancelled OUT NOCOPY NUMBER,
1351 P_calling_sequence IN VARCHAR2)
1352 IS
1353 l_num_cancelled NUMBER := 0;
1354 l_num_not_cancelled NUMBER := 0;
1355 l_success BOOLEAN;
1356 l_message_name VARCHAR2(30);
1357 l_invoice_amount NUMBER;
1358 -- bug 6883407
1359 l_invoice_gl_date DATE;
1360
1361 l_base_amount NUMBER;
1362 l_temp_cancelled_amount NUMBER;
1363 l_cancelled_by NUMBER;
1364 l_cancelled_amount NUMBER;
1365 l_pay_curr_invoice_amount NUMBER;
1366 l_cancelled_date DATE;
1367 l_last_update_date DATE;
1368 l_debug_info VARCHAR2(240);
1369 l_original_prepayment_amount NUMBER;
1370 l_curr_calling_sequence VARCHAR2(2000);
1371 l_token VARCHAR2(4000);
1372
1373 /*-----------------------------------------------------------------+
1374 | Declare cursor to select all invoices associated with the |
1375 | payment given by P_check_id and ensuring that the invoice was |
1376 | effectively being paid by the check i.e. the invoice payment |
1377 | wasn't already reversed. |
1378 +-----------------------------------------------------------------*/
1379
1380 --bug 5182311 Modified the cursor to ignore already cancelled invoices
1381 -- Bug 8257752. Commented out the reversal_flag condition.
1382
1383 CURSOR invoices_cursor IS
1384 SELECT DISTINCT aip.invoice_id
1385 FROM ap_invoice_payments aip,ap_invoices ai
1386 WHERE aip.check_id = P_check_id
1387 --AND nvl(aip.reversal_flag, 'N') <> 'Y'
1388 AND ai.invoice_id=aip.invoice_id
1389 AND ai.cancelled_date is null;
1390
1391 TYPE inv_ib_tab_Type IS TABLE OF ap_invoices.invoice_id%TYPE;
1392
1393 l_invoice_id_list inv_ib_tab_Type;
1394 i BINARY_INTEGER :=1;
1395
1396 BEGIN
1397 l_curr_calling_sequence := 'AP_CANCEL_PKG.AP_CANCEL_INVOICES<-' ||
1398 P_calling_sequence;
1399
1400 l_debug_info := 'Open invoices_cursor and do bulk fetch';
1401
1402 OPEN invoices_cursor;
1403 FETCH invoices_cursor
1404 BULK COLLECT INTO l_invoice_id_list;
1405 CLOSE invoices_cursor;
1406
1407 FOR i IN l_invoice_id_list.FIRST..l_invoice_id_list.LAST
1408 LOOP
1409
1410 -- bug 6883407
1411 l_debug_info := 'Fetch Invoice GL Date.';
1412 SELECT ai.gl_date
1413 INTO l_invoice_gl_date
1414 FROM ap_invoices ai
1415 WHERE ai.invoice_id = l_invoice_id_list(i);
1416
1417
1418 l_success := AP_Cancel_Single_Invoice(
1419 l_invoice_id_list(i),
1420 P_last_updated_by,
1421 P_last_update_login,
1422 l_invoice_gl_date, --P_accounting_date,-- bug 6883407
1423 l_message_name,
1424 l_invoice_amount,
1425 l_base_amount,
1426 l_temp_cancelled_amount,
1427 l_cancelled_by,
1428 l_cancelled_amount,
1429 l_cancelled_date,
1430 l_last_update_date,
1431 l_original_prepayment_amount,
1432 l_pay_curr_invoice_amount,
1433 l_token,
1434 l_curr_calling_sequence);
1435
1436 IF (l_success) THEN
1437 l_num_cancelled := l_num_cancelled + 1;
1438 ELSE
1439 l_num_not_cancelled := l_num_not_cancelled + 1;
1440 END IF;
1441
1442 END LOOP;
1443
1444 l_invoice_id_list.DELETE;
1445
1446 P_num_cancelled := l_num_cancelled;
1447 P_num_not_cancelled := l_num_not_cancelled;
1448
1449 EXCEPTION
1450 WHEN OTHERS THEN
1451 IF (SQLCODE <> -20001) THEN
1452 FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1453 FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1454 FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',l_curr_calling_sequence);
1455 FND_MESSAGE.SET_TOKEN('PARAMETERS',
1456 ' P_check_id = ' || P_check_id
1457 ||' P_last_updated_by = ' || P_last_updated_by
1458 ||' P_last_update_login = ' || P_last_update_login
1459 ||' P_accounting_date = ' || P_accounting_date);
1460 FND_MESSAGE.SET_TOKEN('DEBUG_INFO',l_debug_info);
1461 END IF;
1462
1463 IF ( invoices_cursor%ISOPEN ) THEN
1464 CLOSE invoices_cursor;
1465 END IF;
1466 APP_EXCEPTION.RAISE_EXCEPTION;
1467
1468 END Ap_Cancel_Invoices;
1469
1470 -- Added for Payment Request Cancellation from Payables.
1471 -- Procedure to subscribe to the invoice cancellation event by other products
1472 -- This procedure checks the product registry table for all the product that have
1473 -- subscribed to cancellation event and calls the product API.
1474 ---------------------------------------------------------------------------------
1475 PROCEDURE Subscribe_To_Cancel_Event
1476 (P_Event_Type IN VARCHAR2,
1477 P_Invoice_ID IN NUMBER,
1478 P_Application_ID IN NUMBER,
1479 P_Return_Status OUT NOCOPY VARCHAR2,
1480 P_Msg_Count OUT NOCOPY NUMBER,
1481 P_Msg_Data OUT NOCOPY VARCHAR2,
1482 P_Calling_Sequence IN VARCHAR2) IS
1483
1484
1485 current_calling_sequence VARCHAR2(2000);
1486 debug_info VARCHAR2(100);
1487
1488 l_stmt VARCHAR2(1000);
1489 l_return_status VARCHAR2(1);
1490 l_msg_count NUMBER;
1491 l_msg_data VARCHAR2(2000);
1492
1493
1494 CURSOR c_products_registered IS
1495 SELECT Reg_Application_ID,
1496 Registration_API
1497 FROM AP_Product_Registrations
1498 WHERE Reg_Application_ID = P_Application_ID
1499 AND Registration_Event_Type = P_Event_Type;
1500
1501 BEGIN
1502
1503 -- Update the calling sequence
1504 --
1505 current_calling_sequence := 'AP_Cancel_PKG.Subscribe_To_Cancel_Event<-' ||
1506 P_calling_sequence;
1507
1508 debug_info := 'Calling the subscribe payment event API';
1509
1510 FOR c_product_rec IN c_products_registered
1511 LOOP
1512
1513 l_stmt := 'Begin ' ||
1514 c_product_rec.Registration_API ||
1515 '(:P_Event_Type,' ||
1516 ':P_Invoice_ID,' ||
1517 ':l_return_Status,' ||
1518 ':l_msg_count,' ||
1519 ':l_msg_data);' ||
1520 'End;';
1521
1522 EXECUTE IMMEDIATE l_stmt
1523 USING IN P_Event_Type,
1524 IN P_Invoice_ID,
1525 OUT l_return_status,
1526 OUT l_msg_count,
1527 OUT l_msg_data;
1528
1529 P_Return_Status := l_return_status;
1530 P_Msg_Count := l_msg_count;
1531 P_Msg_Data := l_msg_data;
1532
1533
1534 END LOOP;
1535
1536 EXCEPTION
1537
1538 WHEN OTHERS THEN
1539 IF (SQLCODE <> -20001) THEN
1540 FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
1541 FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
1542 FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',current_calling_sequence);
1543 FND_MESSAGE.SET_TOKEN('PARAMETERS','Invoice_id = ' || to_char(P_Invoice_ID));
1544 FND_MESSAGE.SET_TOKEN('DEBUG_INFO',debug_info);
1545 END IF;
1546 APP_EXCEPTION.RAISE_EXCEPTION;
1547
1548 END Subscribe_To_Cancel_Event;
1549
1550 END AP_CANCEL_PKG;