DBA Data[Home] [Help]

PACKAGE BODY: APPS.PAY_SG_DEDUCTIONS

Source


1 PACKAGE BODY pay_sg_deductions AS
2 /*  $Header: pysgdedn.pkb 120.10.12010000.3 2008/08/06 08:21:51 ubhat ship $
3 **
4 **  Copyright (c) 2002 Oracle Corporation
5 **  All Rights Reserved
6 **
7 **  Procedures and functions used in SG deduction formula
8 **
9 **  Change List
10 **  ===========
11 **
12 **  Date        Author   Reference    Bug Number        Description
13 **  =========== ======== =========    ==========	=====================
14 **  26 Jun 2000 makelly  115.0     			Initial
15 **  6  Apr 2002 Ragovind 115.4     			Added Sg_get_Prorator function
16 **  10 Apr 2002 Ragovind 115.6     			Modified the sg_get_prorator function.
17 **  10 apr 2002 Ragovind 115.7     			Added comments to sg_get_prorator about functionality of CPF Proration calculation.
18 **  28 Jun 2002 SRussell 115.9     			Added CPF Retropay functions.
19 **  26 Jul 2002 SRussell 115.10    			Changed exception clause and Table order.
20 **  06 Aug 2002 Kaverma  115.11       2494173		modified sg_get_prorator function(Bug No - 2494173).
21 **  07 Aug 2002 Kaverma  115.12    			Modified fwl_amount function
22 **  02 Sep 2002 Ragoivnd 115.13    			Added Function get_prev_year_ord_ytd
23 **  19 Sep 2002 Ragovind 115.14    			Modified the cursor c_tax_unit_id
24 **  04 Oct 2002 vgsriniv 115.15    			Modified fwl_amount function
25 **  17 Oct 2002 apunekar 115.16    			Modified cursor c_get_dates to add distinct clause
26 **  17 Oct 2002 apunekar 115.17    			Added comments
27 **  06 Nov 2002 Ragovind 115.18    			Modified the cursor c_get_per_start_end_dates for CPF Calculation
28 **  11 Dec 2002 Apunekar 115.19    			Added nocopy to out or in out parameters
29 **  20 Dec 2002 Ragovind 115.20       2475324		Added CPF Report Coding.
30 **  29 Jan 2002 JLin     115.21       2772106		Modified cursor c_get_per_start_end_dates
31 **  11 Feb 2003 Ragovind 115.22       2796093   	Modified the CPF Report code for Correct CPF for Terminated Employees.
32 **  19 Mar 2003 Ragovind 115.23       2858065  		Corrected CPF prorator factor for Termination and Rehire employee in the same month
33 **  27 Mar 2003 Ragovind 115.24       2873083 	 	Corrected CPF prorator factor for Term/Rehire in same month and run Quickpay for the
34 **                                 			Terminated Employee Assignment.
35 **  02 Jan 2004 Nanuradh 115.25       3331018  		Removed the cursor c_get_prev_ord_ytd, instead used
36 **                                 			pay_balance.get_value to get prev year ordinary earnings ytd value.
37 **  02 Jan 2004 Nanuradh 115.26       3331018  		Modified the function get_prev_year_ord_ytd by initializing the
38 **                                 			variable l_prev_ord_ytd to zerio.
39 **  21 Jan 2004 agore    115.27       3279235 		Modified the function get_prev_year_ord_ytd ( ) to refer monthly balance
40 **                                 			values of following balances to arrive at Annual CPF eligible OW with monthly ceiling
41 **                                 			of 5500.CPF_ORDINARY_EARNINGS_ELIGIBLE_COMP, ORDINARY_EARNINGS_INELIGIBLE_FOR_CPF
42 **                                 			and RETRO_ORD_RETRO_PERIOD
43 **                                 			Added new functions get_cur_year_ord_ytd ( ) and get_retro_earnings( )
44 **  18 May 2004 Nanuradh 115.28       3595103 		Added new function spl_amount( ) to calculate S Pass Levy for permit type SP.
45 **  18 May 2004 Nanuradh 115.32       3595103 		Modified function sg_get_prorator() for permit type 'SP'
46 **  24 Jun 2004 abhargav 115.35        			Undo the changes of the Bug#3677801
47 **  31 Jan 2005 snimmala 115.36       4149190		Modified the function sg_get_prorator() to calculate total days as number of
48 **							working days instead of days in the payroll period.
49 **  27 Jun 2005 JLin     115.37       4267196           Performance issue, modified the function get_prev_year_ord_ytd
50 **                                                      and get_cur_year_ord_ytd to replace ppa.date_earned with ppa.effective_date
51 **  09 Jun 2006 JLin     115.39       5298298           Modified the function
52 **                                                      get_prev_year_ord_ytd and
53 **                                                      get_cur_year_ord_ytd to
54 **                                                      include all assignments.
55 **                                                      (eg.,rehire to include original assignment)
56 **  13 Jun 2006 JLin     115.40       5298298           To include the Legal Entity
57 **                                                      check for previous fix
58 **  14 Jun 2006 JLin     115.41,42    5298298           To include the multi-assignments
59 **  23 Jun 2006 snimmala 115.43       5353558           Modified the sql query of the cursor get_retro_method
60 **                                                      in the function which_retro_method.
61 **  27 Jun 2006 snimmala 115.44       5353558           Removed the check for 'Information' classification
62 **                                                      in the function which_retro_method.
63 **  14 Sep 2006 snimmala 115.45       5410589           Function fwl_amount() has been modified to check whether
64 **                                                      permit category is valid for pay period or not.
65 **  21 May 2007 snimmala 115.46       6046808           Modified the cursor c_get_dates in the function fwl_amount
66 **                                                      to move order by clause to outer query.
67 **  02 Jul 2007 jalin    115.47       6158284           Modified the cursor c_get_dates in the function fwl_amount
68 **                                                      to add currect employee check
69 ** 22 Feb 2008  jalin    115.48       6815874           Modified calling function
70 **                                                      get_retro_earnings to use
71 **                                                      l_effective as parameter
72 **                                                      Modified cursor c_pay_element_entries
73 **                                                      to get correct retro values
74 **                                                      Removed parameter ass_act_id from get_retro_earnings function
75 ** 27 Mar 2008  jalin    115.49       6815874           Added fix if retro ord
76 **                                                      is neg
77 
78 **  ============== Formula Fuctions ====================
79 **  Package containing addition processing required by
80 **  formula in SG localisation
81 */
82 
83 /*
84 **  fwl_amount - returns the amount of foreign workers levy
85 **  due in a month
86 **
87 **  Error return codes used - messages raised in fast formula
88 **
89 **  -77  Invalid dates used for Work Permit
90 **  -88  Work Permit Category is null
91 **  -99  Unhandled Exception
92 */
93 
94 function  fwl_amount ( p_business_group_id in     number
95                      , p_date_earned       in     date
96                      , p_assignment_id     in     number
97                      , p_start_date        in     date
98                      , p_end_date          in     date   )
99           return number is
100 
101 
102 TYPE t_permit_dates_rec is record   (  permit_category  varchar2(60)
103                                      , date_start       date
104                                      , date_end         date
105                                      , date_cancel      date
106                                      , effective_start_date date) ;
107 
108 TYPE t_permit_dates_tab is table of t_permit_dates_rec index by binary_integer ;
109 
110 l_permit              t_permit_dates_tab;
111 l_counter             number;
112 l_amt                 number              := 0;
113 l_mth_amt             number;
114 l_dly_amt             number;
115 l_days                number              := 0;
116 l_tot_days            number              := 0;
117 l_max_days            number              := 0;
118 l_category            varchar2(60);
119 l_same_category       boolean             := TRUE;
120 l_sot                 date;
121 l_eot                 date;
122 l_proc                varchar2(60);
123 l_start		      date;
124 l_end		      date;
125 l_months	      number;
126 l_value               number;
127 
128 /*Bug#2626075-Distinct added in c_get_dates cursor*/
129 /*Bug#6046808 - Moved Order By clause to Outer Query */
130 /*Bug#6158284 - Added current employee flag check */
131 
132 cursor c_get_dates       (  p_assignment_id NUMBER
133                           , p_start_date    DATE
134                           , p_end_date      DATE   ) is
135 select distinct * from
136 (
137 select per_information8
138      , to_date(per_information9,  'YYYY/MM/DD HH24:MI:SS')
139      , to_date(per_information10, 'YYYY/MM/DD HH24:MI:SS')
140      , to_date(per_information11, 'YYYY/MM/DD HH24:MI:SS')
141      , effective_start_date
142   from per_all_people_f        per
143  where per.person_id = (select max(paf.person_id)
144                           from per_all_assignments_f paf
145                          where paf.assignment_id = p_assignment_id)
146    and per.per_information6 = 'WP'
147    and nvl(per.current_employee_flag,'N') = 'Y' /* Bug 6158284 */
148    and per.effective_start_date <= p_end_date
149    and per.effective_end_date   >= p_start_date)
150    order by effective_start_date;
151 
152 /*Bug#5410589 - Following cursor has been added to check whether permit category is valid
153                 for this pay period or not*/
154 
155 cursor c_check_permit_type(p_permit_category  per_all_people_f.per_information8%type
156                           ,p_date_earned DATE)
157 is
158 select CINST.value
159 from   pay_user_tables                    tab
160       ,pay_user_columns                   col
161       ,pay_user_rows_f                    r
162       ,pay_user_column_instances_f        cinst
163 where  tab.user_table_name = 'FWL_RATES'
164 and    col.user_table_id   = tab.user_table_id
165 and    upper(col.user_column_name)= upper('Daily Rate')
166 and    cinst.user_column_id = col.user_column_id
167 and    r.user_table_id = tab.user_table_id
168 and    r.ROW_LOW_RANGE_OR_NAME = p_permit_category
169 and    cinst.user_row_id = r.user_row_id
170 and    p_date_earned between cinst.effective_start_date and cinst.effective_end_date;
171 
172 begin
173   l_sot    := to_date('0001/01/01 00:00:00', 'YYYY/MM/DD HH24:MI:SS');
174   l_eot    := to_date('4712/12/31 00:00:00', 'YYYY/MM/DD HH24:MI:SS');
175   l_proc   := 'pay_sg_deductions.fwl_amount';
176 
177 
178   hr_utility.set_location('Entering : '||l_proc, 5);
179 
180   l_counter := 1;
181 
182   open c_get_dates( p_assignment_id, p_start_date, p_end_date) ;
183   fetch c_get_dates into l_permit(l_counter);
184   if c_get_dates%notfound then
185     hr_utility.set_location('Leaving - No fwl in month : '||l_proc, 10);
186     return 0;
187   end if;
188 
189   l_counter := l_counter + 1;
190 
191   fetch c_get_dates into l_permit(l_counter);
192 
193   while c_get_dates%found loop
194     l_counter := l_counter + 1;
195     fetch c_get_dates into l_permit(l_counter);
196   end loop;
197 
198   close c_get_dates;
199 
200     l_max_days := least (nvl(l_permit(l_permit.last).date_end, l_eot), nvl(l_permit(l_permit.last).date_cancel, l_eot)) -  p_start_date + 1;
201   l_category := l_permit(1).permit_category;
202 
203   if l_category is not null then
204     /*Bug#5410589 */
205     open c_check_permit_type(l_category,p_date_earned);
206     fetch c_check_permit_type into l_value;
207     if c_check_permit_type%notfound then
208          return(-66);
209     end if;
210     close c_check_permit_type;
211 
212     l_mth_amt := to_number(hruserdt.get_table_value (p_bus_group_id   => p_business_group_id
213                                                     ,p_table_name     => 'FWL_RATES'
214                                                     ,p_col_name       => 'Monthly Rate'
215                                                     ,p_row_value      => l_category
216                                                     ,p_effective_date => p_date_earned ));
217 
218     l_dly_amt := to_number(hruserdt.get_table_value (p_bus_group_id   => p_business_group_id
219                                                     ,p_table_name     => 'FWL_RATES'
220                                                     ,p_col_name       => 'Daily Rate'
221                                                     ,p_row_value      => l_category
222                                                     ,p_effective_date => p_date_earned ));
223 
224   end if;
225 
226 
227   FOR i in 1..l_permit.last LOOP
228 
229     if l_permit(i).permit_category is null then
230 
231         hr_utility.set_location('Error - WP Category is null : '||l_proc, 88);
232         return (-88);
233 
234     else
235 
236       if      (l_permit(i).date_start  > l_permit(i).date_end)
237            OR (l_permit(i).date_start  > l_permit(i).date_cancel) THEN
238 
239         hr_utility.set_location('Invalid Date Ranges Within Month: '||l_proc, 77);
240         return (-77);
241 
242 
243       elsif (l_permit(i).date_start  > p_end_date  )
244            OR (l_permit(i).date_end    < p_start_date)
245            OR (l_permit(i).date_cancel < p_start_date) THEN
246 
247         null;
248 
249       else
250         /*Bug#5410589 */
251         open c_check_permit_type(l_permit(i).permit_category,p_date_earned);
252         fetch c_check_permit_type into l_value;
253         if c_check_permit_type%notfound then
254            return(-66);
255         end if;
256         close c_check_permit_type;
257 
258         if l_permit(i).permit_category <> l_category then
259 
260           l_same_category := FALSE;
261 
262         end if;
263         l_start := greatest (nvl(l_permit(i).date_start, l_sot), p_start_date);
264         l_end := least (nvl(l_permit(i).date_end, l_eot), nvl(l_permit(i).date_cancel, l_eot));
265         /* Bug 2610156 : Least of l_end and Pay Period end date should be
266            used to calculate number of days(i.e., l_days)
267            l_end is the least of expiry date and cancellation date */
268         l_end := least(l_end,p_end_date);
269 
270         l_days := greatest ((l_end - l_start)+1, 0 );
271         l_months := round(months_between(l_end + 1,l_start),2);
272 
273 
274         l_days := greatest ((l_end - l_start)+1, 0 );
275 
276         l_tot_days := l_tot_days + l_days;
277 
278 
279         if l_tot_days > l_max_days then
280 
281           hr_utility.set_location('Invalid Date Ranges Within Month : '||l_proc, 77);
282           return (-77);
283 
284         end if;
285 
286         if l_same_category then
287           if l_months >= 1 then
288             l_amt := l_mth_amt;
289           else
290             l_amt := least(l_mth_amt, (l_amt + (l_dly_amt * l_days)));
291           end if;
292 
293         else
294 
295           l_mth_amt  := to_number(hruserdt.get_table_value (p_bus_group_id   => p_business_group_id
296                                                            ,p_table_name     => 'FWL_RATES'
297                                                            ,p_col_name       => 'Monthly Rate'
298                                                            ,p_row_value      => l_permit(i).permit_category
299                                                            ,p_effective_date => p_date_earned ));
300 
301           l_dly_amt  := to_number(hruserdt.get_table_value (p_bus_group_id   => p_business_group_id
302                                                            ,p_table_name     => 'FWL_RATES'
303                                                            ,p_col_name       => 'Daily Rate'
304                                                            ,p_row_value      => l_permit(i).permit_category
305                                                            ,p_effective_date => p_date_earned ));
306 	  if l_months >= 1 then
307 	    l_amt := l_mth_amt;
308 	  else
309             l_amt := l_amt + least(l_mth_amt, (l_dly_amt * l_days));
310           end if;
311 
312         end if;
313 
314       end if;
315 
316     end if;
317 
318   END LOOP;
319 
320   hr_utility.set_location('Leaving:'||l_proc, 20);
321   return l_amt;
322 
323   EXCEPTION
324        WHEN others THEN
325          hr_utility.set_location('Unhandled Exception in function call fwl_amount : '||l_proc, 99);
326          RETURN -99;
327 
328 end fwl_amount;
329 
330 /* Bug: 3595103 - New function to calculate S Pass Levy */
331 function  spl_amount ( p_business_group_id in     number
332                      , p_date_earned       in     date
333                      , p_assignment_id     in     number
334                      , p_start_date        in     date
335                      , p_end_date          in     date   )
336           return number is
337 
338 TYPE t_permit_dates_rec is record   (permit_type varchar2(5)
339                                      , date_start       date
340                                      , date_end         date
341                                      , date_cancel      date      ) ;
342 
343 TYPE t_permit_dates_tab is table of t_permit_dates_rec index by binary_integer ;
344 
345 l_permit              t_permit_dates_tab;
346 l_counter             number;
347 l_amt                 number              := 0;
348 l_mth_amt             number;
349 l_dly_amt             number;
350 l_days                number              := 0;
351 l_tot_days            number              := 0;
352 l_max_days            number              := 0;
353 l_category            varchar2(60);
354 l_same_category       boolean             := TRUE;
355 l_sot                 date;
356 l_eot                 date;
357 l_proc                varchar2(60);
358 l_start		      date;
359 l_end		      date;
360 l_months	      number;
361 
362 cursor c_get_dates       (  p_assignment_id NUMBER
363                           , p_start_date    DATE
364                           , p_end_date      DATE   ) is
365 select distinct * from
366 (
367 select per_information6
368      , to_date(per_information9,  'YYYY/MM/DD HH24:MI:SS')
369      , to_date(per_information10, 'YYYY/MM/DD HH24:MI:SS')
370      , to_date(per_information11, 'YYYY/MM/DD HH24:MI:SS')
371   from per_all_people_f        per
372  where per.person_id = (select max(paf.person_id)
373                           from per_all_assignments_f paf
374                          where paf.assignment_id = p_assignment_id)
375    and per.per_information6 = 'SP'
376    and per.effective_start_date <= p_end_date
377    and per.effective_end_date   >= p_start_date
378  order by per.effective_start_date);
379 
380 
381 begin
382   l_sot    := to_date('0001/01/01 00:00:00', 'YYYY/MM/DD HH24:MI:SS');
383   l_eot    := to_date('4712/12/31 00:00:00', 'YYYY/MM/DD HH24:MI:SS');
384   l_proc   := 'pay_sg_deductions.spl_amount';
385 
386   hr_utility.set_location('Entering : '||l_proc, 5);
387 
388    l_counter := 1;
389 
390   open c_get_dates( p_assignment_id, p_start_date, p_end_date) ;
391   fetch c_get_dates into l_permit(l_counter);
392   if c_get_dates%notfound then
393     hr_utility.set_location('Leaving - No fwl in month : '||l_proc, 10);
394     return 0;
395   end if;
396 
397   l_counter := l_counter + 1;
398 
399   fetch c_get_dates into l_permit(l_counter);
400 
401   while c_get_dates%found loop
402     l_counter := l_counter + 1;
403     fetch c_get_dates into l_permit(l_counter);
404   end loop;
405 
406   close c_get_dates;
407 
408     l_max_days := least (nvl(l_permit(l_permit.last).date_end, l_eot), nvl(l_permit(l_permit.last).date_cancel, l_eot)) -  p_start_date + 1;
409     l_category := 'SP';
410   if l_category is not null then
411 
412     l_mth_amt := to_number(hruserdt.get_table_value (p_bus_group_id   => p_business_group_id
413                                                     ,p_table_name     => 'FWL_RATES'
414                                                     ,p_col_name       => 'Monthly Rate'
415                                                     ,p_row_value      => l_category
419                                                     ,p_table_name     => 'FWL_RATES'
416                                                     ,p_effective_date => p_date_earned ));
417 
418     l_dly_amt := to_number(hruserdt.get_table_value (p_bus_group_id   => p_business_group_id
420                                                     ,p_col_name       => 'Daily Rate'
421                                                     ,p_row_value      => l_category
422                                                     ,p_effective_date => p_date_earned ));
423 
424   end if;
425 
426 
427   FOR i in 1..l_permit.last LOOP
428       if (l_permit(i).date_start  > l_permit(i).date_end)
429          OR (l_permit(i).date_start  > l_permit(i).date_cancel) THEN
430 
431          hr_utility.set_location('Invalid Date Ranges Within Month: '||l_proc, 77);
432          return (-77);
433 
434 
435       elsif (l_permit(i).date_start  > p_end_date  )
436              OR (l_permit(i).date_end    < p_start_date)
437              OR (l_permit(i).date_cancel < p_start_date) THEN
438 
439              null;
440       else
441              l_start := greatest (nvl(l_permit(i).date_start, l_sot), p_start_date);
442              l_end := least (nvl(l_permit(i).date_end, l_eot), nvl(l_permit(i).date_cancel, l_eot));
443              l_end := least(l_end,p_end_date);
444 
445              l_days := greatest ((l_end - l_start)+1, 0 );
446              l_months := round(months_between(l_end + 1,l_start),2);
447 
448 
449              l_tot_days := l_tot_days + l_days;
450 
451              if l_tot_days > l_max_days then
452                  hr_utility.set_location('Invalid Date Ranges Within Month : '||l_proc, 77);
453                  return (-77);
454              end if;
455 
456              if l_months >= 1 then
457                 l_amt := l_mth_amt;
458              else
459                 l_amt := least(l_mth_amt, (l_amt + (l_dly_amt * l_days)));
460              end if;
461 
462         end if;
463 
464   END LOOP;
465 
466   hr_utility.set_location('Leaving:'||l_proc, 20);
467   return l_amt;
468 
469   EXCEPTION
470        WHEN others THEN
471          hr_utility.set_location('Unhandled Exception in function call spl_amount : '||l_proc, 99);
472          RETURN -99;
473 
474 end spl_amount;
475 
476 
477 function sg_get_prorator   ( p_assignment_id       in  number,
478                              p_date_earned         in  date,
479                              p_pay_proc_start_date in  date,
480                              p_pay_proc_end_date   in  date,
481                              p_wac		   in  varchar2,
482                              p_cpf_calc_type       out nocopy varchar2
483                            ) return number is
484 
485 l_wac             varchar2(2);
486 l_effective_date  date;
487 start_date        date;
488 start_wac         varchar2(2);
489 prorate_date      date;
490 prorate_wac       varchar2(2);
491 l_prorator        number;
492 l_days            number;
493 l_total_days      number;
494 l_assign_start_date date;
495 l_assign_end_date   date;
496 l_proc_start_date   date;
497 l_proc_end_date     date;
498 l_emp_start_bet_period varchar2(1);
499 l_emp_end_bet_period   varchar2(1);
500 l_proc            varchar2(60);
501 
502 /* Cursor declaration */
503 cursor c_get_per_start_end_dates (c_assignment_id       number ,
504                               c_pay_proc_start_date date,
505                               c_pay_proc_end_date   date)
506        is
507        select min(pap.effective_start_date),max(pap.effective_end_date) /*bug 2772106 */
508          from per_all_people_f pap,
509               per_all_assignments_f target
510         where target.assignment_id = c_assignment_id
511           and pap.person_id = target.person_id
512           and nvl(pap.current_employee_flag,'N') = 'Y';
513 
514 cursor c_get_wac ( c_assignment_id       NUMBER,
515                    c_date                DATE )
516        is
517        select target.PER_INFORMATION6,
518               target.EFFECTIVE_START_DATE
519          from per_all_people_f               target
520         where target.person_id = (select paf.person_id
521                                     from per_all_assignments_f paf
522                                    where paf.assignment_id = c_assignment_id
523                                      and c_date between paf.effective_start_date and paf.effective_end_date )
524           and c_date between target.effective_start_date and target.effective_end_date;
525 
526 begin
527   l_prorator  := -1.0;
528   l_emp_start_bet_period  := 'N';
529   l_emp_end_bet_period    := 'N';
530   l_proc      := 'pay_sg_deductions.sg_get_prorator';
531 
532  /* Get the WAC effective at start of the pay period */
533   hr_utility.set_location('Entering : '||l_proc, 5);
534   hr_utility.trace('p_assignment_id : '||p_assignment_id);
535   hr_utility.trace('p_pay_proc_start_date : '||p_pay_proc_start_date );
536   hr_utility.trace('p_pay_proc_end_date   : '||p_pay_proc_end_date   );
537   hr_utility.trace('p_date_earned         : '||p_date_earned         );
538   hr_utility.trace('p_wac                 : '||p_wac);
539 
540   p_cpf_calc_type  := p_wac ; /* assign the default value of WAC for the person as WAC exist at period end date */
541 
545   if c_get_per_start_end_dates%NOTFOUND then
542   open c_get_per_start_end_dates(p_assignment_id , p_pay_proc_start_date, p_pay_proc_end_date);
543   fetch c_get_per_start_end_dates into l_assign_start_date,l_assign_end_date;
544 
546     close c_get_per_start_end_dates;
547     hr_utility.set_location('Error : Assignment does not exist in the pay process period'||l_proc,5);
548   else
549     if (l_assign_start_date > p_pay_proc_start_date ) then
550        l_proc_start_date := l_assign_start_date;
551     else
552        l_proc_start_date := p_pay_proc_start_date;
553     end if;
554     if (l_assign_end_date < p_pay_proc_end_date ) then
555        l_proc_end_date := l_assign_end_date;
556     else
557        l_proc_end_date := p_pay_proc_end_date;
558     end if;
559   end if;
560 
561     open c_get_wac( p_assignment_id , l_proc_start_date );
562     fetch c_get_wac into l_wac, l_effective_date;
563     if c_get_wac%NOTFOUND then
564        close c_get_wac;
565        hr_utility.set_location('Error : Assignment doesnot exist at the pay proc start date'||l_proc,10);
566        return 1;  /* Bug#2858065 */
567     end if;
568     close c_get_wac;
569     /* store the wac at the start of the period */
570     start_wac := l_wac;
571     /* store the wac effective start date */
572     start_date := l_effective_date;
573 
574    /* if wac effective start date is less than pay proc start date,then
575    set the pay proc start date as the start_date */
576    if (l_effective_date < p_pay_proc_start_date) then
577     start_date := p_pay_proc_start_date;
578    end if;
579 
580    hr_utility.trace('start_wac : '||start_wac);
581    hr_utility.trace('start_date : '||start_date);
582 
583    /* Get the WAC and at the period end date*/
584 
585   open c_get_wac( p_assignment_id,l_proc_end_date);
586   fetch c_get_wac into l_wac, l_effective_date;
587   if c_get_wac%NOTFOUND then
588     close c_get_wac;
589     hr_utility.set_location('Error : Assignment doesnot exist at the pay proc end date (ie terminated)'||l_proc,20);
590     return 1; /* Bug#2873083 */
591   end if;
592   close c_get_wac;
593 
594   /* store the wac at the end of the pay period*/
595   prorate_wac  := l_wac;
596   /* store the effective start date for the above wac*/
597   prorate_date := l_effective_date;
598 
599   /* if wac effective start date is less than pay proc start date ,then
600    set the pay proc start date as the prorate_date */
601 
602   if (l_effective_date < p_pay_proc_start_date ) then
603     prorate_date := p_pay_proc_start_date;
604   end if;
605 
606   hr_utility.trace('prorate_wac : '||prorate_wac);
607   hr_utility.trace('prorate_date : '||prorate_date);
608 
609   if (p_date_earned <> start_date ) then
610        l_total_days := fffunc.days_between(l_proc_end_date , l_proc_start_date)+1;
611 -------------------------------------------------------------------------------------------------
612 --Bug# 4149190
613 --p_pay_proc_start_date, p_pay_proc_end_date are replaced by l_proc_start_date,
614 --l_proc_end_date respectively.
615 -------------------------------------------------------------------------------------------------
616        hr_utility.trace('l_total_days : '||l_total_days );
617   end if;
618 
619   /* Proration Calculation Block */
620   /* If the employee start date or end date is in between the pay period then
621     for proration we have to take the employee start / end date instead of period
622     start/end date .That is , if the employee has started in between the pay period,then
623     we will take this date for the calculation of proration instead of pay period start date.
624     Similarly if the emplyee is terminated in between then we will take the termination date
625     instead of period end date.In such case the proration is calculated for example
626     from employee start date to period end date divided by the number of days in the period*/
627 
628    If (l_proc_start_date > p_pay_proc_start_date and l_proc_start_date < p_pay_proc_end_date) then
629      l_emp_start_bet_period := 'Y';
630    end if;
631 
632    If (l_proc_end_date > p_pay_proc_start_date and l_proc_end_date < p_pay_proc_end_date) then
633      l_emp_end_bet_period := 'Y';
634    end if;
635 
636    if (start_wac = prorate_wac and (start_wac = 'PR' or start_wac = 'SG')) then
637       p_cpf_calc_type := prorate_wac; /*2494173*/
638       l_prorator := 1.0;
639   else
640   /* Proration need to be accounted for the eligible duration of pay period */
641   /* Bug: 3595103 - Modified get_sg_prorator for Permit type S Pass - SP    */
642 
643       if ((start_wac = 'PR' or start_wac = 'SG') and (prorate_wac = 'EP' or prorate_wac = 'WP' or start_wac = 'SP'))then
644         /* Need to calculate the proration for the first period, since the wac in the second period is
645            not eligible for CPF*/
646           l_days := fffunc.days_between(prorate_date,start_date);
647           p_cpf_calc_type := start_wac;
648           l_prorator := l_days / l_total_days;
649           hr_utility.trace('p_cpf_calc_type :'||p_cpf_calc_type);
650           hr_utility.trace('l_days : '||l_days );
651 
652       elsif ((start_wac = 'WP' or start_wac = 'EP' or start_wac = 'SP') and (prorate_wac = 'PR' or prorate_wac = 'SG')) then
653         /* Need to calculate the proration for the second period and first period does not have
654            eligible for the CPF Proration */
658           p_cpf_calc_type := prorate_wac;
655           l_days := fffunc.days_between(l_proc_end_date,prorate_date)+1;
656                                 /* Added +1 to include prorate date also */
657           hr_utility.trace('l_days : '||l_days );
659           l_prorator := l_days / l_total_days;
660 
661       elsif ((start_wac = 'SG' or start_wac = 'PR') and (prorate_wac = 'SG' or prorate_wac = 'PR')) then
662         /* Need not calculate the CPF Calculation. Hence setting the l_prorator value to 1 and the
663         CPF Calcualtion type to prorate type */
664          if (l_emp_start_bet_period = 'Y' and l_emp_end_bet_period = 'Y' ) then
665 	      l_days := fffunc.days_between(l_proc_end_date, l_proc_start_date)+1;
666             l_prorator := l_days/l_total_days;
667 
668          elsIf (l_emp_start_bet_period = 'Y') then
669            l_days := fffunc.days_between(p_pay_proc_end_date, l_proc_start_date)+1;
670            l_prorator := l_days/l_total_days;
671 
672          elsif (l_emp_end_bet_period = 'Y') then
673            l_days := fffunc.days_between(l_proc_end_date,p_pay_proc_start_date)+1;
674            l_prorator := l_days/l_total_days;
675 
676          else
677 	     l_prorator := 1.0;
678          end if;
679          p_cpf_calc_type := prorate_wac;
680 
681      elsif ((start_wac = 'WP' or start_wac = 'EP' or start_wac = 'SP') and
682             (prorate_wac = 'WP' or prorate_wac = 'EP' or start_wac = 'SP')) then
683      /* Need not calculate the CPF Calculation. Hence setting the l_prorator value to -1 and the
684         CPF Calcualtion type to prorate type */
685           l_prorator := -1.0;
686           p_cpf_calc_type := prorate_wac;
687 
688      end if;
689   end if;
690  /* End of Proration Calculation */
691   hr_utility.trace('p_cpf_calc_type :'||p_cpf_calc_type);
692   hr_utility.trace('l_prorator : '||l_prorator);
693   hr_utility.set_location('Leaving : '||l_proc, 5);
694 
695   return l_prorator;
696 end sg_get_prorator;
697 
698 /*
699 **  This function will identify if the element being processed is a retropay element.
700 **  If it is a flag set to Y is returned.
701 */
702 
703 function check_if_retro
704          (
705            p_element_entry_id  in pay_element_entries_f.element_entry_id%TYPE,
706            p_date_earned in pay_payroll_actions.date_earned%TYPE
707          ) return varchar2 IS
708 
709 cursor c_get_creator_type(
710      c_element_entry_id in pay_element_entries_f.element_entry_id%TYPE,
711      c_date_earned in pay_payroll_actions.date_earned%TYPE
712                          ) is
713 SELECT creator_type
714   FROM pay_element_entries_f pee
715   WHERE pee.element_entry_id = c_element_entry_id
716   AND c_date_earned between pee.effective_start_date and pee.effective_end_date;
717 
718 l_creator_type pay_element_entries_f.creator_type%TYPE;
719 IS_retro_payment varchar2(10);
720 
721 begin
722 
723 /*  Check creator_type to identify if its a retropay element.
724 **  Creator_type of RR (updated element entry) or EE (new element entry) indicates
725 **  it's a retropay element.
726 */
727 
728    OPEN  c_get_creator_type(p_element_entry_id,p_date_earned);
729    FETCH c_get_creator_type INTO l_creator_type ;
730    CLOSE c_get_creator_type;
731    if l_creator_type = 'RR' or l_creator_type = 'EE' then
732        IS_retro_payment:='Y';
733    else
734        IS_retro_payment:='N';
735    end if;
736 
737   return IS_retro_payment;
738 
739   EXCEPTION
740       when others then
741         IS_retro_payment:='N';
742 
743 end check_if_retro;
744 
745 
746 /*
747 **  This function will identify which retropay method the retropay element was
748 **  created under.
749 **  Eg. Retropay method A indicates that CPF calculations are to be performed in the
750 **  current payroll period and therefore the Retropay By Element run had no CPF
751 **  elements in the element set.
752 **      Retropay method B indicates that CPF calculations are to be performed in the
753 **  period the retrospective payment was earnt therefore the Retropay By Element run
754 **  DID have CPF elements in the element set.
755 **
756 */
757 
758 function which_retro_method
759          (
760            p_assignment_id    in pay_assignment_actions.assignment_id%TYPE,
761            p_date_earned      in pay_payroll_actions.date_earned%TYPE,
762            p_element_entry_id in pay_element_entries_f.element_entry_id%TYPE
763          ) return varchar2 IS
764 
765 /*
766 **  Bug#5353558  Cursor to look for any CPF elements exists in the Element Set of
767 **  the retro pay, which has created this retro element.
768 */
769 
770 cursor get_retro_method
771          ( c_assignment_id in pay_element_entries_f.element_entry_id%TYPE,
772            c_date_earned   in pay_payroll_actions.date_earned%TYPE,
773            c_element_entry_id in pay_element_entries_f.element_entry_id%TYPE
774          ) is
775 select pet.element_name
776   from pay_element_entries_f pee,
777        pay_assignment_actions paa,
778        pay_payroll_actions ppa,
779        pay_element_sets pes,
780        pay_element_type_rules petr,
781        pay_element_types_f pet
782   where pee.creator_id = paa.assignment_action_id
783   and   pee.assignment_id = c_assignment_id
784   and   pee.creator_type in ('EE', 'RR')
788   and   pes.element_set_id = petr.element_set_id
785   and   pee.element_entry_id = c_element_entry_id
786   and   paa.payroll_action_id = ppa.payroll_action_id
787   and   ppa.element_set_id = pes.element_set_id
789   and   petr.element_type_id = pet.element_type_id
790   and   petr.include_or_exclude = 'I'
791   and   c_date_earned between pet.effective_start_date and pet.effective_end_date
792   and   c_date_earned between pee.effective_start_date and pee.effective_end_date
793   and pet.element_name like '%CPF%'
794   and pet.legislation_code = 'SG'
795 union all
796 select pec.classification_name
797   from pay_element_entries_f pee,
798        pay_assignment_actions paa,
799        pay_payroll_actions ppa,
800        pay_element_sets pes,
801        pay_ele_classification_rules pecr,
802        pay_element_classifications pec
803   where pee.creator_id = paa.assignment_action_id
804   and   pee.assignment_id = c_assignment_id
805   and   pee.creator_type in ('EE', 'RR')
806   and   pee.element_entry_id = c_element_entry_id
807   and   paa.payroll_action_id = ppa.payroll_action_id
808   and   ppa.element_set_id = pes.element_set_id
809   and   pes.element_set_id = pecr.element_set_id
810   and   pecr.classification_id = pec.classification_id
811   and   c_date_earned between pee.effective_start_date and pee.effective_end_date
812   and   pec.classification_name in ('Statutory Deductions', 'Employer Liabilities')
813   and   pec.legislation_code = 'SG';
814 
815 l_ele_rec        get_retro_method%ROWTYPE;
816 l_retro_method   varchar2(10);
817 
818 begin
819 
820 /*  Default to method A. */
821 
822     l_retro_method := 'A';
823 
824 /*
825 **  Bug# 5353558 If any of the elements processed in the retro pay were CPF elements and
826 **  seeded then the retropay process must have been for Method B.
827 */
828 
829     open get_retro_method(p_assignment_id,p_date_earned,p_element_entry_id);
830     fetch get_retro_method into l_ele_rec;
831     if  get_retro_method%FOUND then
832         l_retro_method := 'B';
833         close get_retro_method;
834     end if;
835 
836     return l_retro_method;
837 
838 end which_retro_method;
839 
840 /*
841 **  This function will identify the earnings type of the retropay element.
842 **  If the balance it feeds is 'CPF Ordinary Earnings Eligible Comp' then it
843 **  must be classed as Ordinary Earnings (type O).
844 **  If the balance it feeds is 'CPF Additional Earnings Eligible Comp' then it
845 **  must be classed as Additional Earnings (type A).
846 **  If neither of these then leave blank.
847 */
848 
849 function earnings_type
850          (
851            p_element_type_id  in pay_element_types_f.element_type_id%TYPE
852          ) return varchar2 IS
853 
854 cursor c_earnings_type
855          ( c_element_type_id   in pay_element_types_f.element_type_id%TYPE,
856            c_balance_name      in pay_balance_types.balance_name%TYPE
857          ) is
858   select decode(pbt.balance_name,
859     'CPF Ordinary Earnings Eligible Comp', 'O',
860     'CPF Additional Earnings Eligible Comp', 'A', ' ')
861     from pay_balance_types pbt,
862            pay_balance_feeds_f pbf,
863            pay_input_values_f pivf,
864            pay_element_types_f petf
865     where pbt.balance_type_id = pbf.balance_type_id
866     and   pbf.input_value_id = pivf.input_value_id
867     and   pivf.element_type_id = petf.element_type_id
868     and   pbt.balance_name = c_balance_name
869     and   petf.element_type_id = c_element_type_id;
870 
871 l_earnings_type   varchar2(10);
872 l_balance_name    pay_balance_types.balance_name%TYPE;
873 
874 begin
875   l_earnings_type  := ' ';
876   hr_utility.set_location('Entering Earnings Type : ', 5);
877   hr_utility.set_location('Element Type Id : ' || p_element_type_id, 10);
878 
879   l_balance_name := 'CPF Ordinary Earnings Eligible Comp';
880   open c_earnings_type(p_element_type_id, l_balance_name);
881   fetch c_earnings_type into l_earnings_type;
882   close c_earnings_type;
883 
884   if l_earnings_type <> 'O' then
885      l_balance_name := 'CPF Additional Earnings Eligible Comp';
886      open c_earnings_type(p_element_type_id, l_balance_name);
887      fetch c_earnings_type into l_earnings_type;
888      close c_earnings_type;
889   end if;
890 
891   hr_utility.set_location('Earnings Type : ' || l_earnings_type, 15);
892 
893   return l_earnings_type;
894 
895   EXCEPTION
896     when others then
897       l_earnings_type := ' ';
898       hr_utility.set_location('Exception Earnings Type : ', 20);
899 
900 end earnings_type;
901 ---------------------------------------------------------------------------
902 -- Function returns Previous Year Ordinary Earnings total with
903 -- Monthly ceiling of 5,500
904 ---------------------------------------------------------------------------
905 function get_prev_year_ord_ytd
906         (
907            p_assignment_id   in pay_assignment_actions.assignment_id%TYPE,
908            p_date_earned     in pay_payroll_actions.date_earned%TYPE
909         )
910 return number is
911     --
912     cursor c_tax_unit_id( c_assignment_id number,
913                           c_assignment_action_id pay_assignment_actions.assignment_action_id%TYPE)
914     is
915     select paa.tax_unit_id
916       from pay_assignment_actions paa
920     --------------------------------------------------------------------
917      where paa.assignment_id = c_assignment_id
918        and paa.assignment_action_id = c_assignment_action_id;
919     --
921     -- Bug 5298298, need to get action sequence to include all the assignment
922     -- for the re-hire employee, it will include the original assignment. For
923     -- multi-assignments with the same LE will be included.
924     --------------------------------------------------------------------
925     cursor c_month_year_action_sequence( c_assignment_id number,
926  			                 c_date_earned   date )
927     is
928     select  max(paa.action_sequence),
929             to_number(to_char(ppa.effective_date,'MM')),
930             max(pas.person_id)
931       from  per_assignments_f  pas,
932             pay_assignment_actions paa,
933             pay_payroll_actions ppa
934      where  (pas.person_id, paa.tax_unit_id)
935                    IN (select pas1.person_id,
936                              hsc1.segment1
937                       from   per_assignments_f  pas1,
938                              hr_soft_coding_keyflex hsc1
939                       where  pas1.assignment_id     = c_assignment_id
940                       and    pas1.soft_coding_keyflex_id = hsc1.soft_coding_keyflex_id
941                       and    c_date_earned between pas1.effective_start_date and pas1.effective_end_date) /* Bug 5298298 */
942        and  pas.assignment_id = paa.assignment_id
943        and  ppa.payroll_action_id = paa.payroll_action_id
944        and  ppa.action_type       in ('R','Q','B','V','I')
945        and  ppa.effective_date       between trunc(add_months(c_date_earned,-12),'Y') /* Bug 4267196 */
946                                       and trunc(c_date_earned,'Y') - 1
947      group by  to_number(to_char(ppa.effective_date,'MM'))
948      order by  to_number(to_char(ppa.effective_date,'MM')) desc;
949     --
950     cursor c_month_year_action ( c_person_id       number,
951  			         c_date_earned     date,
952                                  c_action_sequence number )
953     is
954     select  paa.assignment_action_id,
955             ppa.effective_date,
956             paa.assignment_id
957       from  per_assignments_f pas,
958             pay_assignment_actions paa,
959             pay_payroll_actions ppa
960      where  pas.person_id = c_person_id /* Bug 5298298 */
961        and  paa.assignment_id = pas.assignment_id
962        and  ppa.payroll_action_id = paa.payroll_action_id
963        and  paa.action_sequence   = c_action_sequence
964        and  ppa.effective_date between trunc(add_months(c_date_earned,-12),'Y') /* Bug 4267196 */
965                                 and trunc(c_date_earned,'Y') - 1;
966     --
967     cursor c_defined_bal_id ( p_balance_name   in varchar2,
968                               p_dimension_name in varchar2 )
969         is
970     select  pdb.defined_balance_id
971       from  pay_defined_balances pdb,
972             pay_balance_types pbt,
973             pay_balance_dimensions pbd
974      where  pbt.balance_name         = p_balance_name
975        and  pbd.dimension_name       = p_dimension_name
976        and  pbt.balance_type_id      = pdb.balance_type_id
977        and  pdb.balance_dimension_id = pbd.balance_dimension_id
978        and  pdb.legislation_code = 'SG';
979     --
980     cursor c_globals
981         is
982     select global_value
983       from ff_globals_f
984      where global_name = 'CPF_ORD_MONTH_CAP_AMT'
985        and p_date_earned between effective_start_date and effective_end_date;
986     --
987     g_balance_value_tab    pay_balance_pkg.t_balance_value_tab;
988     g_context_tab          pay_balance_pkg.t_context_tab;
989     g_detailed_bal_out_tab pay_balance_pkg.t_detailed_bal_out_tab;
990     --
991     l_assignment_action_id   pay_assignment_actions.assignment_action_id%TYPE;
992     l_action_sequence        pay_assignment_actions.action_sequence%TYPE;
993     l_assignment_id          pay_assignment_actions.assignment_id%TYPE;
994     l_person_id              per_assignments_f.person_id%TYPE;
995     l_month                  number;
996     l_effective_date         date;
997     l_tax_unit_id            pay_assignment_actions.tax_unit_id%TYPE;
998     l_defined_bal_id         number;
999     l_prev_ord_ytd           number;
1000     l_ord_mon_cap_amt        number;
1001     l_retro_exist            boolean := FALSE ;
1002     l_retro_ele              number;
1003     l_retro_date             date;
1004 begin
1005     l_prev_ord_ytd := 0;
1006     --
1007     open c_globals;
1008     fetch c_globals into l_ord_mon_cap_amt;
1009     close c_globals ;
1010     --
1011     g_balance_value_tab.delete;
1012     --
1013     open c_defined_bal_id('CPF Ordinary Earnings Eligible Comp','_PER_LE_MONTH');
1014     fetch c_defined_bal_id into g_balance_value_tab(1).defined_balance_id;
1015     close c_defined_bal_id;
1016     --
1017     open c_defined_bal_id('Ordinary Earnings ineligible for CPF','_PER_LE_MONTH');
1018     fetch c_defined_bal_id into g_balance_value_tab(2).defined_balance_id;
1019     close c_defined_bal_id;
1020     --
1021     open c_defined_bal_id('Retro Ord Retro Period','_ASG_PTD');
1022     fetch c_defined_bal_id into g_balance_value_tab(3).defined_balance_id;
1023     close c_defined_bal_id;
1024     --
1025     open c_month_year_action_sequence( p_assignment_id, p_date_earned );
1026     loop
1030          --
1027          fetch c_month_year_action_sequence into l_action_sequence,l_month,l_person_id;
1028 
1029          exit when c_month_year_action_sequence%NOTFOUND;
1031          open c_month_year_action( l_person_id, p_date_earned, l_action_sequence );
1032          fetch c_month_year_action into l_assignment_action_id,l_effective_date,l_assignment_id;
1033 
1034          --
1035          if c_month_year_action%FOUND then
1036               open c_tax_unit_id(l_assignment_id , l_assignment_action_id );
1037               fetch c_tax_unit_id into l_tax_unit_id;
1038               close c_tax_unit_id;
1039               --
1040               g_context_tab.delete;
1041               g_detailed_bal_out_tab.delete;
1042               --
1043               g_context_tab(1).tax_unit_id := l_tax_unit_id;
1044               g_context_tab(2).tax_unit_id := l_tax_unit_id;
1045               g_context_tab(3).tax_unit_id := l_tax_unit_id;
1046               --
1047               pay_balance_pkg.get_value ( l_assignment_action_id,
1048                                           g_balance_value_tab,
1049                                           g_context_tab,
1050                                           false,
1051                                           false,
1052                                           g_detailed_bal_out_tab
1053                                         );
1054               --
1055               if l_retro_exist
1056                 or nvl(g_detailed_bal_out_tab(3).balance_value,0) <> 0  then /* Bug 6815874 */
1057                     l_retro_ele   := get_retro_earnings( p_assignment_id , l_effective_date ); /* Bug 6815874 */
1058                     if l_retro_ele = 0 then /* Bug 6815874 */
1059                         l_retro_exist := FALSE;
1060                     end if;
1061                     l_prev_ord_ytd := l_prev_ord_ytd + least( (nvl( g_detailed_bal_out_tab(1).balance_value,0 )
1062                                                            - nvl( g_detailed_bal_out_tab(2).balance_value,0 )
1063                                                            - nvl( g_detailed_bal_out_tab(3).balance_value,0 )
1064                                                            + nvl(l_retro_ele,0)),l_ord_mon_cap_amt );
1065               else
1066                     l_prev_ord_ytd := l_prev_ord_ytd + least( (nvl( g_detailed_bal_out_tab(1).balance_value,0 )
1067                                                            - nvl( g_detailed_bal_out_tab(2).balance_value,0 )
1068                                                            - nvl( g_detailed_bal_out_tab(3).balance_value,0 )),l_ord_mon_cap_amt );
1069               end if;
1070               --
1071               if nvl( g_detailed_bal_out_tab(3).balance_value,0 ) <> 0 then
1072                   l_retro_exist := TRUE;
1073               end if;
1074               --
1075          end if;
1076          --
1077          close c_month_year_action;
1078     end loop;
1079     --
1080     close c_month_year_action_sequence;
1081     --
1082     return l_prev_ord_ytd;
1083     --
1084 end get_prev_year_ord_ytd;
1085 
1086 ---------------------------------------------------------------------------
1087 -- Function returns Current Year Ordinary Earnings total with
1088 -- Monthly ceiling of 5,500
1089 ---------------------------------------------------------------------------
1090 function get_cur_year_ord_ytd
1091         (
1092            p_assignment_id   in pay_assignment_actions.assignment_id%TYPE,
1093            p_date_earned     in pay_payroll_actions.date_earned%TYPE
1094         )
1095 return number is
1096     --
1097     cursor c_tax_unit_id( c_assignment_id number,
1098                           c_assignment_action_id pay_assignment_actions.assignment_action_id%TYPE)
1099     is
1100     select paa.tax_unit_id
1101       from pay_assignment_actions paa
1102      where paa.assignment_id = c_assignment_id
1103        and paa.assignment_action_id = c_assignment_action_id;
1104     --
1105     --------------------------------------------------------------------
1106     -- Bug 5298298, need to get action sequence to include all the assignment
1107     -- for the re-hire employee, it will include the original assignment. For
1108     -- multi-assignments with the same LE will be included.
1109     --------------------------------------------------------------------
1110     cursor c_month_year_action_sequence( c_assignment_id number,
1111  			                 c_date_earned   date )
1112     is
1113     select  max(paa.action_sequence),
1114             to_number(to_char(ppa.effective_date,'MM')),
1115             max(pas.person_id)
1116       from  per_assignments_f pas,
1117             pay_assignment_actions paa,
1118             pay_payroll_actions ppa
1119      where  (pas.person_id, paa.tax_unit_id)
1120                   IN (select pas1.person_id,
1121                              hsc1.segment1
1122                       from   per_assignments_f  pas1,
1123                              hr_soft_coding_keyflex hsc1
1124                       where  pas1.assignment_id     = c_assignment_id
1125                       and    pas1.soft_coding_keyflex_id = hsc1.soft_coding_keyflex_id
1126                       and    c_date_earned between pas1.effective_start_date and pas1.effective_end_date) /* Bug 5298298 */
1127        and  pas.assignment_id = paa.assignment_id
1128        and  ppa.payroll_action_id = paa.payroll_action_id
1129        and  ppa.action_type       in ('R','Q','B','V','I')
1133      order by  to_number(to_char(ppa.effective_date,'MM')) desc;
1130        and  ppa.effective_date between trunc(c_date_earned,'Y') /* Bug 4267196 */
1131                                 and last_day(add_months(c_date_earned,-1))
1132      group by  to_number(to_char(ppa.effective_date,'MM'))
1134     --
1135     cursor c_month_year_action ( c_person_id   number,
1136  			         c_date_earned     date,
1137                                  c_action_sequence number )
1138     is
1139     select  paa.assignment_action_id,
1140             ppa.effective_date,
1141             pas.assignment_id
1142       from  per_assignments_f pas,
1143             pay_assignment_actions paa,
1144             pay_payroll_actions ppa
1145      where  pas.person_id = c_person_id /* Bug 5298298 */
1146        and  paa.assignment_id = pas.assignment_id
1147        and  ppa.payroll_action_id = paa.payroll_action_id
1148        and  paa.action_sequence   = c_action_sequence
1149        and  ppa.effective_date between trunc(c_date_earned,'Y') /* Bug 4267196 */
1150                                 and last_day(add_months(c_date_earned,-1)) ;
1151     --
1152     cursor c_defined_bal_id ( p_balance_name   in varchar2,
1153                               p_dimension_name in varchar2 )
1154         is
1155     select  pdb.defined_balance_id
1156       from  pay_defined_balances pdb,
1157             pay_balance_types pbt,
1158             pay_balance_dimensions pbd
1159      where  pbt.balance_name         = p_balance_name
1160        and  pbd.dimension_name       = p_dimension_name
1161        and  pbt.balance_type_id      = pdb.balance_type_id
1162        and  pdb.balance_dimension_id = pbd.balance_dimension_id
1163        and  pdb.legislation_code = 'SG';
1164     --
1165     cursor c_globals
1166         is
1167     select global_value
1168       from ff_globals_f
1169      where global_name = 'CPF_ORD_MONTH_CAP_AMT'
1170        and p_date_earned between effective_start_date and effective_end_date;
1171     --
1172     g_balance_value_tab      pay_balance_pkg.t_balance_value_tab;
1173     g_context_tab            pay_balance_pkg.t_context_tab;
1174     g_detailed_bal_out_tab   pay_balance_pkg.t_detailed_bal_out_tab;
1175     --
1176     l_assignment_action_id   pay_assignment_actions.assignment_action_id%TYPE;
1177     l_action_sequence        pay_assignment_actions.action_sequence%TYPE;
1178     l_assignment_id          pay_assignment_actions.assignment_id%TYPE;
1179     l_person_id              per_assignments_f.person_id%TYPE;
1180     l_month                  number;
1181     l_effective_date         date;
1182     l_tax_unit_id            pay_assignment_actions.tax_unit_id%TYPE;
1183     l_defined_bal_id         number;
1184     l_cur_ord_ytd            number;
1185     l_ord_mon_cap_amt        number;
1186     l_retro_exist            boolean := FALSE ;
1187     l_retro_ele              number;
1188     l_retro_date             date;
1189 begin
1190     l_cur_ord_ytd := 0;
1191     --
1192     open c_globals;
1193     fetch c_globals into l_ord_mon_cap_amt;
1194     close c_globals ;
1195     --
1196     g_balance_value_tab.delete;
1197     --
1198     open c_defined_bal_id('CPF Ordinary Earnings Eligible Comp','_PER_LE_MONTH');
1199     fetch c_defined_bal_id into g_balance_value_tab(1).defined_balance_id;
1200     close c_defined_bal_id;
1201     --
1202     open c_defined_bal_id('Ordinary Earnings ineligible for CPF','_PER_LE_MONTH');
1203     fetch c_defined_bal_id into g_balance_value_tab(2).defined_balance_id;
1204     close c_defined_bal_id;
1205     --
1206     open c_defined_bal_id('Retro Ord Retro Period','_ASG_PTD');
1207     fetch c_defined_bal_id into g_balance_value_tab(3).defined_balance_id;
1208     close c_defined_bal_id;
1209     --
1210     open c_month_year_action_sequence( p_assignment_id, p_date_earned );
1211     loop
1212          fetch c_month_year_action_sequence into l_action_sequence,l_month,l_person_id;
1213          exit when c_month_year_action_sequence%NOTFOUND;
1214          --
1215          open c_month_year_action( l_person_id, p_date_earned, l_action_sequence );
1216          fetch c_month_year_action into l_assignment_action_id,l_effective_date,l_assignment_id;
1217          --
1218          if c_month_year_action%FOUND then
1219               open c_tax_unit_id( l_assignment_id, l_assignment_action_id );
1220               fetch c_tax_unit_id into l_tax_unit_id;
1221               close c_tax_unit_id;
1222               --
1223               g_context_tab.delete;
1224               g_detailed_bal_out_tab.delete;
1225               --
1226               g_context_tab(1).tax_unit_id := l_tax_unit_id;
1227               g_context_tab(2).tax_unit_id := l_tax_unit_id;
1228               g_context_tab(3).tax_unit_id := l_tax_unit_id;
1229               --
1230               pay_balance_pkg.get_value ( l_assignment_action_id,
1231                                           g_balance_value_tab,
1232                                           g_context_tab,
1233                                           false,
1234                                           false,
1235                                           g_detailed_bal_out_tab
1236                                         );
1237               --
1238               if l_retro_exist
1239                   or nvl(g_detailed_bal_out_tab(3).balance_value,0) <> 0 then /* Bug 6815874 */
1240                     l_retro_ele   := get_retro_earnings( p_assignment_id , l_effective_date );  /* Bug 6815874 */
1244                     l_cur_ord_ytd := l_cur_ord_ytd + least( (nvl( g_detailed_bal_out_tab(1).balance_value,0 )
1241                     if l_retro_ele = 0 then /* Bug 6815874 */
1242                       l_retro_exist := FALSE;
1243                     end if;
1245                                                            - nvl( g_detailed_bal_out_tab(2).balance_value,0 )
1246                                                            - nvl( g_detailed_bal_out_tab(3).balance_value,0 )
1247                                                            + nvl(l_retro_ele,0)),l_ord_mon_cap_amt );
1248               else
1249                     l_cur_ord_ytd := l_cur_ord_ytd + least( (nvl( g_detailed_bal_out_tab(1).balance_value,0 )
1250                                                            - nvl( g_detailed_bal_out_tab(2).balance_value,0 )
1251                                                            - nvl( g_detailed_bal_out_tab(3).balance_value,0 )),l_ord_mon_cap_amt );
1252               end if;
1253               --
1254               if nvl( g_detailed_bal_out_tab(3).balance_value,0 ) <> 0 then
1255                   l_retro_exist := TRUE;
1256               end if;
1257 
1258               --
1259          end if;
1260          --
1261          close c_month_year_action;
1262     end loop;
1263     --
1264     close c_month_year_action_sequence;
1265     --
1266     return l_cur_ord_ytd;
1267     --
1268 end get_cur_year_ord_ytd;
1269 --
1270 function get_retro_earnings( p_assignment_id   in pay_assignment_actions.assignment_id%TYPE,
1271                              p_date_earned     in date ) return number
1272 is
1273   cursor c_pay_element_entries
1274       is
1275   select sum(peev.screen_entry_value)
1276     from pay_element_entry_values_f peev,
1277          pay_element_entries_f pee,
1278          pay_element_types_f pet,
1279          pay_input_values_f piv,
1280          pay_element_classifications pec
1281    where pee.assignment_id         = p_assignment_id
1282      and pee.source_asg_action_id in
1283           (select   paa1.assignment_action_id
1284              from   pay_assignment_actions paa1,
1285                     pay_payroll_actions ppa1
1286             where   paa1.assignment_id = pee.assignment_id
1287               and   ppa1.payroll_action_id = paa1.payroll_action_id
1288               and   ppa1.action_type       in ('R','Q','B','V','I')
1289               and   to_char(ppa1.effective_date,'MM') = to_char(p_date_earned,'MM'))
1290      and pee.creator_type in ('EE','RR')
1291      and pee.element_type_id       = pet.element_type_id
1292      and pet.classification_id     = pec.classification_id
1293      and pec.classification_name   = 'Ordinary Earnings'
1294      and pec.legislation_code      = 'SG'
1295      and pee.element_entry_id      = peev.element_entry_id
1296      and peev.input_value_id       = piv.input_value_id
1297      and piv.name                  = 'Pay Value'
1298      and p_date_earned between pee.source_start_date
1299                            and pee.source_end_date
1300      and p_date_earned between pet.effective_start_date
1301                            and pet.effective_end_date
1302      and p_date_earned between piv.effective_start_date
1303                            and piv.effective_end_date   ;
1304   --
1305   l_retro_value  number;
1306 begin
1307   open  c_pay_element_entries;
1308   fetch c_pay_element_entries into l_retro_value;
1309   close c_pay_element_entries ;
1310   --
1311   return l_retro_value;
1312   --
1313 end get_retro_earnings;
1314 
1315 /*****************************************
1316    CPF Report section : bugno 2475324
1317 *****************************************/
1318 
1319 /* Initialize all the contexts required for SG_STAT*/
1320 Procedure init_formula (p_formula_name in varchar2,
1321                             p_effective_date in date ) is
1322 --
1323 l_effective_date        date;
1324 l_start_date            date;
1325 l_formula_id            number;
1326 --
1327 cursor c_formula_id (c_formula_name varchar2, c_effective_date date)  is
1328 select formula_id, effective_start_date
1329 from   ff_formulas_f
1330 where  formula_name = c_formula_name
1331 and    legislation_code = 'SG'
1332 and    c_effective_date between effective_start_date and effective_end_date;
1333 
1334 Begin
1335    l_effective_date  :=  to_date('1-10-2003','dd-mm-yyyy');
1336    l_start_date      :=  to_date('1-10-2003','dd-mm-yyyy');
1337 
1338    /* This function call returns -1 if the formula was not found */
1339    hr_utility.set_location('Starting init',5);
1340    hr_utility.trace('Formula_id:'||l_formula_id);
1341 
1342    open c_formula_id(p_formula_name, p_effective_date);
1343    fetch c_formula_id into l_formula_id, l_start_date;
1344    if c_formula_id%NOTFOUND then
1345       close c_formula_id;
1346    else
1347 
1348    hr_utility.trace('Formula_id:'||l_formula_id);
1349    ff_exec.init_formula (l_formula_id,
1350                          l_start_date,
1351                          g_inputs,
1352                          g_outputs);
1353    end if;
1354     --
1355    hr_utility.set_location('Leaving init',10);
1356 
1357 End init_formula;
1358 
1359 Function calc_cpf_add_YTD  (p_date_earned          in date
1360                              ,p_assignment_id      in number
1361                              ,p_process_type       in varchar2
1362                              ,p_tax_unit_id        in number
1363                              ,p_asg_action_id      in number
1367                              ,p_balance_date       in date
1364                              ,p_business_group_id  in number
1365                              ,p_payroll_action_id  in number
1366                              ,p_payroll_id         in number
1368                            ) return number is
1369 
1370 l_cpf_add_YTD  number;
1371 
1372 Begin
1373   --
1374   hr_utility.set_location('Entering get_bal',7);
1375   --
1376   init_formula('SG_STAT',p_date_earned);
1377   --
1378   -- Set up contexts for the formula
1379   for i in g_inputs.first..g_inputs.last loop
1380       --
1381 
1382       if g_inputs(i).name = 'DATE_EARNED' then
1383          hr_utility.trace('setting date earned '||p_date_earned);
1384          g_inputs(i).value := fnd_date.date_to_canonical(p_date_earned);
1385       elsif g_inputs(i).name = 'ASSIGNMENT_ID' then
1386          g_inputs(i).value := p_assignment_id;
1387       elsif g_inputs(i).name = 'SOURCE_TEXT' then
1388          hr_utility.trace('setting source text '||p_process_type);
1389          g_inputs(i).value := p_process_type;
1390       elsif g_inputs(i).name = 'PROCESS_TYPE' then
1391          g_inputs(i).value := p_process_type;
1392       elsif g_inputs(i).name = 'TAX_UNIT_ID' then
1393          g_inputs(i).value := p_tax_unit_id;
1394       elsif g_inputs(i).name = 'ASSIGNMENT_ACTION_ID' then
1395          g_inputs(i).value := p_asg_action_id;
1396       elsif g_inputs(i).name = 'BUSINESS_GROUP_ID' then
1397          g_inputs(i).value := p_business_group_id;
1398       elsif g_inputs(i).name = 'PAYROLL_ACTION_ID' then
1399          g_inputs(i).value := p_payroll_action_id;
1400       elsif g_inputs(i).name = 'PAYROLL_ID' then
1401          g_inputs(i).value := p_payroll_id;
1402       elsif g_inputs(i).name = 'BALANCE_DATE' then
1403          g_inputs(i).value := fnd_date.date_to_canonical(p_balance_date);
1404       else
1405          hr_utility.set_location('ERROR value = '||g_inputs(i).name ,7);
1406       end if;
1407       --
1408       hr_utility.trace('g_inputs(i).name : '||g_inputs(i).name);
1409       hr_utility.trace('g_inputs(i).value : '||g_inputs(i).value);
1410   end loop;
1411   --
1412   -- Run the formula
1413   --
1414   hr_utility.set_location('Prior to execute the formula',8);
1415   ff_exec.run_formula (g_inputs ,
1416                        g_outputs  );
1417   --
1418   hr_utility.set_location('End run formula',9);
1419   --
1420   for l_out_cnt in g_outputs.first..g_outputs.last loop
1421       -- only store the output of L_CPF_ADD_CALC_YEAR , ignoe others
1422       if g_outputs(l_out_cnt).name = 'L_CPF_ADD_CALC_YEAR'  then
1423         l_cpf_add_YTD  :=  g_outputs(l_out_cnt).value;
1424         hr_utility.trace('l_cpf_add_YTD:'|| g_outputs(l_out_cnt).value);
1425       end if;
1426       --
1427       hr_utility.trace('Outputs:'||g_outputs(l_out_cnt).name);
1428       hr_utility.trace('Outputs(values):'||g_outputs(l_out_cnt).value);
1429   end loop;
1430   --
1431   return l_cpf_add_YTD;
1432     --
1433 End calc_cpf_add_YTD;
1434 /* End of Function */
1435 
1436 /* Returns whether the SG_STAT is called from the REPORT or PAYROLL Run*/
1437 Function get_SG_STAT_CALLED_FROM return varchar2
1438 is
1439 begin
1440   return g_sgstat_called_from;
1441 end;
1442 
1443 /* In the before report trigger of PAYSGCPF the global g_sgstat_called_from
1444  is set to REPORT*/
1445 
1446 procedure set_SG_STAT_CALLED_FROM (p_running in varchar2)
1447 is
1448 begin
1449   g_sgstat_called_from := p_running;
1450 end;
1451 
1452 /* Populates the pl/sql table with assignment id and difference of CPF paid (values of the balances)
1453  and calculated CPF from SG_STAT with SAEOY*/
1454 
1455 procedure populate_cpf_table (p_person_id in number,
1456                               p_cpf_diff number ) is
1457 l_person_id binary_integer;
1458 begin
1459        l_person_id:= p_person_id;
1460        cpf_inputs_t(l_person_id).person_id:= p_person_id;
1461        cpf_inputs_t(l_person_id).cpf_diff := p_cpf_diff;
1462 end;
1463 
1464 /* If the assignment exists in the cpf pl/sql table (populated by populate_cpf_table)
1465 ,return 1 else 0. Used in the where clause of the report query*/
1466 
1467 function get_assignment_from_cpf_table(p_person_id in number) return number is
1468 l_person_id binary_integer;
1469 begin
1470       l_person_id:= p_person_id;
1471       if cpf_inputs_t.exists(l_person_id) then
1472          if (cpf_inputs_t(l_person_id).person_id=  p_person_id) then
1473             return (1);
1474          end if;
1475       end if;
1476       return (0);
1477 end;
1478 
1479 /* Get the overpaid value for the assignment passed from the pl/sql table populated by
1480 populate_cpf_table above*/
1481 function get_cpf_difference(p_person_id in number) return number is
1482 l_cpf_diff number;
1483 l_person_id binary_integer;
1484 begin
1485    l_cpf_diff := 0;
1486    l_person_id:= p_person_id;
1487    if cpf_inputs_t.exists(l_person_id) then
1488       if (cpf_inputs_t(l_person_id).person_id= p_person_id) then
1489          l_cpf_diff := cpf_inputs_t(l_person_id).cpf_diff;
1490       end if;
1491    end  if;
1492    return l_cpf_diff;
1493 end;
1494 
1495 /* Return last date of the year (stored in g_year_end_date_for_cpf_report)
1496 , used in the SG_STAT*/
1497 
1498 function GET_YEAR_END_DATE return date is
1499 begin
1500    return g_year_end_date_for_cpf_report;
1501 end;
1502 
1503 /* set the g_year_end_date_for_cpf_report as the last date of the year*/
1504 procedure set_year_end_date(p_year_end_date in date) is
1505 begin
1506    g_year_end_date_for_cpf_report := p_year_end_date;
1507 end;
1508 
1509 begin
1510 
1511    g_sgstat_called_from := 'PAYROLL';
1512 
1513 end pay_sg_deductions;