DBA Data[Home] [Help]

PACKAGE BODY: APPS.PER_UTILITY_FUNCTIONS

Source


1 package body per_utility_functions as
2 /* $Header: peutlfnc.pkb 120.7.12020000.4 2013/01/16 18:07:52 srannama ship $ */
3 --
4 g_package  varchar2(33) := '  per_utility_functions.';  -- Global package name
5 --
6 
7 TYPE global_id_table is TABLE OF number INDEX BY BINARY_INTEGER;
8 
9 g_element_entries global_id_table;
10 --
11 -- 3267975 >>
12 g_legcode_cache             HR_ORGANIZATION_INFORMATION.org_information9%TYPE;
13 g_legcode_cached            boolean := FALSE;
14 --
15 g_reset_pto_accruals        varchar2(10) := 'FALSE';
16 g_reset_pto_cache           boolean := false;
17 --
18 TYPE number_tbl        is TABLE OF NUMBER INDEX BY BINARY_INTEGER;
19 TYPE prmValue_type_tbl is TABLE OF PAY_ACTION_PARAMETER_VALUES.parameter_value%TYPE
20                                    INDEX BY BINARY_INTEGER;
21 TYPE prmName_type_tbl  is TABLE OF PAY_ACTION_PARAMETER_VALUES.parameter_name%TYPE
22                                    INDEX BY BINARY_INTEGER;
23 --
24 TYPE action_prm_cache_r is RECORD
25 (
26  parameter_name      prmName_type_tbl,
27  parameter_value     prmValue_type_tbl,
28  sz                  number
29 );
30 
31 g_actionPrm_cache          action_prm_cache_r;
32 g_actionPrm_cached         boolean := FALSE;
33 --
34 --
35 TYPE varchar_80_tbl is TABLE OF VARCHAR2(80) INDEX BY BINARY_INTEGER;
36 --
37 TYPE event_group_cache_r is RECORD
38 (
39  event_group_id         number_tbl,
40  event_group_name       varchar_80_tbl,
41  business_group_id      number_tbl,
42  legislation_code       varchar_80_tbl,
43  sz                     number
44 );
45 
46 g_events_cache          event_group_cache_r;
47 g_events_cached         boolean := FALSE;
48 --
49 --
50 /* =====================================================================
51    Name    : Get_Payroll_Period
52    Purpose : To determine the payroll period spanning a given date and
53              to set global variables containg the start and end dates and the
54              period number
55    Returns : 0 if successful, 1 otherwise
56    ---------------------------------------------------------------------*/
57 function Get_Payroll_Period
58 (P_Payroll_ID                     IN  Number
59 ,P_Date_In_Period                 IN  Date) return number IS
60 --
61 l_proc        varchar2(72) := g_package||'Get_Payroll_Period';
62 --
63 cursor csr_get_payroll_period is
64 select start_date
65 ,      end_date
66 ,      period_num
67 from   per_time_periods
68 where  payroll_id = P_Payroll_ID
69 and    P_Date_In_Period between start_date and end_date;
70 --
71 l_start_date date;
72 l_end_date   date;
73 l_period_number number;
74 --
75 l_error number;
76 --
77 begin
78    hr_utility.set_location(l_proc, 5);
79    --
80    open csr_get_payroll_period;
81    fetch csr_get_payroll_period into l_start_date,l_end_date,l_period_number;
82    if csr_get_payroll_period%notfound then
83       close csr_get_payroll_period;
84       hr_utility.set_location('Payroll Period not found '||l_proc, 10);
85       l_error := per_formula_functions.raise_error(800, 'HR_52798_PTO_PAYROLL_INVALID');
86       return 1;
87    end if;
88    close csr_get_payroll_period;
89    --
90    l_error := per_formula_functions.set_date
91                  ('PAYROLL_PERIOD_START_DATE',l_start_date);
92    l_error := per_formula_functions.set_date
93                  ('PAYROLL_PERIOD_END_DATE',l_end_date);
94    l_error := per_formula_functions.set_number
95                  ('PAYROLL_PERIOD_NUMBER',l_period_number);
96    --
97    hr_utility.set_location(l_proc, 15);
98    return 0;
99 end Get_Payroll_Period;
100 --
101 /* =====================================================================
102    Name    : Get_Accrual_Band
103    Purpose : To determine the accrual band that spans the specified number of
104              years and to set global variables containing the ANNUAL_RATE,
105              UPPER_LIMIT and CEILING values.
106    Returns : 0 if successful, 1 otherwise
107    ---------------------------------------------------------------------*/
108 function Get_Accrual_Band
109 (P_Plan_ID                        IN  Number
110 ,P_Number_Of_Years                IN  Number) return number IS
111 --
112 l_proc        varchar2(72) := g_package||'Get_Accrual_Band';
113 --
114 --
115 cursor csr_get_accrual_band is
116 select annual_rate
117 ,      upper_limit
118 ,      nvl(ceiling, 99999999)
119 ,      nvl(max_carry_over, 99999999)
120 from   pay_accrual_bands
121 where  P_Number_Of_Years >= lower_limit
122 and    P_Number_Of_Years <  upper_limit
123 and    accrual_plan_id = P_Plan_ID;
124 --
125 l_annual_rate number;
126 l_upper_limit number;
127 l_ceiling     number;
128 l_max_carry_over number;
129 --
130 l_error number;
131 --
132 begin
133    hr_utility.set_location(l_proc, 5);
134    l_annual_rate := 0;
135    l_upper_limit := 0;
136    l_ceiling     := 0;
137    l_max_carry_over := 0;
138    --
139    open csr_get_accrual_band;
140    fetch csr_get_accrual_band into l_annual_rate,
141                                    l_upper_limit,
142                                    l_ceiling,
143 				   l_max_carry_over;
144    if csr_get_accrual_band%notfound then
145       hr_utility.set_location(l_proc, 10);
146       return 1;
147    end if;
148    close csr_get_accrual_band;
149    --
150    l_error := per_formula_functions.set_number('ANNUAL_RATE',l_annual_rate);
151    l_error := per_formula_functions.set_number('UPPER_LIMIT',l_upper_limit);
152    l_error := per_formula_functions.set_number('CEILING'    ,l_ceiling);
153    l_error := per_formula_functions.set_number('MAX_CARRY_OVER',l_max_carry_over);
154    --
155    hr_utility.set_location(l_proc, 15);
156    return 0;
157 exception
158    when others then
159         hr_utility.set_location(l_proc, 20);
160         return 1;
161 end Get_Accrual_Band;
162 --
163 /* =====================================================================
164    Name    : Get_Period_Dates
165    Purpose : To determine the start and end dates of a period of time that
166              spans a given date, which is of a given duration (e.g. Month) and
167              which is a mulitple of that duration from a given Start date
168              (e.g. 6 months on from 01/01/90)
169              The globals PERIOD_START_DATE and PERIOD_END_DATE are populated
170    Returns : 0 if successful, 1 otherwise
171    ---------------------------------------------------------------------*/
172 function Get_Period_Dates
173 (P_Date_In_Period                 IN  Date
174 ,P_Period_Unit                    IN  Varchar2
175 ,P_Base_Start_Date                IN  Date
176 ,P_Unit_Multiplier                IN  Number) RETURN Number IS
177 --
178 l_proc        varchar2(72) := g_package||'Get_Period_Dates';
179 --
180 l_start_date    date;
181 l_end_date      date;
182 l_error         number;
183 l_months        number;
184 --
185 begin
186 
187    hr_utility.set_location(l_proc, 5);
188 
189    if P_Date_In_Period >= P_Base_Start_Date then
190    --
191      l_start_date := P_Base_Start_Date;
192      l_months := P_Unit_Multiplier;
193 
194      while true loop
195       --
196       if p_period_unit = 'M' then
197          l_end_date := add_months(P_Base_Start_Date, l_months) - 1;
198          l_start_date := add_months(P_Base_Start_Date, (l_months - P_Unit_Multiplier));
199          l_months := l_months + P_Unit_Multiplier;
200       elsif p_period_unit = 'W' then
201          l_end_date := l_start_date + (7*p_unit_multiplier) - 1;
202       elsif p_period_unit = 'D' then
203 	 l_end_date := l_start_date + p_unit_multiplier - 1;
204       end if;
205       --
206       if P_Date_In_Period between l_start_date and l_end_date then
207          l_error := per_formula_functions.set_date
208                         ('PERIOD_START_DATE',l_start_date);
209          l_error := per_formula_functions.set_date
210                         ('PERIOD_END_DATE',l_end_date);
211          exit;
212       else
213          l_start_date := l_end_date + 1;
214       end if;
215      --
216      end loop;
217    --
218    else
219    --
220      l_end_date := P_Base_Start_Date - 1;
221      l_months := P_Unit_Multiplier * -1;
222 
223      while true loop
224       --
225       if p_period_unit = 'M' then
226         l_end_date := add_months(P_Base_Start_Date, (l_months + P_Unit_Multiplier)) - 1;
227         l_start_date := add_months(P_Base_Start_Date, l_months);
228         l_months := l_months - P_Unit_Multiplier;
229       elsif p_period_unit = 'W' then
230          l_start_date := l_end_date - (7*p_unit_multiplier) + 1;
231       elsif p_period_unit = 'D' then
232 	 l_start_date := l_end_date - p_unit_multiplier + 1;
233       end if;
234       --
235       if P_Date_In_Period between l_start_date and l_end_date then
236          l_error := per_formula_functions.set_date
237                         ('PERIOD_START_DATE',l_start_date);
238          l_error := per_formula_functions.set_date
239                         ('PERIOD_END_DATE',l_end_date);
240          exit;
241       else
242          l_end_date := l_start_date - 1;
243       end if;
244      --
245      end loop;
246    --
247    end if;
248 
249    hr_utility.set_location(l_proc, 10);
250    return 0;
251 exception
252    when others then
253         hr_utility.set_location(l_proc, 15);
254         return 1;
255 end Get_Period_Dates;
256 
257 -- Fix for the bug 13935707
258 
259 function Get_Period_Dates_hd
260 (P_Date_In_Period                 IN  Date
261 ,P_Period_Unit                    IN  Varchar2
262 ,P_Base_Start_Date                IN  Date
263 ,P_Unit_Multiplier                IN  Number) RETURN Number IS
264 --
265 l_proc        varchar2(72) := g_package||'Get_Period_Dates';
266 --
267 l_start_date    date;
268 l_end_date      date;
269 l_error         number;
270 l_months        number;
271 l_hire_date   date;
272 --
273 begin
274 
275    hr_utility.set_location(l_proc, 5);
276 
277    if P_Date_In_Period >= P_Base_Start_Date then
278    --
279      l_start_date := P_Base_Start_Date;
280      l_months := P_Unit_Multiplier;
281 
282      while true loop
283       --
284       if p_period_unit = 'M' then
285          l_end_date := add_months(P_Base_Start_Date, l_months) - 1;
286          l_start_date := add_months(P_Base_Start_Date, (l_months - P_Unit_Multiplier));
287          l_months := l_months + P_Unit_Multiplier;
288       elsif p_period_unit = 'W' then
289          l_end_date := l_start_date + (7*p_unit_multiplier) - 1;
290       elsif p_period_unit = 'D' then
291 	 l_end_date := l_start_date + p_unit_multiplier - 1;
292       end if;
293       --
294       if P_Date_In_Period between l_start_date and l_end_date then
295 
296        if to_char(l_start_date,'ddmm') = '2902' then
297 	       l_hire_date := per_formula_functions.get_date('HIRE_DATE_ANNIVERSARY');
298 		if to_char(l_hire_date,'ddmm')  <> '2902' then
299           		 l_start_date := l_start_date -1;
300 		end if;
301 
302        end if;
303          l_error := per_formula_functions.set_date
304                         ('PERIOD_START_DATE',l_start_date);
305          l_error := per_formula_functions.set_date
306                         ('PERIOD_END_DATE',l_end_date);
307          exit;
308       else
309          l_start_date := l_end_date + 1;
310       end if;
311      --
312      end loop;
313    --
314    else
315    --
316      l_end_date := P_Base_Start_Date - 1;
317      l_months := P_Unit_Multiplier * -1;
318 
319      while true loop
320       --
321       if p_period_unit = 'M' then
322         l_end_date := add_months(P_Base_Start_Date, (l_months + P_Unit_Multiplier)) - 1;
323         l_start_date := add_months(P_Base_Start_Date, l_months);
324         l_months := l_months - P_Unit_Multiplier;
325       elsif p_period_unit = 'W' then
326          l_start_date := l_end_date - (7*p_unit_multiplier) + 1;
327       elsif p_period_unit = 'D' then
328 	 l_start_date := l_end_date - p_unit_multiplier + 1;
329       end if;
330       --
331       if P_Date_In_Period between l_start_date and l_end_date then
332          l_error := per_formula_functions.set_date
333                         ('PERIOD_START_DATE',l_start_date);
334          l_error := per_formula_functions.set_date
335                         ('PERIOD_END_DATE',l_end_date);
336          exit;
337       else
338          l_end_date := l_start_date - 1;
339       end if;
340      --
341      end loop;
342    --
343    end if;
344 
345    hr_utility.set_location(l_proc, 10);
346    return 0;
347 exception
348    when others then
349         hr_utility.set_location(l_proc, 15);
350         return 1;
351 end Get_Period_Dates_hd;
352 --
353 /* =====================================================================
354    Name    : Get_Assignment_Status
355    Purpose : To determine assignment status spanning a given date
356              The globals ASSIGNMENT_EFFECTIVE_SD, ASSIGNMENT_EFFECTIVE_ED and
357              ASSIGNMENT_SYSTEM_STATUS are populated
358    Returns : 0 if successful, 1 otherwise
359    ---------------------------------------------------------------------*/
360 function Get_Assignment_Status
361 (P_Assignment_ID                  IN  Number
362 ,P_Effective_Date                 IN  Date) return number IS
363 --
364 l_proc        varchar2(72) := g_package||'Get_Assignment_Status';
365 --
366 l_effective_start_date date;
367 l_effective_end_date date;
368 l_per_system_status varchar2(30);
369 l_error number;
370 --
371 cursor csr_assignment_status IS
372 select a.effective_start_date
373 ,      a.effective_end_date
374 ,      b.per_system_status
375 from   per_all_assignments_f a
376 ,      per_assignment_status_types b
377 where  a.assignment_id = P_Assignment_ID
378 and    a.assignment_status_type_id = b.assignment_status_type_id
379 and    P_Effective_Date
380         between a.effective_start_date and a.effective_end_date;
381 --
382 begin
383    hr_utility.set_location(l_proc, 5);
384    open csr_assignment_status;
385    fetch csr_assignment_status into l_effective_start_date,
386                                     l_effective_end_date,
387                                     l_per_system_status;
388    if csr_assignment_status%notfound then
389       close csr_assignment_status;
390       --
391       hr_utility.set_location(l_proc, 10);
392       return 1;
393    end if;
394    close csr_assignment_status;
395    --
396    l_error := per_formula_functions.set_date
397                    ('ASSIGNMENT_EFFECTIVE_SD',l_effective_start_date);
398    l_error := per_formula_functions.set_date
399                    ('ASSIGNMENT_EFFECTIVE_ED',l_effective_end_date);
400    l_error := per_formula_functions.set_text
401                    ('ASSIGNMENT_SYSTEM_STATUS',l_per_system_status);
402    --
403    hr_utility.set_location(l_proc, 10);
404    return 0;
405 end Get_Assignment_Status;
406 --
407 /* =====================================================================
408    Name    : Calculate_Payroll_Periods
409    Purpose : Calculates number of periods in one year for the payroll
410              indicated by payroll_id
411    Returns : 0 if successful, 1 otherwise
412    ---------------------------------------------------------------------*/
413 function Calculate_Payroll_Periods
414 (P_Payroll_ID                  IN  Number,
415  P_Calculation_Date            IN  Date) return number IS
416 --
417 l_proc        varchar2(72) := g_package||'Calculate_Payroll_Periods';
418 l_periods     number;
419 l_start_date  date;
420 l_error       number;
421 l_max_ed_cur_year date; -- bug 4956943
422 --
423 -- Bug 1574928
424 -- As bi-weekly, weekly and lunar months can have a variable number of periods
425 -- in a year, these must be calculated based on per_time_periods.
426 -- They are set to zero and counted later on.
427 
428 cursor c_count_periods is
429 select count(*)
430 from per_time_periods ptp
431 where ptp.payroll_id = P_Payroll_ID
432 and ptp.end_date between
433 to_date('01/01/'||to_char(P_Calculation_Date, 'YYYY'), 'DD/MM/YYYY')
434 and to_date('31/12/' || to_char(P_Calculation_Date, 'YYYY'), 'DD/MM/YYYY');
435 
436 cursor c_first_date is
437 select start_date
438 from per_time_periods
439 where payroll_id = p_payroll_id
440 and end_date = (select min(end_date)
441                 from per_time_periods
442                 where payroll_id = p_payroll_id
443                 and to_char(end_date, 'YYYY') = to_char(p_calculation_date, 'YYYY'));
444 
445 begin
446 --
447   hr_utility.set_location(l_proc, 5);
448 
449   open c_count_periods;
450   fetch c_count_periods into l_periods;
451   close c_count_periods;
452 
453   l_error := per_formula_functions.set_number
454                    ('PAYROLL_YEAR_NUMBER_OF_PERIODS',l_periods);
455 
456   hr_utility.set_location(l_proc, 10);
457   -- START bug 4956943
458   select max(end_date)
459     into l_max_ed_cur_year
460     from per_time_periods
461    where payroll_id = p_payroll_id
462      and to_char(end_date, 'YYYY') = to_char(p_calculation_date, 'YYYY');
463   hr_utility.trace(l_proc || ' '  || l_max_ed_cur_year);
464 
465   if l_max_ed_cur_year < p_calculation_date then
466     hr_utility.set_location(l_proc, 100);
467     select min(start_date)
468       into l_start_date
469       from per_time_periods
470      where payroll_id = p_payroll_id
471        and end_date >= p_calculation_date;
472   else
473   -- END bug 4956943
474     open c_first_date;
475     fetch c_first_date into l_start_date;
476     close c_first_date;
477   end if;
478 
479   l_error := per_formula_functions.set_date
480                    ('PAYROLL_YEAR_FIRST_VALID_DATE', l_start_date);
481 
482   hr_utility.set_location(l_proc, 15);
483 
484   return 0;
485 --
486 end Calculate_Payroll_Periods;
487 --
488 /* =====================================================================
489    Name    : Get_Start_Date
490    Purpose : Calculates the adjusted start date for accruals, by checking
491              for element entries attached to an accrual plan which have not
492              yet been processed in a payroll run.
493    Returns : Effective start date of payroll period.
494    ---------------------------------------------------------------------*/
495 function Get_Start_Date
496 (P_Assignment_ID               IN  Number,
497  P_Accrual_Plan_ID             IN  Number,
498  P_Assignment_Action_Id        IN  Number,
499  P_Accrual_Start_Date          IN  Date,
500  P_Turn_Of_Year_Date           IN  Date) return Date is
501 
502 l_proc        varchar2(72) := g_package||'Get_Start_Date';
503 l_date        date;
504 l_balance_exists number;
505 l_payroll_id     number;
506 l_result         number;
507 /*
508    Changes done for Bug 3183291
509    ----------------------------
510 1. Moved pay_element_entries_f pee1 to second last
511 2. Driving the join to pay_net_calculation_rules through the
512    input_value_id (PAY_NET_CALCULATION_RULES_N3) instead of
513    ncr.accrual_plan_id (PAY_NET_CALCULATION_RULES_FK1) which is more selective
514 3. By disabling the Primary Key join to the table the query can be driven off the
515    element entry route which is more selective when driving through subsequent tables.
516 4. Added this predicate to help in the filtering
517 5. Very poor filter so disabled to drive of the source_id which is more selective
518 6. Same as above
519 7. Same as above
520 */
521 /* modified the following cursor to improve performance
522 cursor c_get_date is
523 select nvl(min(pee1.effective_start_date), P_Accrual_Start_Date)
524 from pay_element_links_f pel1,
525      pay_input_values_f piv,
526      pay_net_calculation_rules ncr,
527      pay_accrual_plans pap,
528      pay_element_links_f pel2,
529      pay_element_entries_f pee1, -- Change (1)
530      pay_element_entries_f pee2
531 where pee1.element_link_id = pel1.element_link_id
532 and pel1.element_type_id = piv.element_type_id
533 and piv.input_value_id = ncr.input_value_id
534 and ncr.accrual_plan_id + 0 = pap.accrual_plan_id -- Change (2)
535 and pap.accrual_plan_element_type_id = pel2.element_type_id
536 and pel2.element_link_id = pee2.element_link_id
537 and pee1.assignment_id = p_assignment_id
538 and pee2.assignment_id = p_assignment_id
539 and pap.accrual_plan_id + 0 = p_accrual_plan_id -- Change (3)
540 and pee1.effective_start_date <= p_accrual_start_date - 1 -- Change (4)
541 and pee1.effective_end_date between p_turn_of_year_date
542                             and p_accrual_start_date - 1
543 and not exists (select 1
544                 from pay_run_results prr
545                 where prr.source_id = pee1.element_entry_id
546                 and prr.element_type_id + 0 = pel1.element_type_id -- Change (5)
547                 and prr.status in ('P', 'PA')
548                 )
549 and not exists (select 1
550                 from pay_run_results prr,
551                      pay_run_result_values rrv
552                 where prr.run_result_id = rrv.run_result_id
553                 and prr.source_id = pee2.element_entry_id
554                 and prr.element_type_id + 0 = pap.tagging_element_type_id -- Change (6)
555                 and rrv.result_value = pee1.element_entry_id
556                );
557 */
558 -- fix for the bug 5645232
559 cursor c_get_date is
560 select  /*+ index(pee1 PAY_ELEMENT_ENTRIES_F_N53) use_nl(ncr)*/
561 nvl(min(pee1.effective_start_date), P_Accrual_Start_Date)
562 from
563      pay_input_values_f piv,
564      pay_net_calculation_rules ncr,
565      pay_accrual_plans pap,
566      pay_element_entries_f pee1,
567      pay_element_entries_f pee2
568      where
569  pee1.element_type_id = piv.element_type_id
570 and piv.input_value_id = ncr.input_value_id
571 and ncr.accrual_plan_id +0 = pap.accrual_plan_id
572 and pap.accrual_plan_element_type_id = pee1.element_type_id
573 and pee1.element_type_id = pee2.element_type_id
574 and pee1.assignment_id = p_assignment_id
575 and pee2.assignment_id = p_assignment_id
576 and pap.accrual_plan_id  = p_accrual_plan_id
577 and pee1.effective_start_date <= p_accrual_start_date
578 and pee1.effective_end_date between p_turn_of_year_date
579                             and p_accrual_start_date
580 and not exists (select 1
581                 from pay_run_results prr
582                 where prr.source_id = pee1.element_entry_id
583                 and prr.element_type_id + 0 = pee1.element_type_id -- fix new
584                 and prr.status in ('P', 'PA')
585                 )
586 and not exists (select 1
587                 from pay_run_results prr,
588                      pay_run_result_values rrv
589                 where prr.run_result_id = rrv.run_result_id
590                 and prr.source_id = pee2.element_entry_id
591                 and prr.element_type_id + 0 = pap.tagging_element_type_id
592                 and rrv.result_value = pee1.element_entry_id
593                );
594 -- end of bug 5645232
595 cursor c_check_balance_exists is
596 select 1
597 from pay_element_entries_f pee,
598      pay_element_links_f pel,
599      pay_accrual_plans pap
600 where pap.accrual_plan_id = p_accrual_plan_id
601 and   pee.assignment_id = p_assignment_id
602 and   pap.accrual_plan_element_type_id = pel.element_type_id
603 and   pel.element_link_id = pee.element_link_id
604 and   exists (select 1
605               from pay_run_results prr
606               where prr.source_id = pee.element_entry_id
607               and prr.element_type_id + 0 = pel.element_type_id -- Change (7)
608               and prr.status in ('P', 'PA')
609               );
610 
611 begin
612 --
613   hr_utility.set_location(l_proc, 5);
614 
615   /*
616    * First check that a latest balance actually exists. There will
617    * be no balance if no payrolls have yet been run with the new
618    * pto system. The balance DBI is set to 0 in this case, so we cannot
619    * detect the event with in a FF. In this circumstance, we just want to
620    * accrue for the entire plan term, and we set the return date accordingly.
621    * If there is a latest balance in existence, continue as normal.
622    */
623 
624   open c_check_balance_exists;
625   fetch c_check_balance_exists into l_balance_exists;
626 
627   if c_check_balance_exists%notfound then
628   --
629     close c_check_balance_exists;
630     return P_Turn_Of_Year_Date;
631   --
632   end if;
633 
634   close c_check_balance_exists;
635 
636   /*
637    * Now check for retrospective element entries
638    *
639    */
640 
641   open c_get_date;
642   fetch c_get_date into l_date;
643   close c_get_date;
644 
645   hr_utility.set_location(l_proc, 10);
646 
647   return l_date;
648 --
649 end Get_Start_Date;
650 --
651 --
652 
653 /* =====================================================================
654    Name    : Get_Element_Entry
655    Purpose : Assigns value of element entry id context to a
656              global variable.
657    Returns : 1
658    ---------------------------------------------------------------------*/
659 function Get_Element_Entry
660  (P_Element_Entry_Id            IN  Number,
661   P_Assignment_ID               IN  Number,
662   P_Assignment_Action_Id        IN  Number) return Number is
663 
664 /*
665    Changes done for Bug 3183291
666    ----------------------------
667 1. Moved pay_element_entries_f pee1 to second last
668 2. Driving the join to pay_net_calculation_rules through the
669    input_value_id (PAY_NET_CALCULATION_RULES_N3) instead of
670    ncr.accrual_plan_id (PAY_NET_CALCULATION_RULES_FK1) which is more selective
671 3. Very poor filter so disabled to drive of the source_id which is more selective
672 4. Same as above
673 5. Bulk collect is used to store the values into PL/SQL tables
674 */
675 /*
676 modified the cursor to improve performance
677 cursor c_get_element (p_entry_id number,
678                       p_effective_date date) is
679 select distinct pee1.element_entry_id
680 from pay_element_links_f pel1,
681      pay_input_values_f piv,
682      pay_net_calculation_rules ncr,
683      pay_accrual_plans pap,
684      pay_element_links_f pel2,
685      pay_element_entries_f pee1,  -- Change (1)
686      pay_element_entries_f pee2
687 where pee1.element_link_id = pel1.element_link_id
688 and pel1.element_type_id = piv.element_type_id
689 and piv.input_value_id = ncr.input_value_id
690 and ncr.accrual_plan_id + 0 = pap.accrual_plan_id -- Change (2)
691 and pap.accrual_plan_element_type_id = pel2.element_type_id
692 and pel2.element_link_id = pee2.element_link_id
693 and pee1.assignment_id = p_assignment_id +
694                          decode (pel1.element_link_id, 0, 0, 0)
695 and pee2.assignment_id = p_assignment_id
696 and pee1.effective_end_date < p_effective_date
697 and pee2.element_entry_id = p_entry_id
698 and not exists (select 1
699                 from pay_run_results prr
700                 where prr.source_id = pee1.element_entry_id
701                 and prr.element_type_id + 0 = pel1.element_type_id -- Change (3)
702                 and prr.status in ('P', 'PA')
703                 )
704 and not exists (select 1
705                 from pay_run_results prr,
706                      pay_run_result_values rrv
707                 where prr.run_result_id = rrv.run_result_id
708                 and prr.source_id = pee2.element_entry_id
709                 and prr.element_type_id + 0 = pap.tagging_element_type_id -- Change (4)
710                 and rrv.result_value = pee1.element_entry_id
711                );
712 */
713 -- fix for the bug 5645232
714 cursor c_get_element (p_entry_id number,
715                       p_effective_date date) is
716 select  /*+ index(pee1 PAY_ELEMENT_ENTRIES_F_N53)*/
717        distinct pee1.element_entry_id
718 from
719      pay_input_values_f piv,
720      pay_net_calculation_rules ncr,
721      pay_accrual_plans pap,
722      pay_element_entries_f pee1,
723      pay_element_entries_f pee2
724 where
725  pee1.element_type_id = piv.element_type_id
726 and piv.input_value_id = ncr.input_value_id
727 and ncr.accrual_plan_id +0 = pap.accrual_plan_id
728 and pap.accrual_plan_element_type_id = pee2.element_type_id
729 and pee1.element_type_id = pee2.element_type_id
730 and pee1.assignment_id = p_assignment_id
731 and pee2.assignment_id = p_assignment_id
732 and pee1.effective_end_date < p_effective_date
733 and pee2.element_entry_id = p_entry_id
734 and not exists (select 1
735                 from pay_run_results prr
736                 where prr.source_id = pee1.element_entry_id
737                 and prr.element_type_id + 0 = pee1.element_type_id
738                 and prr.status in ('P', 'PA')
739                 )
740 and not exists (select 1
741                 from pay_run_results prr,
742                      pay_run_result_values rrv
743                 where prr.run_result_id = rrv.run_result_id
744                 and prr.source_id = pee2.element_entry_id
745                 and prr.element_type_id + 0 = pap.tagging_element_type_id
746                 and rrv.result_value = pee1.element_entry_id
747                );
748 
749 -- end of bug 5645232
750 --
751 cursor c_get_date is
752 select ptp.start_date
753 from per_time_periods ptp,
754      pay_payroll_actions ppa,
755      pay_assignment_actions paa
756 where paa.payroll_action_id = ppa.payroll_action_id
757 and ppa.time_period_id = ptp.time_period_id
758 and paa.assignment_action_id = p_assignment_action_id;
759 
760 -- Bug 3183291 -- Change (5)
761 --l_retro_entry_id   number;
762 l_count            number;
763 l_effective_date   date;
764 l_limit            natural := 100; -- Limiting the bulk collect, if not limited then bulk collect
765                                    -- returns entire rows for the condition, it may affect memory
766 l_prev_collect     number  := 0;   -- Cumulative record count till previous fetch
767 l_curr_collect     number  := 0;   -- Cumulative record count including the current fetch
768 l_diff_collect     number  := 0;   -- To check that, whether the last fetch retrived any new
769                                    -- records, if not then to exit from the loop
770 g_element_entries1 global_id_table;
771 --
772 begin
773 --
774 
775   open c_get_date;
776   fetch c_get_date into l_effective_date;
777   close c_get_date;
778 
779   open c_get_element(p_element_entry_id, l_effective_date);
780   --
781      loop
782      --
783      -- Change (5)
784         fetch c_get_element bulk collect into g_element_entries1 limit l_limit;
785            --
786            l_prev_collect := l_curr_collect;
787            l_curr_collect := c_get_element%rowcount;
788            l_diff_collect := l_curr_collect - l_prev_collect;
789            --
790            if l_diff_collect > 0 then
791               --
792               for i in g_element_entries1.first..g_element_entries1.last loop
793                  --
794                  -- Setting the index
795                  l_count := g_element_entries.count + 1;
796                  -- Keeping the cumulated records into actual PL/SQL table
797                  g_element_entries(l_count) := g_element_entries1(i);
798                  --
799               end loop;
800               --
801            end if;
802            --
803         -- Exiting, if the present fetch is NOT returning any new rows
804         exit when (l_diff_collect = 0);
805      --
806      end loop;
807   --
808   close c_get_element;
809   --
810   return 1;
811 --
812 end Get_Element_Entry;
813 --
814 --
815 /* =====================================================================
816    Name    : Get_Retro_Element
817    Purpose : Retrieves retrospective elements in order for them to be
818              tagged as processed.
819              Overloaded version of function for use where element_entry_id
820              context is unavailable.
821    Returns : Element Entry ID
822    ---------------------------------------------------------------------*/
823 function Get_Retro_Element return Number is
824 
825 l_retro_entry_id   number;
826 l_count            number;
827 
828 begin
829 --
830   l_count := g_element_entries.count;
831 
832   if l_count > 0 then
833   --
834     l_retro_entry_id := g_element_entries(l_count);
835     g_element_entries.delete(l_count);
836   --
837   end if;
838 
839   if l_retro_entry_id is null then
840     return -1;
841   else
842     return l_retro_entry_id;
843   end if;
844 --
845 end Get_Retro_Element;
846 --
847 /* =====================================================================
848    Name    : Get_Net_Accrual
849    Purpose : Wrapper function for per_accrual_calc_functions.get_net_accrual.
850              Only returns accrued time figure.
851    Returns : 0 if successful, 1 otherwise
852    ---------------------------------------------------------------------*/
853 function Get_Net_Accrual
854 (P_Assignment_ID                  IN  Number
855 ,P_Payroll_ID                     IN  Number
856 ,P_Business_Group_ID              IN  Number
857 ,P_Assignment_Action_ID           IN  Number default null
858 ,P_Calculation_Date               IN  Date
859 ,P_Plan_ID                        IN  Number
860 ,P_Accrual_Start_Date             IN  Date default null
861 ,P_Accrual_Latest_Balance         IN  Number default null) return number is
862 
863 l_proc               varchar2(72) := g_package||'Get_Net_Accrual';
864 l_start_date         date;
865 l_end_date           date;
866 l_accrual_start_date date;
867 l_accrual_end_date   date;
868 l_accrual            number;
869 l_net_entitlement    number;
870 
871 begin
872 --
873   hr_utility.set_location(l_proc, 5);
874 
875   if P_Accrual_Start_Date = hr_api.g_eot then
876     -- The accrual start date database item returned null but Fast
877     -- Formula defaulted it to the end of time. Re-set it back to null.
878     l_accrual_start_date := null;
879   else
880     l_accrual_start_date := P_Accrual_Start_Date;
881   end if;
882 
883   per_accrual_calc_functions.get_net_accrual(
884                 P_Assignment_ID      => P_Assignment_ID
885                ,P_Plan_ID            => P_Plan_ID
886                ,P_Payroll_ID         => P_Payroll_ID
887                ,P_Business_Group_ID  => P_Business_Group_ID
888                ,P_Assignment_Action_ID => P_Assignment_Action_ID
889                ,P_Calculation_Date   => P_Calculation_Date
890                ,P_Accrual_Start_Date => l_accrual_start_date
891                ,P_Accrual_Latest_Balance => P_Accrual_Latest_Balance
892                ,P_Calling_Point      => 'SQL'
893                ,P_Start_Date         => l_start_date
894                ,P_End_Date           => l_end_date
895                ,P_Accrual_End_Date   => l_accrual_end_date
896                ,P_Accrual            => l_accrual
897                ,P_Net_Entitlement    => l_net_entitlement);
898 
899   hr_utility.set_location(l_proc, 10);
900 
901   return round(nvl(l_net_entitlement, 0), 5);
902 --
903 end Get_Net_Accrual;
904 --
905 --
906 /* =====================================================================
907    Name    : Calculate_Hours_Worked
908    Purpose : Calculates the total number of hours worked in a given date
909              range.  Moved here to create global version as previously
910 	     only localised versions existed (Bug 2720878).
911    Returns : Number of hours
912    ---------------------------------------------------------------------*/
913 FUNCTION calculate_hours_worked(
914 				p_std_hrs	in NUMBER,
915 				p_range_start	in DATE,
916 				p_range_end	in DATE,
917 				p_std_freq	in VARCHAR2) RETURN NUMBER IS
918 --
919   c_wkdays_per_week	NUMBER(5,2)		:= 5;
920   c_wkdays_per_month	NUMBER(5,2)		:= 20;
921   c_wkdays_per_year	NUMBER(5,2)		:= 250;
922 
923   /* 353434, 368242 : Fixed number width for total hours */
924   v_total_hours	NUMBER(15,7) 	:= 0;
925   v_wrkday_hours	NUMBER(15,7) 	:= 0;	 -- std hrs/wk divided by 5 workdays/wk
926   v_curr_date	DATE			:= NULL;
927   v_curr_day	VARCHAR2(3)		:= NULL; -- 3 char abbrev for day of wk.
928   v_day_no        NUMBER;
929 --
930 BEGIN -- calculate_hours_worked
931   --
932   -- Check for valid range
933   hr_utility.set_location('calculate_hours_worked', 5);
934   IF p_range_start > p_range_end THEN
935     hr_utility.set_location('calculate_hours_worked', 7);
936     RETURN v_total_hours;
937   --  hr_utility.set_message(801,'PAY_xxxx_INVALID_DATE_RANGE');
938   --  hr_utility.raise_error;
939   END IF;
940   --
941   --
942   IF UPPER(p_std_freq) = 'W' THEN
943     v_wrkday_hours := p_std_hrs / c_wkdays_per_week;
944   ELSIF UPPER(p_std_freq) = 'M' THEN
945     v_wrkday_hours := p_std_hrs / c_wkdays_per_month;
946   ELSIF UPPER(p_std_freq) = 'Y' THEN
947     v_wrkday_hours := p_std_hrs / c_wkdays_per_year;
948   ELSE
949     v_wrkday_hours := p_std_hrs;
950   END IF;
951   --
952   v_curr_date := p_range_start;
953 
954   hr_utility.set_location('calculate_hours_worked', 10);
955 
956            hr_utility.trace('p_range_start is'|| to_char(p_range_start));
957            hr_utility.trace('p_range_end is'|| to_char(p_range_end));
958   LOOP
959 
960     v_day_no := TO_CHAR(v_curr_date, 'D');
961 
962     hr_utility.set_location('calculate_hours_worked', 15);
963 
964     IF v_day_no > 1 and v_day_no < 7 then
965 
966       v_total_hours := v_total_hours + v_wrkday_hours;
967       hr_utility.set_location('calculate_hours_worked v_total_hours = ', v_total_hours);
968     END IF;
969     v_curr_date := v_curr_date + 1;
970     EXIT WHEN v_curr_date > p_range_end;
971   END LOOP;
972   --
973            hr_utility.set_location('v_total_hours is', to_number(v_total_hours));
974   RETURN v_total_hours;
975   --
976 END calculate_hours_worked;
977 --
978 function Get_Payroll_ID
979 (P_Asg_ID            IN  Number
980 ,P_Payroll_Id        IN  Number
981 ,P_Date_In_Period    IN  Date) return number IS
982 --
983 l_proc        varchar2(72) := g_package||'Get_Payroll_ID';
984 --
985 cursor csr_get_payroll is
986 select payroll_id
987 from   per_all_assignments_f
988 where  assignment_id = P_asg_ID
989 and    P_Date_In_Period between effective_start_date
990                             and effective_end_date;
991 --
992 l_payroll_id number;
993 --
994 l_error number;
995 --
996 begin
997    hr_utility.set_location(l_proc, 5);
998    --
999    open csr_get_payroll;
1000    fetch csr_get_payroll into l_payroll_id;
1001    if csr_get_payroll%notfound then
1002       close csr_get_payroll;
1003       hr_utility.set_location('Payroll not found '||l_proc, 10);
1004       -- Since no payroll found for the assignment, using the context value
1005       l_payroll_id := P_Payroll_Id;
1006    elsif l_payroll_id is null then
1007       close csr_get_payroll;
1008       hr_utility.set_location('Payroll is null '||l_proc, 12);
1009       -- Since no payroll found for the assignment, using the context value
1010       l_payroll_id := P_Payroll_Id;
1011    end if;
1012    if csr_get_payroll%isopen then
1013       close csr_get_payroll;
1014    end if;
1015    --
1016    l_error := per_formula_functions.set_number
1017                                   ('LATEST_PAYROLL_ID',l_payroll_id);
1018    --
1019    hr_utility.set_location(l_proc, 15);
1020    return 0;
1021    --
1022 end Get_Payroll_ID;
1023 --
1024 --
1025 function Get_Payroll_Details
1026 (P_payroll_ID		IN  Number
1027 ,P_Date_In_Period	IN  Date) return number IS
1028 --
1029 l_proc        varchar2(72) := g_package||'Get_Payroll_Details';
1030 --
1031 cursor csr_get_payroll_period is
1032 select start_date
1033 ,      end_date
1034 ,      period_num
1035 from   per_time_periods
1036 where  payroll_id = P_Payroll_ID
1037 and    P_Date_In_Period between start_date and end_date;
1038 --
1039 l_start_date date;
1040 l_end_date   date;
1041 l_period_number number;
1042 --
1043 l_error number;
1044 --
1045 begin
1046    hr_utility.set_location(l_proc, 5);
1047    --
1048    open csr_get_payroll_period;
1049    fetch csr_get_payroll_period into l_start_date,l_end_date,l_period_number;
1050    if csr_get_payroll_period%notfound then
1051       close csr_get_payroll_period;
1052       hr_utility.set_location('Payroll Period not found '||l_proc, 10);
1053       l_error := per_formula_functions.raise_error(800, 'HR_52798_PTO_PAYROLL_INVALID');
1054       return 1;
1055    end if;
1056    close csr_get_payroll_period;
1057    --
1058    l_error := per_formula_functions.set_date
1059                  ('PAYROLL_PERIOD_START_DATE',l_start_date);
1060    l_error := per_formula_functions.set_date
1061                  ('PAYROLL_PERIOD_END_DATE',l_end_date);
1062    l_error := per_formula_functions.set_number
1063                  ('PAYROLL_PERIOD_NUMBER',l_period_number);
1064    --
1065    hr_utility.set_location(l_proc, 15);
1066    return 0;
1067 end Get_Payroll_Details;
1068 --
1069 --
1070 --
1071 -- 3267975 >>
1072 /* =====================================================================
1073    Name    : cache_action_prms
1074    =====================================================================
1075    Purpose : Populates the PL/SQL table with the given parameter_name. If
1076              the table is already cached, the parameter is added.
1077    Returns : Nothing.
1078    ---------------------------------------------------------------------*/
1079 procedure cache_action_prms (p_prm_name in varchar2) is
1080 
1081    cursor csr_get_parameter is
1082      select parameter_name
1083            ,parameter_value
1084        from pay_action_parameters
1085       where parameter_name = p_prm_name;
1086 --
1087   l_proc varchar2(80) := g_package||'cache_action_prms';
1088 --
1089 begin
1090 --
1091    hr_utility.set_location('Entering: '||l_proc,5);
1092 
1093    if NOT g_actionPrm_cached then
1094      g_actionPrm_cache.sz := 0;
1095    end if;
1096 --
1097    for actionPrm_rec in csr_get_parameter loop
1098 --
1099      g_actionPrm_cache.sz := g_actionPrm_cache.sz + 1;
1100      g_actionPrm_cache.parameter_name(g_actionPrm_cache.sz) := actionPrm_rec.parameter_name;
1101      g_actionPrm_cache.parameter_value(g_actionPrm_cache.sz) := actionPrm_rec.parameter_value;
1102 --
1103    end loop;
1104 --
1105    g_actionPrm_cached := TRUE;
1106 --
1107     hr_utility.set_location('Leaving: '||l_proc,88);
1108 --
1109 end cache_action_prms;
1110 /* =====================================================================
1111    Name    : Get Cache ActionPrm
1112 /* =====================================================================
1113    Purpose : Gets the event_id from a cached pl/sql table to prevent
1114              same reads of pay action parameters view.
1115    Returns : parameter value if found, null otherwise.
1116    ---------------------------------------------------------------------*/
1117 function get_cache_ActionPrm(p_prm_name        in varchar2)
1118         return varchar2 is
1119 
1120 --
1121   l_proc varchar2(80) := g_package||'get_cache_ActionPrm';
1122 --
1123 actionPrm_rec    number;
1124 l_prm_value      PAY_ACTION_PARAMETER_VALUES.parameter_value%TYPE;
1125 
1126 begin
1127 --
1128    hr_utility.set_location('Entering: '||l_proc,5);
1129 
1130    for actionPrm_rec in 1..g_actionPrm_cache.sz loop
1131 
1132      if   (g_actionPrm_cache.parameter_name(actionPrm_rec) = p_prm_name)
1133      then
1134        l_prm_value := g_actionPrm_cache.parameter_value(actionPrm_rec);
1135      end if;
1136 
1137    end loop;
1138 --
1139    hr_utility.set_location('Leaving: '||l_proc,88);
1140 --
1141    return l_prm_value;
1142 --
1143 end get_cache_ActionPrm;
1144 --
1145 /* ========================================================================
1146    Name    : Get Action Parameter
1147    ========================================================================
1148    Purpose : Gets the Action Parameter from a cached pl/sql table to prevent
1149              same table scans on pay_action_parameters.
1150    Returns : parameter value.
1151    -----------------------------------------------------------------------*/
1152 function get_action_parameter(p_prm_name      in varchar2)
1153                      return varchar2 is
1154 
1155 l_prm_value  PAY_ACTION_PARAMETER_VALUES.parameter_value%TYPE;
1156 
1157 begin
1158 --
1159    if NOT g_actionPrm_cached then
1160      cache_action_prms (p_prm_name => p_prm_name);
1161    end if;
1162 
1163    l_prm_value := get_cache_ActionPrm (p_prm_name);
1164 
1165    return l_prm_value;
1166 --
1167 end get_action_parameter;
1168 -- <<
1169 -- 3267975 >>
1170 /* =====================================================================
1171    Name    : Reset_PTO_Accruals
1172    =====================================================================
1173    Purpose : Determines whether the PTO accruals for an assignment
1174              should be recalculated from the beginning.
1175              This is based on RESET_PTO_ACCRUALS action parameter
1176    Returns : 'FALSE' or 'TRUE'
1177    ---------------------------------------------------------------------*/
1178 function Reset_PTO_Accruals return varchar2 is
1179 
1180 --
1181    l_proc        varchar2(72) := g_package||'Reset_PTO_Accruals';
1182 --
1183    l_result PAY_ACTION_PARAMETER_VALUES.parameter_value%TYPE := 'N';
1184 --
1185 
1186 begin
1187    hr_utility.set_location('Entering: '||l_proc, 5);
1188 
1189    if NOT g_reset_pto_cache then
1190        l_result := Get_Action_Parameter('RESET_PTO_ACCRUALS');
1191        if nvl(l_result,'N') = 'Y' then
1192            g_reset_pto_accruals := 'TRUE';
1193        else
1194            g_reset_pto_accruals := 'FALSE';
1195        end if;
1196        g_reset_pto_cache := true;
1197    end if;
1198    hr_utility.set_location('Leaving: '||l_proc||' => RESET = '||g_reset_pto_accruals, 88);
1199    return g_reset_pto_accruals;
1200 
1201 end Reset_PTO_Accruals;
1202 -- <<
1203 --
1204 --
1205 -- 3267975 >>
1206 --
1207 /* =====================================================================
1208    Name    : Get_Legislation
1209    =====================================================================
1210    Purpose : Retrieves the legislation code associated with
1211              business group.
1212    Returns : Legislation code.
1213    ---------------------------------------------------------------------*/
1214 function get_legislation (p_business_group_id number)
1215    return varchar2 is
1216 
1217    cursor csr_getLegCode is
1218      select legislation_code
1219        from per_business_groups
1220        where organization_id = p_business_group_id;
1221 --
1222   l_proc varchar2(80) := g_package||'get_legislation';
1223 --
1224   l_legcode  HR_ORGANIZATION_INFORMATION.org_information9%TYPE;
1225 --
1226 begin
1227    if NOT g_legcode_cached then
1228        open csr_getLegCode;
1229        fetch csr_getLegCode into l_legcode;
1230        close csr_getLegCode;
1231        --
1232        g_legcode_cache := l_legcode;
1233        g_legcode_cached := TRUE;
1234        --
1235    end if;
1236    return g_legcode_cache;
1237 end get_legislation;
1238 --
1239 /* =====================================================================
1240    Name    : Cache Events
1241    =====================================================================
1242    Purpose : Populates the PL/SQL table with the given event_name. If
1243              the table is already cached, the event is added.
1244    Returns : Nothing.
1245    ---------------------------------------------------------------------*/
1246 procedure cache_events (p_event_name in varchar2) is
1247 
1248   cursor csr_get_events is
1249   select e.event_group_id,
1250          e.event_group_name,
1251          e.business_group_id,
1252          e.legislation_code
1253   from   pay_event_groups e
1254   where  e.event_group_name = p_event_name;
1255 --
1256   l_proc varchar2(80) := g_package||'cache_events';
1257 --
1258 begin
1259 --
1260 
1261    if NOT g_events_cached then
1262      g_events_cache.sz := 0;
1263    end if;
1264 --
1265    for events_rec in csr_get_events loop
1266 --
1267      g_events_cache.sz := g_events_cache.sz + 1;
1268      g_events_cache.event_group_id(g_events_cache.sz) := events_rec.event_group_id;
1269      g_events_cache.event_group_name(g_events_cache.sz) := events_rec.event_group_name;
1270      g_events_cache.business_group_id(g_events_cache.sz) := events_rec.business_group_id;
1271      g_events_cache.legislation_code(g_events_cache.sz) := events_rec.legislation_code;
1272 --
1273    end loop;
1274 --
1275    g_events_cached := TRUE;
1276 --
1277 end cache_events;
1278 /* =====================================================================
1279    Name    : Get Cache Event
1280 /* =====================================================================
1281    Purpose : Gets the event_id from a cached pl/sql table to prevent
1282              same reads of PEM tables for each person in the
1283              payroll run.
1284    Returns : event_id if found, otherwise 0.
1285    ---------------------------------------------------------------------*/
1286 function get_cache_event(p_event_name        in varchar2,
1287                          p_business_group_id in number,
1288                          p_legislation_code  in varchar2)
1289    return number is
1290 
1291 event_rec    number;
1292 l_event_id   number := 0;
1293 
1294 begin
1295 --
1296 
1297    for event_rec in 1..g_events_cache.sz loop
1298 
1299      if   (g_events_cache.event_group_name(event_rec) = p_event_name)
1300       and (nvl(g_events_cache.business_group_id(event_rec)
1301              , nvl(p_business_group_id,-1)) = nvl(p_business_group_id,-1))
1302       and (nvl(g_events_cache.legislation_code(event_rec)
1303              , nvl(p_legislation_code,'X')) = nvl(p_legislation_code,'X'))
1304      then
1305        l_event_id := g_events_cache.event_group_id(event_rec);
1306      end if;
1307 
1308    end loop;
1309 
1310    return l_event_id;
1311    -- This will be zero if the event is not in the cached events
1312 --
1313 end get_cache_event;
1314 --
1315 /* ========================================================================
1316    Name    : Get Event
1317    ========================================================================
1318    Purpose : Gets the event_group_id from a cached pl/sql table to prevent
1319              same table scans on pay_event_groups for each person in the
1320              payroll run.
1321    Returns : event_id if found, otherwise null.
1322    -----------------------------------------------------------------------*/
1323 function get_event(p_event_name      in varchar2,
1324                    p_business_group_id in number,
1325                    p_legislation_code  in varchar2)
1326    return number is
1327 
1328 l_event_id   number;
1329 
1330 begin
1331 --
1332    if NOT g_events_cached then
1333      cache_events (p_event_name => p_event_name);
1334    end if;
1335 
1336    l_event_id := get_cache_event (
1337                        p_event_name => p_event_name,
1338                        p_business_group_id => p_business_group_id,
1339                        p_legislation_code  => p_legislation_code
1340                        );
1341 
1342    return l_event_id;
1343    -- This will be zero if event does not exist
1344 --
1345 end get_event;
1346 --
1347 FUNCTION GET_PER_TERMINATION_DATE
1348 (P_Assignment_id     IN  Number) return NUMBER IS
1349 --
1350 l_proc        varchar2(72) := g_package||'get_payroll_dtrange';
1351 --
1352 cursor csr_get_per_term_date is
1353   select max(actual_termination_date)
1354   FROM   per_all_assignments_f asg,
1355          per_periods_of_service pps
1356   where  asg.assignment_id = P_Assignment_id
1357     and  asg.period_of_service_id = pps.period_of_service_id;
1358 --changes for bug 5749588 starts here
1359 cursor csr_get_Asg_term_date is
1360   select max(EFFECTIVE_END_DATE)
1361   FROM   per_all_assignments_f asg
1362   where  asg.assignment_id = P_Assignment_id
1363   and asg.assignment_type<>'B';
1364 --changes for bug 5749588 ends here
1365 
1366 --
1367 l_Per_date date;
1368 --
1369 l_error number;
1370 --
1371 begin
1372    hr_utility.set_location(l_proc, 5);
1373    --
1374    l_Per_date := NULL;
1375    open csr_get_per_term_date;
1376    fetch csr_get_per_term_date into l_Per_date;
1377    close csr_get_per_term_date;
1378    --
1379    if l_Per_date is not null THEN
1380      l_error := per_formula_functions.set_date
1381                  ('PER_TERMINATION_DATE',l_Per_date);
1382    else
1383 --changes for bug 5749588 starts here
1384    open csr_get_Asg_term_date;
1385    fetch csr_get_Asg_term_date into l_Per_date;
1386    close csr_get_Asg_term_date;
1387 --changes for bug 5749588 ends here
1388 --   l_Per_date := hr_api.g_eot;
1389    l_error := per_formula_functions.set_date
1390                  ('PER_TERMINATION_DATE',l_Per_date);
1391      hr_utility.set_location(l_proc, 10);
1392 --     return 1;
1393    end if;
1394    --
1395    hr_utility.set_location(l_proc, 15);
1396    return 0;
1397 end GET_PER_TERMINATION_DATE;
1398 --
1399 --
1400 FUNCTION GET_PAYROLL_DTRANGE
1401 (P_Payroll_ID                     IN  Number) return number IS
1402 --
1403 l_proc        varchar2(72) := g_package||'get_payroll_dtrange';
1404 --
1405 cursor csr_get_payroll_range is
1406 select min(start_date),max(end_date)
1407 from   per_time_periods
1408 where  payroll_id = P_Payroll_ID;
1409 --
1410 l_start_date date;
1411 l_end_date   date;
1412 l_period_number number;
1413 --
1414 l_error number;
1415 --
1416 begin
1417    hr_utility.set_location(l_proc, 5);
1418    --
1419    open csr_get_payroll_range;
1420    fetch csr_get_payroll_range into l_start_date,l_end_date;
1421    close csr_get_payroll_range;
1422    --
1423    if l_start_date is not null and l_end_date is not null then
1424      l_error := per_formula_functions.set_date
1425                  ('PAYROLL_MAX_START_DATE',l_start_date);
1426      l_error := per_formula_functions.set_date
1427                  ('PAYROLL_MAX_END_DATE',l_end_date);
1428    else
1429      hr_utility.set_location(l_proc, 10);
1430      return 1;
1431    end if;
1432    --
1433    hr_utility.set_location(l_proc, 15);
1434    return 0;
1435 end GET_PAYROLL_DTRANGE;
1436 
1437 --
1438 /* =====================================================================
1439    Name    : Get_Earliest_AsgChange_Date
1440    =====================================================================
1441    Purpose : Determines the earliest assignment status change recorded
1442              by the Payroll Events Model.
1443    Returns : Date
1444    ---------------------------------------------------------------------*/
1445 FUNCTION Get_Earliest_AsgChange_Date(p_business_group_id NUMBER
1446                                     ,p_assignment_id     NUMBER
1447                                     ,p_event_group       VARCHAR2
1448                                     ,p_start_date        DATE
1449                                     ,p_end_date          DATE
1450                                     ,p_recalc_date       DATE)
1451    RETURN DATE IS
1452 --
1453     l_proc        varchar2(72) := g_package||'Get_Earliest_AsgChange_Date';
1454 --
1455 
1456     l_recalc_date DATE;
1457     l_detailed_output       pay_interpreter_pkg.t_detailed_output_table_type;
1458     l_proration_dates       pay_interpreter_pkg.t_proration_dates_table_type;
1459     l_proration_change_type pay_interpreter_pkg.t_proration_type_table_type;
1460     l_proration_type        pay_interpreter_pkg.t_proration_type_table_type;
1461 
1462     l_event_group_id        pay_event_groups.event_group_id%TYPE;
1463     l_legislation_code      HR_ORGANIZATION_INFORMATION.org_information9%TYPE;
1464 
1465 BEGIN
1466     hr_utility.set_location('Entering: '||l_proc, 5);
1467 
1468     l_recalc_date := p_recalc_date;
1469     l_legislation_code := get_legislation(p_business_group_id);
1470 
1471     l_event_group_id := get_event(p_event_group, p_business_group_id, l_legislation_code);
1472 
1473     IF l_event_group_id <> 0 THEN
1474 
1475        pay_interpreter_pkg.entry_affected
1476         (p_assignment_id         => p_assignment_id
1477         ,p_mode                  => 'DATE_PROCESSED'
1478         ,p_event_group_id        => l_event_group_id
1479         ,p_process_mode          => 'ENTRY_CREATION_DATE'
1480         ,p_start_date            => p_start_date
1481         ,p_end_date              => p_end_date
1482         ,t_detailed_output       => l_detailed_output
1483         ,t_proration_dates       => l_proration_dates
1484         ,t_proration_change_type => l_proration_change_type
1485         ,t_proration_type        => l_proration_type);
1486 
1487        IF l_detailed_output.COUNT <> 0 THEN
1488 
1489            FOR i IN l_detailed_output.FIRST..l_detailed_output.LAST LOOP
1490 
1491                IF l_detailed_output(i).effective_date < l_recalc_date THEN
1492 
1493                    l_recalc_date := l_detailed_output(i).effective_date;
1494 
1495                END IF;
1496 
1497            END LOOP;
1498        ELSE
1499            hr_utility.set_location(l_proc, 99);
1500        END IF;
1501     END IF;
1502 
1503     hr_utility.set_location('Leaving: '||l_proc, 88);
1504 
1505     RETURN l_recalc_date;
1506 
1507 END Get_Earliest_AsgChange_Date;
1508 --
1509 --
1510 --
1511 end per_utility_functions;