DBA Data[Home] [Help]

PACKAGE BODY: APPS.AP_PAYMENT_SCHEDULES_PKG

Source


1 PACKAGE BODY AP_PAYMENT_SCHEDULES_PKG AS
2 /* $Header: apipascb.pls 120.7.12010000.3 2009/01/28 14:06:11 amitmukh ship $ */
3 
4   -----------------------------------------------------------------------
5   -- PROCEDURE adjust_pay_schedule adjusts the payment schedule of
6   -- a paid or partially paid invoice
7   --
8   -- PRECONDITION: Called from the invoice block in PRE-UPDATE via
9   --               stored procedure call ap_invoices_pkg.invoice_pre_update()
10   -----------------------------------------------------------------------
11   PROCEDURE adjust_pay_schedule (X_invoice_id          IN number,
12                                  X_invoice_amount      IN number,
13                                  X_payment_status_flag IN OUT NOCOPY varchar2,
14                                  X_invoice_type_lookup_code IN varchar2,
15                                  X_last_updated_by     IN number,
16                                  X_message1            IN OUT NOCOPY varchar2,
17                                  X_message2            IN OUT NOCOPY varchar2,
18                                  X_reset_match_status  IN OUT NOCOPY varchar2,
19                                  X_liability_adjusted_flag IN OUT NOCOPY varchar2,
20                                  X_calling_sequence    IN varchar2,
21 				 X_calling_mode        IN varchar2,
22                                  X_revalidate_ps       IN OUT NOCOPY varchar2)
23   IS
24     current_calling_sequence VARCHAR2(2000);
25     debug_info               VARCHAR2(100);
26     l_current_payment_num  number;
27     l_current_amount_to_adjust number;
28     l_original_invoice_amount number;
29     l_net_amount_to_adjust   number;
30     l_payment_num_to_add     number;
31     l_amount_remaining     number;
32     l_payment_status_flag     ap_payment_schedules.payment_status_flag%TYPE;
33     l_allow_paid_invoice_adjust
34                         ap_system_parameters.allow_paid_invoice_adjust%TYPE;
35     l_add_new_payment_schedule varchar2(1) := 'Y';
36     l_sum_ps_amount_remaining	number;
37     l_payment_currency_code   ap_invoices.payment_currency_code%TYPE;
38     l_invoice_currency_code   ap_invoices.invoice_currency_code%TYPE;
39     l_payment_cross_rate      ap_invoices.payment_cross_rate%TYPE;
40     l_pay_curr_invoice_amount ap_invoices.pay_curr_invoice_amount%TYPE;
41     l_pay_curr_orig_inv_amt   ap_invoices.pay_curr_invoice_amount%TYPE;
42     l_pay_curr_net_amt_to_adj number;
43     l_inv_curr_sched_total    number;
44 
45     cursor message1_cursor is
46         SELECT 'AP_PAY_WARN_DISC_UPDATE'
47         FROM   ap_payment_schedules
48         WHERE  invoice_id = X_invoice_id
49         AND    payment_num = l_current_payment_num
50         AND    (NVL(discount_amount_available, 0) <> 0
51                 OR NVL(second_disc_amt_available, 0) <> 0
52                 OR NVL(third_disc_amt_available, 0) <> 0);
53 
54     cursor invoice_cursor is
55         select AI.invoice_amount,
56                SP.allow_paid_invoice_adjust,
57                AI.invoice_currency_code,
58                AI.payment_currency_code,
59                AI.payment_cross_rate,
60                nvl(AI.pay_curr_invoice_amount, AI.invoice_amount)
61         from   ap_invoices AI,
62                ap_system_parameters SP
63         where  invoice_id = X_invoice_id;
64 
65     -- If we're adding a new payment schedule and not adjusting
66     -- an existing one, then the payment_status_flag of the
67     -- payment schedule we're copying from is irrelevant.
68     --
69     -- NOTE: The reason l_add_new_payment_schedule is declared as a
70     -- 	     varchar2 and not a boolean is that a boolean can not
71     --       be evaluated in a cursor select statement.
72     --
73     cursor pay_sched_adjust_cursor is
74         SELECT payment_num,
75 	       amount_remaining,
76 	       payment_status_flag
77         FROM   ap_payment_schedules
78         WHERE  invoice_id = X_invoice_id
79         AND    (l_add_new_payment_schedule='Y' OR
80 		payment_status_flag <> 'Y')
81 	ORDER BY due_date desc, payment_num desc;
82 
83     cursor payment_num_to_add_cursor is
84         SELECT nvl((MAX(payment_num)+1),1)
85         FROM   ap_payment_schedules
86         WHERE  invoice_id = X_invoice_id;
87 
88     cursor c_inv_curr_sched_total IS
89         SELECT SUM(nvl(inv_curr_gross_amount, gross_amount))
90         FROM   ap_payment_schedules
91         WHERE  invoice_id = X_Invoice_Id;
92 
93   BEGIN
94     current_calling_sequence :=
95 		'AP_PAYMENT_SCHEDULES_PKG.ADJUST_PAY_SCHEDULE<-' ||
96 				X_calling_sequence;
97 
98     -- Determine the original invoice_amount
99     -- The precondition of this procedure is that it is being called
100     -- in PRE-UPDATE mode; thus the new amount has not been saved
101     -- to the database.
102 
103     debug_info := 'Determining proper payment schedule to adjust';
104 
105     open invoice_cursor;
106     debug_info := 'Fetch cursor invoice_cursor';
107     fetch invoice_cursor into l_original_invoice_amount,
108                               l_allow_paid_invoice_adjust,
109                               l_invoice_currency_code,
110                               l_payment_currency_code,
111                               l_payment_cross_rate,
112                               l_pay_curr_orig_inv_amt;
113     debug_info := 'Close cursor invoice_cursor';
114     close invoice_cursor;
115 
116     l_pay_curr_invoice_amount := ap_utilities_pkg.ap_round_currency(
117                                  X_invoice_amount * l_payment_cross_rate,
118                                  l_payment_currency_code);
119     l_net_amount_to_adjust := X_invoice_amount - l_original_invoice_amount;
120     l_pay_curr_net_amt_to_adj := l_pay_curr_invoice_amount -
121                                     l_pay_curr_orig_inv_amt;
122 
123     if (l_net_amount_to_adjust = 0) then
124       -- No need to alter payment schedules if we're not
125       -- adjusting the liability
126       --
127       X_liability_adjusted_flag := 'N';
128       return;
129     else
130       -- Make note of the fact that a liability adjustment will
131       -- be made.  In the Invoice Workbench, we will requery the
132       -- payment schedules block if the liability_adjusted_flag = 'Y'.
133       --
134       X_liability_adjusted_flag := 'Y';
135     end if;
136 
137     -- Although the Invoice Workbench enforces rules which prevent
138     -- updates to the invoice (liability) amount in certain cases,
139     -- we want to ensure that these rules are enforced server-side
140     -- as well.
141 
142     if (ap_invoices_pkg.get_encumbered_flag(X_invoice_id) = 'Y') then
143       -- Cannot change the invoice_amount as it is encumbered
144       fnd_message.set_name('SQLAP','AP_INV_ALL_DISTS_ENCUMB');
145       app_exception.raise_exception;
146     elsif (ap_invoices_pkg.get_posting_status(X_invoice_id) = 'Y') then
147       -- Cannot change the invoice_amount as it is posted
148       fnd_message.set_name('SQLAP','AP_INV_ALL_DIST_POSTED');
149       app_exception.raise_exception;
150     elsif (ap_invoices_pkg.selected_for_payment_flag(
151                         X_invoice_id) = 'Y') then
152           -- Cannot change the amount as it is selected for payment
153       fnd_message.set_name('SQLAP','AP_INV_SELECTED_INVOICE');
154       app_exception.raise_exception;
155     elsif (l_allow_paid_invoice_adjust  <> 'Y'
156 	   and nvl(x_calling_mode, 'X') <> 'APXIIMPT') then
157       fnd_message.set_name('SQLAP','AP_DIST_NO_UPDATE_PAID');
158       app_exception.raise_exception;
159     end if;
160 
161     -- Look at the sign of the adjustment and determine whether
162     -- an existing payment should be adjusted or a payment schedule
163     -- should be added.
164     --
165     if (X_payment_status_flag <> 'N' and
166         ((X_invoice_type_lookup_code in ('CREDIT','DEBIT') and
167            l_net_amount_to_adjust <= 0) or
168          (X_invoice_type_lookup_code not in ('CREDIT','DEBIT') and
169            l_net_amount_to_adjust >= 0))) then
170       --
171       -- Invoice is either paid or partially paid and the
172       -- the amount of the adjustment is greater than the
173       -- scheduled payment is absolute terms.  In this case,
174       -- we can add a payment schedule
175       --
176       l_add_new_payment_schedule := 'Y';
177     else
178       --
179       -- We will be adjusting a payment schedule in this case
180       --
181       l_add_new_payment_schedule := 'N';
182     end if;
183 
184     --
185     -- New for 10SC
186     --
187     -- Instead of restricting liability adjustment to a single
188     -- payment schedule, we will iteratively apply adjustment to all unpaid
189     -- and partially paid payment schedules in descending order
190     -- of due date until the adjustment is fully applied.
191     --
192     -- We will delete any unpaid payment schedules where an adjustment
193     -- will cause the gross amount to be reduced to zero.
194     --
195     -- If an adjustment to existing payment schedule is not planned,
196     -- ie, we will be adding a new one, then the first fetch from
197     -- pay_sched_adjust_cursor will yield the payment_num of the
198     -- payment schedule that we wish to base our new record on.
199     --
200     debug_info := 'Open pay_sched_adjust_cursor';
201     open pay_sched_adjust_cursor;
202 
203     loop
204 
205       debug_info := 'Fetch pay_sched_adjust_cursor';
206       fetch pay_sched_adjust_cursor into l_current_payment_num,
207 					 l_amount_remaining,
208 					 l_payment_status_flag;
209 
210       -- Leave the cursor if we intend to create a new payment schedule
211       -- or if we've run out NOCOPY of payment schedules to process.
212       --
213       exit when (l_add_new_payment_schedule='Y' or
214                  pay_sched_adjust_cursor%NOTFOUND);
215 
216       -- For the current payment schedule, reduce the gross_amount
217       -- by the adjustment amount or its amount_remaining,
218       -- whichever is less.
219       --
220       if (ABS(l_amount_remaining) - ABS(l_pay_curr_net_amt_to_adj) >= 0) then
221         l_current_amount_to_adjust := l_pay_curr_net_amt_to_adj;
222       else
223         l_current_amount_to_adjust := (0 - l_amount_remaining);
224       end if;
225 
226       -- If the adjustment is being made for the entire gross amount
227       -- of the payment schedule and the payment schedule is unpaid,
228       -- then delete the record, otherwise update it.
229       --
230       if ((l_amount_remaining + l_current_amount_to_adjust = 0) and
231 	  l_payment_status_flag not in ('Y','P')) then
232 
233         debug_info := 'Delete AP_PAYMENT_SCHEDULES payment_num '||
234                       l_current_payment_num;
235 
236         delete from ap_payment_schedules
237         where  invoice_id = X_invoice_id
238         and    payment_num = l_current_payment_num;
239 
240       else
241         --
242         -- Update the payment schedule.
243         --
244         -- NOTE: This is non-standard to have an update to another table
245         -- called from the pre_update trigger.  We anticipate no problems
246         -- in this case because the table ap_invoices was marked already
247         -- when the commit was invoked.  (See the update_liability trigger.)
248         -- Usual locking order is invoices then pay lines,
249         -- so this is consistent.
250         --
251         debug_info := 'Update AP_PAYMENT_SCHEDULES payment_num '||
252                       l_current_payment_num;
253 
254         UPDATE ap_payment_schedules
255         SET    gross_amount = NVL(gross_amount, 0)+l_current_amount_to_adjust,
256                inv_curr_gross_amount = (
257                    SELECT   DECODE(F.minimum_accountable_unit,NULL,
258     	                       ROUND( ((NVL(gross_amount, 0)+
259                                        l_current_amount_to_adjust)/
260                                        l_payment_cross_rate)
261                                       , F.precision),
262                                ROUND( ((NVL(gross_amount, 0)+
263                                        l_current_amount_to_adjust)/
264                                        l_payment_cross_rate)
265                                       / F.minimum_accountable_unit)
266 	                              * F.minimum_accountable_unit)
267                    FROM   fnd_currencies_vl F
268                    WHERE  F.currency_code = l_invoice_currency_code),
269                amount_remaining = NVL(amount_remaining, 0)
270                                 + l_current_amount_to_adjust,
271                payment_status_flag =
272                 DECODE(NVL(amount_remaining, 0) +
273                        l_current_amount_to_adjust,
274                            NVL(gross_amount, 0) +
275                            l_current_amount_to_adjust, 'N',
276                        0, DECODE(X_invoice_amount,
277                                 0,'N',
278                                   'Y'),
279                           'P')
280         WHERE  invoice_id = X_invoice_id
281         AND    payment_num = l_current_payment_num;
282 
283 
284         -- If message name is returned in to X_Message1 then
285         -- we know that the payment schedule line has a non-zero
286         -- discount which may need adjustment
287         -- Message to display is AP_PAY_WARN_DISC_UPDATE
288         --
289         if (X_Message1 is null) then
290           debug_info := 'Select from AP_PAYMENT_SCHEDULES';
291 
292           open message1_cursor;
293           debug_info := 'Fetch message1_cursor';
294           fetch message1_cursor into X_Message1;
295           debug_info := 'Close message1_cursor';
296           close message1_cursor;
297         end if;
298       end if;
299 
300       -- Reduce the Net Adjustment amount by the amount we're
301       -- applying in this adjustment.
302       --
303       l_pay_curr_net_amt_to_adj := l_pay_curr_net_amt_to_adj -
304 				    l_current_amount_to_adjust;
305 
306       -- If the adjustment has been fully applied then exit the loop
307       exit when (l_pay_curr_net_amt_to_adj = 0);
308 
309     end loop;
310 
311     debug_info := 'Close pay_sched_adjust_cursor';
312     close pay_sched_adjust_cursor;
313 
314     -- If the previous cursor retrieved no payment schedules,
315     -- fail the procedure and tell the user.
316     --
317     if (l_current_payment_num is null) then
318       -- Cannot find a payment schedule to adjust
319       FND_MESSAGE.Set_Name('SQLAP', 'AP_INV_NO_PAYMENT_SCHEDULE');
320       FND_MESSAGE.Set_Name('SQLAP', 'AP_PAY_NO_PAYMENT_SCHEDULE');
321       APP_EXCEPTION.Raise_Exception;
322     end if;
323 
324     -- Adjust for any rounding errors that might have been introduced
325     -- for inv_curr_gross_amount
326 
327     if (l_add_new_payment_schedule = 'N') then
328       debug_info := 'Open cursor c_inv_curr_sched_total';
329       OPEN  c_inv_curr_sched_total;
330       debug_info := 'Fetch cursor c_inv_curr_sched_total';
331       FETCH c_inv_curr_sched_total INTO l_inv_curr_sched_total;
332       debug_info := 'Close cursor c_inv_curr_sched_total';
333       CLOSE c_inv_curr_sched_total;
334 
335       -- Adjust inv_curr_gross_amount for rounding errors
336                                                                          --
337       IF (l_inv_curr_sched_total <> X_invoice_amount) THEN
338                                                                          --
339         debug_info:= 'Update ap_payment_schedules - set inv_curr_gross_amount';
340         UPDATE AP_PAYMENT_SCHEDULES
341         SET inv_curr_gross_amount = inv_curr_gross_amount
342                                     + X_Invoice_Amount
343                                     - l_inv_curr_sched_total
344         WHERE invoice_id = X_Invoice_Id
345         AND payment_num = (SELECT MAX(payment_num)
346                            FROM   ap_payment_schedules
347                            WHERE  invoice_id = X_Invoice_Id);
348                                                                          --
349       END IF;
350     end if;
351                                                                          --
352     -- Add the new payment schedule
353     --
357       debug_info := 'Open payment_num_to_add_cursor';
354     if (l_add_new_payment_schedule = 'Y') then
355 
356       -- Determine payment num of new payment schedule
358       open payment_num_to_add_cursor;
359       debug_info := 'Fetch payment_num_to_add_cursor';
360       fetch payment_num_to_add_cursor into l_payment_num_to_add;
361       debug_info := 'Close payment_num_to_add_cursor';
362       close payment_num_to_add_cursor;
363 
364       debug_info := 'Insert into AP_PAYMENT_SCHEDULES';
365 
366       -- Insert the new payment schedule
367       INSERT INTO ap_payment_schedules(
368       invoice_id, payment_num, due_date,
369       last_update_date, last_updated_by,
370       last_update_login, creation_date, created_by,
371       payment_cross_rate,
372       gross_amount,inv_curr_gross_amount,amount_remaining,
373       payment_priority, hold_flag,
374       payment_status_flag, batch_id, payment_method_code,
375       external_bank_account_id,
376       org_id, --MOAC project
377       remittance_message1,
378       remittance_message2,
379       remittance_message3,
380       --third party payments
381       remit_to_supplier_name,
382       remit_to_supplier_id,
383       remit_to_supplier_site,
384       remit_to_supplier_site_id,
385       relationship_id
386       )
387       SELECT X_invoice_id, l_payment_num_to_add, P.due_date,
388              SYSDATE, X_last_updated_by,
389              null, SYSDATE, X_last_updated_by,
390              P.payment_cross_rate,
391              l_pay_curr_net_amt_to_adj,
392              l_net_amount_to_adjust,
393              l_pay_curr_net_amt_to_adj,
394              P.payment_priority, P.hold_flag, 'N', P.batch_id,
395              P.payment_method_code,
396              P.external_bank_account_id,
397              P.org_id, --MOAC project
398              p.remittance_message1,
399              p.remittance_message2,
400              p.remittance_message3,
401 	     --third party payments
402 	     p.remit_to_supplier_name,
403 	     p.remit_to_supplier_id,
404 	     p.remit_to_supplier_site,
405 	     p.remit_to_supplier_site_id,
406 	     p.relationship_id
407       FROM   ap_payment_schedules P
408       WHERE  P.invoice_id           = X_invoice_id
409       AND    P.payment_num          = l_current_payment_num;
410 
411       x_revalidate_ps := 'Y';
412 
413 
414 
415       -- If encumbrance is on, then this invoice will already have dist
416       -- lines that need reapproval, so we can skip this.  Plus, we don't
417       -- want to flip any 'A' flags to 'N' if encumbrance is on.
418       X_reset_match_status := 'Y';
419 
420     else
421       --
422       -- Existing payment schedules were adjusted.  Inform user.
423       --
424       X_Message2 := 'AP_PAY_WARN_SCHED_UPDATE';
425     end if;
426 
427     --
428     -- Check if we need to change the payment_status_flag
429     --
430      SELECT sum(amount_remaining)
431        INTO l_sum_ps_amount_remaining
432        FROM ap_payment_schedules
433       WHERE invoice_id = X_invoice_id;
434 
435     if (l_sum_ps_amount_remaining <> 0) then
436   	X_payment_status_flag := 'P';
437     else
438         X_payment_status_flag := 'Y';
439     end if;
440 
441 
442      EXCEPTION
443        WHEN OTHERS THEN
444          IF (SQLCODE <> -20001) THEN
445            FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
446            FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
447            FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',
448                      current_calling_sequence);
449            FND_MESSAGE.SET_TOKEN('PARAMETERS',
450                'X_invoice_id = '        ||X_invoice_id
451            ||', X_invoice_amount = '    ||X_invoice_amount
452            ||', X_payment_status_flag= '||X_payment_status_flag
453            ||', X_invoice_type_lookup_code = '||X_invoice_type_lookup_code
454            ||', X_last_updated_by = '   ||X_last_updated_by
455            ||', X_message1 = '          ||X_message1
456            ||', X_message2 = '          ||X_message2
457            ||', X_reset_match_status = '||X_reset_match_status
458            ||', X_liability_adjusted_flag = '||X_liability_adjusted_flag
459                                     );
460            FND_MESSAGE.SET_TOKEN('DEBUG_INFO',debug_info);
461          END IF;
462        APP_EXCEPTION.RAISE_EXCEPTION;
463 
464   END adjust_pay_schedule;
465 
466   -----------------------------------------------------------------------
467   -- FUNCTION get_amt_withheld_per_sched, returns prorated withheld
468   -- per payment schedule of an invoice.
469   -- Function added for bug 3484292
470   -----------------------------------------------------------------------
471 
472   FUNCTION get_amt_withheld_per_sched(X_invoice_id           IN NUMBER,
473                                       X_gross_amount         IN NUMBER,
474                                       X_currency_code        IN VARCHAR2)
475   RETURN NUMBER
476   IS
477   l_wt_amt_to_subtract number :=0;
478   BEGIN
479         select  nvl(ap_utilities_pkg.ap_round_currency(
480                 ap_invoices_pkg.get_amount_withheld(ai.invoice_id)*
481        		ai.payment_cross_rate,X_currency_code),0)*
482                 X_gross_amount/decode(ai.pay_curr_invoice_amount, 0, 1,
483 				      nvl(ai.pay_curr_invoice_amount, 1))
487   return l_wt_amt_to_subtract;
484 	into    l_wt_amt_to_subtract
485         from    ap_invoices ai
486         where   ai.invoice_id=X_invoice_id;
488   END get_amt_withheld_per_sched;
489 
490   -----------------------------------------------------------------------
491   -- FUNCTION get_discount_available computes the discount available
492   -- based on X_check_date
493   -----------------------------------------------------------------------
494   FUNCTION get_discount_available(X_invoice_id	       IN NUMBER,
495 				  X_payment_num	       IN NUMBER,
496 				  X_check_date	       IN DATE,
497 				  X_currency_code      IN VARCHAR2)
498     RETURN NUMBER
499   IS
500     l_discount_available	NUMBER;
501     l_wt_amt_to_subtract        NUMBER := 0; --Bug 3484292
502     l_gross_amount              NUMBER;      -- BUG 3741934
503   BEGIN
504 
505     -- bug 3484292 Added the select stmt below.
506     select  nvl(ap_utilities_pkg.ap_round_currency(
507      ap_invoices_pkg.get_amount_withheld(ai.invoice_id)*
508        ai.payment_cross_rate,X_currency_code),0)*
509                  aps.gross_amount/decode(ai.pay_curr_invoice_amount, 0, 1,
510 					 nvl(ai.pay_curr_invoice_amount, 1)),
511          aps.gross_amount                                -- BUG 3741934
512     into l_wt_amt_to_subtract, l_gross_amount
513     from ap_invoices ai,ap_payment_schedules aps
514     where ai.invoice_id=aps.invoice_id
515     and   aps.payment_num=X_payment_num
516     and    ai.invoice_id=X_invoice_id;
517 
518 /*
519      BUG 3741934: Branch around the SQL that calculates the discount if the
520                   Gross Amount of the payment schedule is equal to the withheld
521                   amount.
522 */
523 
524    IF l_wt_amt_to_subtract <> l_gross_amount
525    THEN
526     SELECT NVL(ap_utilities_pkg.ap_round_currency(
527 	     DECODE(gross_amount, 0, 0,
528 	       DECODE(air.always_take_disc_flag, 'Y', discount_amount_available,  --Bug7717053, added the table alias
529 		 GREATEST(
530                   DECODE(SIGN(X_check_date -
531 	                 NVL(discount_date, sysdate-9000)),
532 			    1, 0, NVL(ABS(discount_amount_available), 0)),
533 	          DECODE(SIGN(X_check_date -
534 		         NVL(second_discount_date, sysdate-9000)),
535 		            1, 0, NVL(ABS(second_disc_amt_available), 0)),
536 	          DECODE(SIGN(X_check_date -
537 		         NVL(third_discount_date, sysdate-9000)),
538 		            1, 0, NVL(ABS(third_disc_amt_available),0))) * DECODE(SIGN(gross_amount),-1,-1,1) )
539 	       * (amount_remaining/DECODE(gross_amount, 0, 1, gross_amount-decode(asp.create_awt_dists_type,
540                                      'APPROVAL',
541                                      l_wt_amt_to_subtract,
542                                      0)))),
543                  X_currency_code),0)                              --Bug7717053, added the decode
544     INTO   l_discount_available
545     FROM   ap_invoices_ready_to_pay_v air, ap_system_parameters asp
546     WHERE  invoice_id = X_invoice_id
547     AND    payment_num = X_payment_num;
548    ELSE l_discount_available := 0;
549    END IF;
550 
551     RETURN l_discount_available;
552 
553   END get_discount_available;
554 
555   -----------------------------------------------------------------------
556   -- FUNCTION get_discount_date computes the discount date based on
557   -- X_check_date
558   -----------------------------------------------------------------------
559   FUNCTION get_discount_date(X_invoice_id	IN NUMBER,
560 			     X_payment_num	IN NUMBER,
561 			     X_check_date	IN DATE)
562     RETURN DATE
563   IS
564     l_discount_date		DATE;
565   BEGIN
566 
567     SELECT DECODE(always_take_disc_flag, 'Y', due_date,
568 	     DECODE(SIGN(X_check_date - NVL(discount_date,sysdate-9000)-1),
569 	            -1, discount_date,
570 	       DECODE(SIGN(X_check_date - NVL(second_discount_date,sysdate-9000)-1),
571 	              -1, second_discount_date,
572 	         DECODE(SIGN(X_check_date - NVL(third_discount_date,sysdate-9000)-1),
573 			-1, third_discount_date, due_date))))
574     INTO   l_discount_date
575     FROM   ap_invoices_ready_to_pay_v
576     WHERE  invoice_id = X_invoice_id
577     AND    payment_num = X_payment_num;
578 
579     RETURN l_discount_date;
580 
581   END get_discount_date;
582 PROCEDURE Lock_Row(	X_Invoice_Id                               NUMBER,
583 			X_Last_Updated_By                          NUMBER,
584 			X_Last_Update_Date                         DATE,
585 			X_Payment_Cross_Rate                       NUMBER,
586 			X_Payment_Num                              NUMBER,
587 			X_Amount_Remaining                         NUMBER,
588 			X_Created_By                               NUMBER,
589 			X_Creation_Date                            DATE,
590 			X_Discount_Date                            DATE,
591 			X_Due_Date                                 DATE,
592 			X_Future_Pay_Due_Date                      DATE,
593 			X_Gross_Amount                             NUMBER,
594 			X_Hold_Flag                                VARCHAR2,
595 			X_Last_Update_Login                        NUMBER,
596 			X_Payment_Method_Lookup_Code               VARCHAR2 default null,
597                         X_payment_method_code                      varchar2,
598 			X_Payment_Priority                         NUMBER,
599 			X_Payment_Status_Flag                      VARCHAR2,
600 			X_Second_Discount_Date                     DATE,
604 			X_Second_Disc_Amt_Available                NUMBER,
601 			X_Third_Discount_Date                      DATE,
602 			X_Batch_Id                                 NUMBER,
603 			X_Discount_Amount_Available                NUMBER,
605 			X_Third_Disc_Amt_Available                 NUMBER,
606 			X_Attribute1                               VARCHAR2,
607 			X_Attribute10                              VARCHAR2,
608 			X_Attribute11                              VARCHAR2,
609 			X_Attribute12                              VARCHAR2,
610 			X_Attribute13                              VARCHAR2,
611 			X_Attribute14                              VARCHAR2,
612 			X_Attribute15                              VARCHAR2,
613 			X_Attribute2                               VARCHAR2,
614 			X_Attribute3                               VARCHAR2,
615 			X_Attribute4                               VARCHAR2,
616 			X_Attribute5                               VARCHAR2,
617 			X_Attribute6                               VARCHAR2,
618 			X_Attribute7                               VARCHAR2,
619 			X_Attribute8                               VARCHAR2,
620 			X_Attribute9                               VARCHAR2,
621 			X_Attribute_Category                       VARCHAR2,
622 			X_Discount_Amount_Remaining                NUMBER,
623 			X_Global_Attribute_Category                VARCHAR2,
624 			X_Global_Attribute1                        VARCHAR2,
625 			X_Global_Attribute2                        VARCHAR2,
626 			X_Global_Attribute3                        VARCHAR2,
627 			X_Global_Attribute4                        VARCHAR2,
628 			X_Global_Attribute5                        VARCHAR2,
629 			X_Global_Attribute6                        VARCHAR2,
630 			X_Global_Attribute7                        VARCHAR2,
631 			X_Global_Attribute8                        VARCHAR2,
632 			X_Global_Attribute9                        VARCHAR2,
633 			X_Global_Attribute10                       VARCHAR2,
634 			X_Global_Attribute11                       VARCHAR2,
635 			X_Global_Attribute12                       VARCHAR2,
636 			X_Global_Attribute13                       VARCHAR2,
637 			X_Global_Attribute14                       VARCHAR2,
638 			X_Global_Attribute15                       VARCHAR2,
639 			X_Global_Attribute16                       VARCHAR2,
640 			X_Global_Attribute17                       VARCHAR2,
641 			X_Global_Attribute18                       VARCHAR2,
642 			X_Global_Attribute19                       VARCHAR2,
643 			X_Global_Attribute20                       VARCHAR2,
644 			X_External_Bank_Account_Id                 NUMBER,
645 			X_Inv_Curr_Gross_Amount                    NUMBER,
646                         X_Org_Id                                   NUMBER,
647 			X_Calling_Sequence                     IN  VARCHAR2,
648 			--Third Party Payments
649 			X_Remit_To_Supplier_Name		VARCHAR2,
650 			X_Remit_To_Supplier_Id		NUMBER,
651 			X_Remit_To_Supplier_Site		VARCHAR2,
652 			X_Remit_To_Supplier_Site_Id		NUMBER,
653 			X_Relationship_Id				NUMBER
654 ) IS
655   CURSOR C IS
656       SELECT *
657       FROM   ap_payment_schedules
658       WHERE  invoice_id = X_Invoice_Id
659       AND    payment_num = X_Payment_Num
660       FOR UPDATE of invoice_id NOWAIT;
661   Recinfo C%ROWTYPE;
662 
663   first_conditions BOOLEAN := TRUE;
664   current_calling_sequence      VARCHAR2(2000);
665   debug_info                    VARCHAR2(100);
666 
667   BEGIN
668   -- Update the calling sequence
669   --
670     current_calling_sequence :=
671                'AP_PAYMENT_SCHEDULES_PKG.LOCK_ROW<-'||X_calling_sequence;
672 
673     debug_info := 'Open cursor C';
674     OPEN C;
675     debug_info := 'Fetch cursor C';
676     FETCH C INTO Recinfo;
677     if (C%NOTFOUND) then
678       debug_info := 'Close cursor C - ROW NOTFOUND';
679       CLOSE C;
680       RAISE NO_DATA_FOUND;
681     end if;
682     debug_info := 'Close cursor C';
683     CLOSE C;
684 
685     first_conditions :=
686 	    ((Recinfo.Invoice_Id = X_Invoice_Id) OR
687 	     ((Recinfo.Invoice_Id IS NULL)
688 	      AND (X_Invoice_Id IS NULL)))
689 	AND ((Recinfo.Last_Updated_By = X_Last_Updated_By) OR
690 	     ((Recinfo.Last_Updated_By IS NULL)
691 	      AND (X_Last_Updated_By IS NULL)))
692       -- Bug 2909797 AND ((Recinfo.Last_Update_Date = X_Last_Update_Date) OR
693       --     ((Recinfo.Last_Update_Date IS NULL)
694       --      AND (X_Last_Update_Date IS NULL)))
695 	AND ((Recinfo.Payment_Cross_Rate = X_Payment_Cross_Rate) OR
696 	     ((Recinfo.Payment_Cross_Rate IS NULL)
697 	      AND (X_Payment_Cross_Rate IS NULL)))
698 	AND ((Recinfo.Payment_Num = X_Payment_Num) OR
699 	     ((Recinfo.Payment_Num IS NULL)
700 	      AND (X_Payment_Num IS NULL)))
701 	AND ((Recinfo.Amount_Remaining = X_Amount_Remaining) OR
702 	     ((Recinfo.Amount_Remaining IS NULL)
703 	      AND (X_Amount_Remaining IS NULL)))
704 	AND ((Recinfo.Created_By = X_Created_By) OR
705 	     ((Recinfo.Created_By IS NULL)
706 	      AND (X_Created_By IS NULL)))
707       -- Bug 2909797 AND ((Recinfo.Creation_Date = X_Creation_Date) OR
708       --     ((Recinfo.Creation_Date IS NULL)
709       --      AND (X_Creation_Date IS NULL)))
710 	AND ((Recinfo.Discount_Date = X_Discount_Date) OR
711 	     ((Recinfo.Discount_Date IS NULL)
712 	      AND (X_Discount_Date IS NULL)))
713 	AND ((Recinfo.Due_Date = X_Due_Date) OR
714 	     ((Recinfo.Due_Date IS NULL)
715 	      AND (X_Due_Date IS NULL)))
719 	AND ((Recinfo.Gross_Amount = X_Gross_Amount) OR
716 	AND ((Recinfo.Future_Pay_Due_Date = X_Future_Pay_Due_Date) OR
717 	     ((Recinfo.Future_Pay_Due_Date IS NULL)
718 	      AND (X_Future_Pay_Due_Date IS NULL)))
720 	     ((Recinfo.Gross_Amount IS NULL)
721 	      AND (X_Gross_Amount IS NULL)))
722 	AND ((Recinfo.Hold_Flag = X_Hold_Flag) OR
723 	     ((Recinfo.Hold_Flag IS NULL)
724 	      AND (X_Hold_Flag IS NULL)))
725 	AND ((Recinfo.Last_Update_Login = X_Last_Update_Login) OR
726 	     ((Recinfo.Last_Update_Login IS NULL)
727 	      AND (X_Last_Update_Login IS NULL)))
728 	AND ((Recinfo.Payment_Method_Code = X_Payment_Method_Code) OR
729 	     ((Recinfo.Payment_Method_Code IS NULL)
730 	      AND (X_Payment_Method_Code IS NULL)))
731 	AND ((Recinfo.Payment_Priority = X_Payment_Priority) OR
732 	     ((Recinfo.Payment_Priority IS NULL)
733 	      AND (X_Payment_Priority IS NULL)))
734 	AND ((Recinfo.Payment_Status_Flag = X_Payment_Status_Flag) OR
735 	     ((Recinfo.Payment_Status_Flag IS NULL)
736 	      AND (X_Payment_Status_Flag IS NULL)))
737 	AND ((Recinfo.Second_Discount_Date = X_Second_Discount_Date) OR
738 	     ((Recinfo.Second_Discount_Date IS NULL)
739 	      AND (X_Second_Discount_Date IS NULL)))
740 	AND ((Recinfo.Third_Discount_Date = X_Third_Discount_Date) OR
741 	     ((Recinfo.Third_Discount_Date IS NULL)
742 	      AND (X_Third_Discount_Date IS NULL)))
743 	AND ((Recinfo.Batch_Id = X_Batch_Id) OR
744 	     ((Recinfo.Batch_Id IS NULL)
745 	      AND (X_Batch_Id IS NULL)))
746 	AND ((Recinfo.Discount_Amount_Available = X_Discount_Amount_Available) OR
747 	     ((Recinfo.Discount_Amount_Available IS NULL)
748 	      AND (X_Discount_Amount_Available IS NULL)))
749 	AND ((Recinfo.Second_Disc_Amt_Available = X_Second_Disc_Amt_Available) OR
750 	     ((Recinfo.Second_Disc_Amt_Available IS NULL)
751 	      AND (X_Second_Disc_Amt_Available IS NULL)))
752 	AND ((Recinfo.Third_Disc_Amt_Available = X_Third_Disc_Amt_Available) OR
753 	     ((Recinfo.Third_Disc_Amt_Available IS NULL)
754 	      AND (X_Third_Disc_Amt_Available IS NULL)))
755 	AND ((Recinfo.Attribute1 = X_Attribute1) OR
756 	     ((Recinfo.Attribute1 IS NULL)
757 	      AND (X_Attribute1 IS NULL)))
758 	AND ((Recinfo.Attribute10 = X_Attribute10) OR
759 	     ((Recinfo.Attribute10 IS NULL)
760 	      AND (X_Attribute10 IS NULL)))
761 	AND ((Recinfo.Attribute11 = X_Attribute11) OR
762 	     ((Recinfo.Attribute11 IS NULL)
763 	      AND (X_Attribute11 IS NULL)))
764 	AND ((Recinfo.Attribute12 = X_Attribute12) OR
765 	     ((Recinfo.Attribute12 IS NULL)
766 	      AND (X_Attribute12 IS NULL)))
767 	AND ((Recinfo.Attribute13 = X_Attribute13) OR
768 	     ((Recinfo.Attribute13 IS NULL)
769 	      AND (X_Attribute13 IS NULL)))
770 	AND ((Recinfo.Attribute14 = X_Attribute14) OR
771 	     ((Recinfo.Attribute14 IS NULL)
772 	      AND (X_Attribute14 IS NULL)))
773 	AND ((Recinfo.Attribute15 = X_Attribute15) OR
774 	     ((Recinfo.Attribute15 IS NULL)
775 	      AND (X_Attribute15 IS NULL)))
776 	AND ((Recinfo.Attribute2 = X_Attribute2) OR
777 	     ((Recinfo.Attribute2 IS NULL)
778 	      AND (X_Attribute2 IS NULL)))
779 	AND ((Recinfo.Attribute3 = X_Attribute3) OR
780 	     ((Recinfo.Attribute3 IS NULL)
781 	      AND (X_Attribute3 IS NULL)))
782 	AND ((Recinfo.Attribute4 = X_Attribute4) OR
783 	     ((Recinfo.Attribute4 IS NULL)
784 	      AND (X_Attribute4 IS NULL)))
785 	AND ((Recinfo.Attribute5 = X_Attribute5) OR
786 	     ((Recinfo.Attribute5 IS NULL)
787 	      AND (X_Attribute5 IS NULL)))
788 	AND ((Recinfo.Attribute6 = X_Attribute6) OR
789 	     ((Recinfo.Attribute6 IS NULL)
790 	      AND (X_Attribute6 IS NULL)))
791 	AND ((Recinfo.Attribute7 = X_Attribute7) OR
792 	     ((Recinfo.Attribute7 IS NULL)
793 	      AND (X_Attribute7 IS NULL)))
794 	AND ((Recinfo.Attribute8 = X_Attribute8) OR
795 	     ((Recinfo.Attribute8 IS NULL)
796 	      AND (X_Attribute8 IS NULL)))
797 	AND ((Recinfo.Attribute9 = X_Attribute9) OR
798 	     ((Recinfo.Attribute9 IS NULL)
799 	      AND (X_Attribute9 IS NULL)))
800 	AND ((Recinfo.Attribute_Category = X_Attribute_Category) OR
801 	     ((Recinfo.Attribute_Category IS NULL)
802 	      AND (X_Attribute_Category IS NULL)))
803 	AND ((Recinfo.Discount_Amount_Remaining = X_Discount_Amount_Remaining) OR
804 	     ((Recinfo.Discount_Amount_Remaining IS NULL)
805 	      AND (X_Discount_Amount_Remaining IS NULL)))
806 	-- Third party payments
807 	AND ((Recinfo.Remit_To_Supplier_Name = X_Remit_To_Supplier_Name) OR
808              ((Recinfo.Remit_To_Supplier_Name IS NULL)
809               AND (X_Remit_To_Supplier_Name IS NULL)))
810         AND ((Recinfo.Remit_To_Supplier_Id = X_Remit_To_Supplier_Id) OR
811              ((Recinfo.Remit_To_Supplier_Id IS NULL)
812               AND (X_Remit_To_Supplier_Id IS NULL)))
813         AND ((Recinfo.Remit_To_Supplier_Site = X_Remit_To_Supplier_Site) OR
814              ((Recinfo.Remit_To_Supplier_Site IS NULL)
815               AND (X_Remit_To_Supplier_Site IS NULL)))
816         AND ((Recinfo.Remit_To_Supplier_Site_Id = X_Remit_To_Supplier_Site_Id) OR
817              ((Recinfo.Remit_To_Supplier_Site_Id IS NULL)
818               AND (X_Remit_To_Supplier_Site_Id IS NULL)))
819         AND ((Recinfo.Relationship_Id = X_Relationship_Id) OR
820              ((Recinfo.Relationship_Id IS NULL)
821               AND (X_Relationship_Id IS NULL)));
822 
823     if (first_conditions
824 	AND ((Recinfo.Global_Attribute_Category = X_Global_Attribute_Category) OR
825 	     ((Recinfo.Global_Attribute_Category IS NULL)
826 	      AND (X_Global_Attribute_Category IS NULL)))
827 	AND ((Recinfo.Global_Attribute1 = X_Global_Attribute1) OR
828 	     ((Recinfo.Global_Attribute1 IS NULL)
829 	      AND (X_Global_Attribute1 IS NULL)))
830 	AND ((Recinfo.Global_Attribute2 = X_Global_Attribute2) OR
831 	     ((Recinfo.Global_Attribute2 IS NULL)
832 	      AND (X_Global_Attribute2 IS NULL)))
833 	AND ((Recinfo.Global_Attribute3 = X_Global_Attribute3) OR
834 	     ((Recinfo.Global_Attribute3 IS NULL)
835 	      AND (X_Global_Attribute3 IS NULL)))
836 	AND ((Recinfo.Global_Attribute4 = X_Global_Attribute4) OR
837 	     ((Recinfo.Global_Attribute4 IS NULL)
838 	      AND (X_Global_Attribute4 IS NULL)))
839 	AND ((Recinfo.Global_Attribute5 = X_Global_Attribute5) OR
840 	     ((Recinfo.Global_Attribute5 IS NULL)
841 	      AND (X_Global_Attribute5 IS NULL)))
842 	AND ((Recinfo.Global_Attribute6 = X_Global_Attribute6) OR
843 	     ((Recinfo.Global_Attribute6 IS NULL)
844 	      AND (X_Global_Attribute6 IS NULL)))
845 	AND ((Recinfo.Global_Attribute7 = X_Global_Attribute7) OR
846 	     ((Recinfo.Global_Attribute7 IS NULL)
847 	      AND (X_Global_Attribute7 IS NULL)))
848 	AND ((Recinfo.Global_Attribute8 = X_Global_Attribute8) OR
849 	     ((Recinfo.Global_Attribute8 IS NULL)
850 	      AND (X_Global_Attribute8 IS NULL)))
851 	AND ((Recinfo.Global_Attribute9 = X_Global_Attribute9) OR
852 	     ((Recinfo.Global_Attribute9 IS NULL)
853 	      AND (X_Global_Attribute9 IS NULL)))
854 	AND ((Recinfo.Global_Attribute10 = X_Global_Attribute10) OR
855 	     ((Recinfo.Global_Attribute10 IS NULL)
856 	      AND (X_Global_Attribute10 IS NULL)))
857 	AND ((Recinfo.Global_Attribute11 = X_Global_Attribute11) OR
858 	     ((Recinfo.Global_Attribute11 IS NULL)
859 	      AND (X_Global_Attribute11 IS NULL)))
860 	AND ((Recinfo.Global_Attribute12 = X_Global_Attribute12) OR
861 	     ((Recinfo.Global_Attribute12 IS NULL)
862 	      AND (X_Global_Attribute12 IS NULL)))
863 	AND ((Recinfo.Global_Attribute13 = X_Global_Attribute13) OR
864 	     ((Recinfo.Global_Attribute13 IS NULL)
865 	      AND (X_Global_Attribute13 IS NULL)))
866 	AND ((Recinfo.Global_Attribute14 = X_Global_Attribute14) OR
867 	     ((Recinfo.Global_Attribute14 IS NULL)
868 	      AND (X_Global_Attribute14 IS NULL)))
869 	AND ((Recinfo.Global_Attribute15 = X_Global_Attribute15) OR
870 	     ((Recinfo.Global_Attribute15 IS NULL)
871 	      AND (X_Global_Attribute15 IS NULL)))
872 	AND ((Recinfo.Global_Attribute16 = X_Global_Attribute16) OR
873 	     ((Recinfo.Global_Attribute16 IS NULL)
874 	      AND (X_Global_Attribute16 IS NULL)))
875 	AND ((Recinfo.Global_Attribute17 = X_Global_Attribute17) OR
876 	     ((Recinfo.Global_Attribute17 IS NULL)
877 	      AND (X_Global_Attribute17 IS NULL)))
878 	AND ((Recinfo.Global_Attribute18 = X_Global_Attribute18) OR
879 	     ((Recinfo.Global_Attribute18 IS NULL)
880 	      AND (X_Global_Attribute18 IS NULL)))
881 	AND ((Recinfo.Global_Attribute19 = X_Global_Attribute19) OR
882 	     ((Recinfo.Global_Attribute19 IS NULL)
883 	      AND (X_Global_Attribute19 IS NULL)))
884 	AND ((Recinfo.Global_Attribute20 = X_Global_Attribute20) OR
885 	     ((Recinfo.Global_Attribute20 IS NULL)
886 	      AND (X_Global_Attribute20 IS NULL)))
887 	AND ((Recinfo.External_Bank_Account_Id = X_External_Bank_Account_Id) OR
888 	     ((Recinfo.External_Bank_Account_Id IS NULL)
889 	      AND (X_External_Bank_Account_Id IS NULL)))
890 	AND ((Recinfo.Inv_Curr_Gross_Amount = X_Inv_Curr_Gross_Amount) OR
891 	     ((Recinfo.Inv_Curr_Gross_Amount IS NULL)
892 	      AND (X_Inv_Curr_Gross_Amount IS NULL)))
893         AND ((Recinfo.Org_Id = X_Org_Id) OR
894              ((Recinfo.Org_Id IS NULL)
895               AND (X_Org_Id IS NULL)))
896 ) then
897       return;
898     else
899       FND_MESSAGE.Set_Name('FND', 'FORM_RECORD_CHANGED');
900       APP_EXCEPTION.RAISE_EXCEPTION;
901     end if;
902 
903   EXCEPTION
904      WHEN OTHERS THEN
905          IF (SQLCODE <> -20001) THEN
906            IF (SQLCODE = -54) THEN
907              FND_MESSAGE.SET_NAME('SQLAP','AP_RESOURCE_BUSY');
908            ELSE
909              FND_MESSAGE.SET_NAME('SQLAP','AP_DEBUG');
910              FND_MESSAGE.SET_TOKEN('ERROR',SQLERRM);
911              FND_MESSAGE.SET_TOKEN('CALLING_SEQUENCE',
912                        current_calling_sequence);
913              FND_MESSAGE.SET_TOKEN('PARAMETERS',
914                  'X_Invoice_Id = '||X_Invoice_Id
915              ||', X_Payment_Num = '||X_Payment_Num
916                                   );
917              FND_MESSAGE.SET_TOKEN('DEBUG_INFO',debug_info);
918            END IF;
919          END IF;
920          APP_EXCEPTION.RAISE_EXCEPTION;
921 
922   END Lock_Row;
923 
924 END AP_PAYMENT_SCHEDULES_PKG;