DBA Data[Home] [Help]

PACKAGE BODY: APPS.PER_UTILITY_FUNCTIONS

Source


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