DBA Data[Home] [Help]

PACKAGE BODY: APPS.HR_CALENDAR_PKG

Source


1 package body HR_CALENDAR_PKG as
2 /* $Header: hrcalapi.pkb 120.1.12010000.2 2008/11/07 11:03:35 pbalu noship $ */
3 --
4 --------------------------------------------------------------------------------
5 /*
6 +==============================================================================+
7 |                       Copyright (c) 1994 Oracle Corporation                  |
8 |                          Redwood Shores, California, USA                     |
9 |                               All rights reserved.                           |
10 +==============================================================================+
11 --
12 Name
13 	Calendars Business Process
14 Purpose
15 	To provide routines to give information about calendars
16 History
17 	05 sep 95	N Simpson	Created
18 	07 Sep 95	N Simpson	Added function purpose_usage_id
19 Version Date        BugNo     Author    Comment
20 -------+-----------+---------+---------+--------------------------------------
21 40.3    18-Jul_97   513292    RThirlby  Created another overload of procedure
22                                         denormalise_calendar. Altered function
23                                         total_availability to accept parameters
24                                         for both bg and person pattern in the
25                                         same (linked) absence.
26 40.4	29-Sep-97   504386    RThirlby	Changes made to derive_pattern_cycle
27 					to enhance performance.
28 40.5    11-Nov-97   572460    AMills    Added exit to reconcile_schedule to trap
29 					values where the normal pattern stack
30 					pointer exceeds the number of rows in
31 					the normal_pattern table.
32 40.6    14-Nov-97   504386    AMills    Added extra criteria to 'derive_pattern
33 					cycle' to ensure normal_pattern table
34 					is restored for absence periods greater
35 					than the original time period, where the
36 					calendar remains the same. Cancelled
37 					last alteration to reconcile_schedule as
38 					no longer necessary.
39 40.7    27-Nov-97  584613    RThirlby	Global variables re-initiated at start
40  					of denormalise_calendar, so that the
41 					Schedules window can be re-queried.
42 40.8    03-JUL-98  655707    A.Myers 	Added processing_level parameter which
43 					indicates how much processing needs to
44 					be done, whether the existing calendar
45 					can be used or not (used by calling
46                                         package SSP_SSP_PKG only).
47 115.9  23-jul-02 1404898     vmkhande    The denormalise_calendar procedure in
48                                          TOTAL_AVAILABILITY funciton is called
49                                          if the prcoessing level is less than 2.
50                                          When this funciton is called for the
51                                          BG calendar usage, the processing level
52                                          is set as 2 hence the
53                                          denormalise_calendar is not called and
54                                          the schedule stack holds incorrect date
55 					 values. The fix is: The condtion which
56 					 check the parameter value is to be
57 					 changed to <= 2.
58 115.10   15-JUN-04  3669001  kthampan   Changes to the derive_pattern_cycle procdure
59                                         to use g_period_from instead of p_period_from
60                                         when extending the pattern cycle.
61 115.11   15-JUN-04           kthampan   Fix GSCC warnings
62 115.12   24-MAR-08  6850908  pbalu      When a person has two Qualifying patterns and both are created
63                                         after the absence start date and there is a gap between the two
64                                         Person qualifying patterns then while saving or updating the absence
65                                         oracle error no data found occurs
66 */
67 --------------------------------------------------------------------------------
68 type number_table is table of number index by binary_integer;
69 type varchar_table is table of varchar2 (30) index by binary_integer;
70 type date_table is table of date index by binary_integer;
71 --
72 one_second constant number := 1/86400; -- a second as a proportion of one day
73 --
74 -- Normal pattern construction variables
75 --
76 type pattern_info is record (
77 	availability	varchar_table,
78 	duration_days	number_table,
79 	stored_pattern_id	number :=0,
80 	stored_number_of_bits	number :=0);
81 	--
82 type stack is record (
83 	--
84 	pointer		integer :=1,
85 	run_out		boolean := FALSE,
86 	start_date	date_table,
87 	end_date	date_table,
88 	level		number_table,
89 	availability	varchar_table);
90 	--
91 calendar_exception	stack;
92 usage_exception		stack;
93 normal_pattern		stack;
94 schedule		stack;
95 empty_stack		stack;
96 --
97 pattern			pattern_info;
98 empty_pattern		pattern_info;
99 index_no		integer;
100 g_hc_package            constant varchar2 (18) := 'hr_calendar_pkg.';
101 g_calendar_id		number; --global calendar ID
102 g_period_from		date;   --global period from
103 g_period_to		date;   --global period to
104 initialise_flag		boolean := false;
105 --
106 cursor pattern_bits (p_pattern_id	in number) is
107 --
108 -- Get the pattern by denormalising the duration of each bit of the pattern
109 -- to show the duration and availability. The sql separates those bits of the
110 -- pattern which are directly based on time units from those which are
111 -- themselves patterns and require a further step to get the time units. There
112 -- is a business rule which limits the pattern hierarchy to two levels.
113 --
114 	select	bit1.time_unit_multiplier,
115 		bit1.base_time_unit,
116 		con1.sequence_no,
117 		0,
118 		con1.availability
119 	from	hr_pattern_constructions	CON1,
120 		hr_pattern_bits			BIT1
121 	where	bit1.pattern_bit_id = con1.pattern_bit_id
122 	and	con1.pattern_id = p_pattern_id
123 	union all
124 	select	bit2.time_unit_multiplier,
125 		bit2.base_time_unit,
126 		con2.sequence_no,
127 		con3.sequence_no,
128 		con3.availability
129 	from	hr_pattern_bits			BIT2,
130 		hr_pattern_constructions	CON2,
131 		hr_pattern_constructions	CON3
132 	where	bit2.pattern_bit_id = con3.pattern_bit_id
133 	and	con2.component_pattern_id = con3.pattern_id
134 	and	con2.pattern_id = p_pattern_id
135 	order by 3,4;
136 --------------------------------------------------------------------------------
137 --
138 function TO_DAYS (
139 --
140 -- Convert user-defined time unit into days for ease of comparison and
141 -- manipulation.
142 --
143 	quantity	number,
144 	units		varchar2) return number is
145 --
146 conversion_factor	number :=1;
147 --
148 begin
149 --
150 if units = 'H' then
151   conversion_factor := 24;
152 --
153 elsif units = 'W' then
154   conversion_factor := 1/7;
155 --
156 end if;
157 --
158 return (quantity / conversion_factor);
159 --
160 end to_days;
161 --------------------------------------------------------------------------------
162 --
163 procedure DERIVE_PATTERN_CYCLE (
164 --
165 -- Converts a pattern from a single iteration of undated durations into a
166 -- schedule of dated chunks.
167 --
168 	p_calendar_id	number,
169         p_period_from   date,
170 	p_period_to	date,
171 	p_called_from_SSP boolean default false) is
172 --
173 cursor calendar is
174 	--
175 	-- Get the details of the calendar
176 	--
177 	select	pattern_start_position,
178 		calendar_start_time,
179 		pattern_id
180 	from	hr_calendars
181 	where	calendar_id = P_CALENDAR_ID;
182 --
183 start_position      integer;
184 start_time          date;
185 l_pattern_id        number;
186 cycle_date          date;
187 n                   integer :=0;
188 first_bit	    integer :=1;
189 total_duration_time number :=0;
190 duration_time       number :=0;
191 first_loop          boolean;
192 old_cycle_date      date;
193 counter             integer := 0;
194 l_proc  varchar2 (42) := g_hc_package||'Derive_Pattern_Cycle';
195 --
196 begin
197 --
198 hr_utility.set_location('Entering:'||l_proc,1);
199 --
200 -- Find out which pattern we are dealing with, where within the pattern sequence
201 -- to start the calendar, and what the start date for the pattern is.
202 --
203 -- Bug 504386 - If the same calendar is being passed in, then use the values
204 -- already in the pl/sql table normal_pattern.
205 --
206 if g_calendar_id is null or
207    g_calendar_id <> p_calendar_id or
208    p_period_to not between g_period_from and g_period_to or
209    (p_period_from < g_period_from or p_called_from_SSP = false)
210 then
211    if p_called_from_SSP = true
212    then
213       if (g_period_from is null or p_period_from < g_period_from)
214       then
215       --
216       -- Do not reset g_period_from if we are currently using it (i.e. it is
217       -- not null, but set it if p_period_from is earlier so that we get a
218       -- complete calendar.
219       --
220          g_period_from := p_period_from;
221       end if;
222    else
223       g_period_from := p_period_from;
224    end if;
225    --
226    hr_utility.set_location('      In:'||l_proc||', rederiving calendar',10);
227    --
228    g_period_to   := p_period_to;
229    g_calendar_id := p_calendar_id;
230    index_no := 1;
231    --
232    open calendar;
233    fetch calendar into start_position, cycle_date, l_pattern_id;
234    close calendar;
235    --
236    -- Get required pattern from the database, and convert it to units of a day.
237    --
238    if l_pattern_id <> pattern.stored_pattern_id then
239       --
240       -- Get pattern construction and cache it in private global variables
241       --
242       for next_bit in pattern_bits (l_pattern_id) LOOP
243          counter := counter+1;
244          --
245          pattern.duration_days (counter) :=
246                     hr_calendar_pkg.to_days (next_bit.time_unit_multiplier,
247                                              next_bit.base_time_unit);
248          pattern.availability (counter) := next_bit.availability;
249       end loop;
250       --
251       pattern.stored_pattern_id := l_pattern_id;
252       pattern.stored_number_of_bits := counter;
253    end if;
254    --
255    -- Bug 504386 - Find out the patterns total duration time
256    --
257    for n in first_bit..pattern.stored_number_of_bits LOOP
258       total_duration_time := total_duration_time + pattern.duration_days (n);
259    end loop;
260    --
261    -- Bug 504386 - Roll forward to the periods required.
262    first_loop := TRUE;
263    --
264    -- Bug 3669001 - change from p_period_from to g_period_from
265    while cycle_date <= g_period_from
266    loop
267       old_cycle_date := cycle_date;
268       --
269       if first_loop = TRUE
270       then
271          --
272          -- If we are in the first pass through the loop (ie we are on the first
273          -- iteration of the pattern) then we must take account of the position
274          -- in the pattern on which the calendar starts, because we may not want
275          -- to start at the beginning of the pattern.
276          --
277          first_loop := FALSE;
278          first_bit := start_position;
279          for n in first_bit..pattern.stored_number_of_bits LOOP
280             duration_time := duration_time + pattern.duration_days (n);
281          end loop;
282       else
283          --
284          -- If we are in any but the first pass through the loop, then we always
285          -- take the whole pattern into account.
286          --
287          duration_time := total_duration_time;
288       end if;
289       --
290       cycle_date := cycle_date + duration_time;
291    end loop;
292    --
293    --6850908 Begin
294    --cycle_date := old_cycle_date;
295     --before assigning the old cycle date the value is checked
296    IF old_cycle_date <= g_period_from THEN
297    cycle_date := old_cycle_date;
298    END IF;
299    --6850908 End
300    --
301    -- Generate a denormalised calendar by placing copies of the pattern end to
302    -- end, starting with the calendar start date and ending with the end of our
303    -- period of interest.
304    --
305    while cycle_date <= p_period_to
306    LOOP
307       --
308       -- Go through the cached pattern, deriving the dates of the calendar by
309       -- taking the date we have reached so far and adding the duration of the
310       -- next bit of the pattern to it.
311       --
312       for n in 1..pattern.stored_number_of_bits LOOP
313          --
314          -- Derive the dates of the next bit of the calendar.
315          --
316          normal_pattern.start_date (index_no) := cycle_date;
317          --
318          normal_pattern.end_date (index_no) :=
319                normal_pattern.start_date (index_no) + pattern.duration_days (n);
320          --
321          -- Increment 'date reached so far' by the duration of the pattern bit.
322          --
323          cycle_date := cycle_date + pattern.duration_days (n);
324          --
325          -- Derive the availability value for the next bit of the calendar.
326          --
327          normal_pattern.availability (index_no) := pattern.availability (n);
328          --
329          index_no := index_no + 1;
330          --
331       end loop;
332    end loop;
333 end if;
334 --
335 hr_utility.set_location('Leaving :'||l_proc,100);
336 --
337 end derive_pattern_cycle;
338 --------------------------------------------------------------------------------
339 --
340 procedure DERIVE_CALENDAR_EXCEPTIONS (
341 --
342 -- Cache the calendar exceptions in a pl/sql data structure for use in the
343 -- reconcile_schedule procedure.
344 --
345 p_calendar_id		number,
346 p_period_start_time	date,
347 p_period_end_time	date) is
348 --
349 cursor calendar_exceptions is
350 	--
351 	-- Get all the calendar exceptions for the calendar, which are within
352 	-- our period of interest
353 	--
354 	select	exc.pattern_id,
355 		exc.exception_start_time
356 	from	hr_pattern_exceptions	EXC,
357 		hr_exception_usages	EXC_USE
358 	where	exc.exception_start_time < p_period_end_time
359 	and	exc.exception_end_time > p_period_start_time
360 	and	exc.exception_id = exc_use.exception_id
361 	and	exc_use.calendar_id = p_calendar_id
362 	order by exc.exception_start_time;
363 --
364 index_no		integer :=1;
365 cycle_date		date;
366 --
367 begin
368 --
369 for next_exception in calendar_exceptions LOOP
370   --
371   -- For each exception in the period on the calendar, derive the dates of each
372   -- bit of the pattern on which the exception is based.
373   --
374   cycle_date := next_exception.exception_start_time;
378     --
375   --
376   for next_exception_bit in pattern_bits (next_exception.pattern_id)
377   LOOP
379     calendar_exception.start_date (index_no) := cycle_date;
380     --
381     -- Increment the date reached so far by the duration of the next pattern bit
382     --
383     cycle_date := cycle_date
384 	+ (hr_calendar_pkg.to_days (next_exception_bit.time_unit_multiplier,
385 					next_exception_bit.base_time_unit)) ;
386 					--
387     calendar_exception.end_date (index_no) := cycle_date ;
388     --
389     calendar_exception.availability (index_no)
390 	:= next_exception_bit.availability;
391     --
392     index_no := index_no+1;
393     --
394   end loop;
395   --
396 end loop;
397 --
398 end derive_calendar_exceptions;
399 --------------------------------------------------------------------------------
400 --
401 procedure DERIVE_USAGE_EXCEPTIONS (
402 --
403 p_calendar_usage_id	number,
404 p_period_start_time	date,
405 p_period_end_time	date) is
406 --
407 cursor usage_exceptions is
408 	--
409 	-- Get all the exceptions for the specified usage which are within the
410 	-- period of interest.
411 	--
412 	select	exc.pattern_id,
413 		exc.exception_start_time
414 	from	hr_pattern_exceptions	EXC,
415 		hr_exception_usages	EXC_USE
416 	where	exc.exception_start_time < p_period_end_time
417 	and	exc.exception_end_time > p_period_start_time
418 	and	exc.exception_id = exc_use.exception_id
419 	and	exc_use.calendar_usage_id = p_calendar_usage_id
420 	order by exc.exception_start_time;
421 --
422 index_no		integer :=1;
423 cycle_date		date;
424 --
425 begin
426 --
427 for next_exception in usage_exceptions LOOP
428   --
429   -- For each exception, derive the dates of each bit of the pattern on which
430   -- the exception is based.
431   --
432   cycle_date := next_exception.exception_start_time;
433   --
434   for next_exception_bit in pattern_bits (next_exception.pattern_id)
435   LOOP
436     --
437     usage_exception.start_date (index_no) := cycle_date;
438     --
439     -- Increment the date reached so far by the duration of the next pattern bit
440     --
441     cycle_date := cycle_date
442 	+ (hr_calendar_pkg.to_days (next_exception_bit.time_unit_multiplier,
443  					next_exception_bit.base_time_unit)) ;
444 					--
445     usage_exception.end_date (index_no) := cycle_date  ;
446     --
447     usage_exception.availability (index_no) := next_exception_bit.availability;
448     --
449     index_no := index_no+1;
450     --
451   end loop;
452   --
453 end loop;
454 --
455 end derive_usage_exceptions;
456 --------------------------------------------------------------------------------
457 procedure RECONCILE_SCHEDULE (
458 --
459 -- Reconcile the repeating pattern on which the calendar is based with all the
460 -- exceptions to that pattern at calendar and usage level.
461 --
462 p_period_from	date,
463 p_period_to	date) is
464 --
465 cycle_date	date := p_period_from;
466 --
467 begin
468 --
469 -- Reset the pointers
470 --
471 usage_exception.pointer :=1;
472 calendar_exception.pointer :=1;
473 normal_pattern.pointer :=1;
474 usage_exception.run_out := FALSE;
475 calendar_exception.run_out := FALSE;
476 normal_pattern.run_out := FALSE;
477 --
478 -- Construct the schedule from the start to the end of the requested period
479 --
480 while cycle_date < p_period_to LOOP
481   --
482   -- There are 3 stacks to be merged; the normal pattern, the exceptions
483   -- which apply to the calendar as a whole (calendar exceptions), and
484   -- the exceptions which apply only to a particular entity (usage
485   -- exceptions).
486   --
487   -- Set the pointers of each stack to the current or next date
488   --
489   -- Set the usage exception stack pointer
490   --
491   if (not usage_exception.run_out) then
492     --
493     begin
494     --
495     LOOP
496       --
497       -- Find the first row which is later than the date we have reached so far
498       --
499       exit when usage_exception.end_date (usage_exception.pointer) > cycle_date;
500       usage_exception.pointer := usage_exception.pointer +1;
501       --
502     end loop;
503     --
504     exception
505     when no_data_found then
506       --
507       -- There are no more rows in the data structure so do not attempt more
508       -- fetches. Set flag to prevent this.
509       --
510       usage_exception.run_out := TRUE;
511       --
512     end;
513     --
514   end if;
515   --
516   -- Set the calendar excption stack pointer
517   --
518   if (not calendar_exception.run_out) then
519     --
520     begin
521     --
522     LOOP
523       --
524       -- Find the first row which is later than the date we have reached so far
525       --
526       exit when calendar_exception.end_date (calendar_exception.pointer)
527 	> cycle_date;
528       calendar_exception.pointer := calendar_exception.pointer +1;
529       --
530     end loop;
531     --
532     exception
533     when no_data_found then
537       --
534       --
535       -- There are no more rows in the data structure so do not attempt more
536       -- fetches. Set flag to prevent this.
538       calendar_exception.run_out := TRUE;
539       --
540     end;
541     --
542   end if;
543   --
544   -- Set the normal pattern stack pointer
545   --
546   if (not normal_pattern.run_out) then
547     --
548     begin
549     --
550     LOOP
551       --
552       exit when normal_pattern.end_date (normal_pattern.pointer) > cycle_date;
553       normal_pattern.pointer := normal_pattern.pointer +1;
554       --
555     end loop;
556     --
557     exception
558     when no_data_found then
559       normal_pattern.run_out := TRUE;
560     end;
561     --
562   end if;
563   --
564   schedule.start_date (schedule.pointer) := cycle_date;
565   --
566   if (not usage_exception.run_out)
567   and usage_exception.start_date (usage_exception.pointer) <=cycle_date then
568     --
569     -- We are currently on a usage exception. Usage exceptions override
570     -- all other levels, so the schedule takes on all the values of the
571     -- usage exception.
572     --
573     schedule.level (schedule.pointer) := 3;
574     schedule.availability (schedule.pointer)
575 	:= usage_exception.availability (usage_exception.pointer);
576     schedule.end_date (schedule.pointer)
577 	:= usage_exception.end_date (usage_exception.pointer);
578     --
579   elsif (not calendar_exception.run_out)
580   and calendar_exception.start_date (calendar_exception.pointer)
581 	<= cycle_date then
582     --
583     -- We are currently on a calendar exception. Assign the level and
584     -- availability values of the calendar exception to the schedule
585     --
586     schedule.level (schedule.pointer) := 2;
587     schedule.availability (schedule.pointer)
588 	:= calendar_exception.availability (calendar_exception.pointer);
589     --
590     -- Before we can assign the end date value to the schedule, we must
591     -- determine if there is a usage exception starting before the calendar
592     -- exception ends, because that start date would take precedence
593     --
594     if (not usage_exception.run_out)
595     and usage_exception.start_date (usage_exception.pointer)
596 	< calendar_exception.end_date (calendar_exception.pointer)
597     then
598       schedule.end_date (schedule.pointer)
599 	:= usage_exception.start_date (usage_exception.pointer) ;
600     else
601       schedule.end_date (schedule.pointer)
602 	:= calendar_exception.end_date (calendar_exception.pointer);
603     end if;
604     --
605   else
606     --
607     -- If we get to this point, there must be no exceptions so we are on the
608     -- normal pattern. Assign the level and availability values to those of
609     -- the normal pattern.
610     --
611     schedule.level (schedule.pointer) := 1;
612     schedule.availability (schedule.pointer)
613 	:= normal_pattern.availability (normal_pattern.pointer);
614     --
615     -- Before we can assign the end date of the normal pattern bit to the
616     -- schedule, we must determine if there are any exceptions which start
617     -- before the normal bit ends. The start of such an exception would take
618     -- precedence over the end of the normal pattern bit.
619     --
620     -- First check for usage exceptions
621     --
622     if (not usage_exception.run_out)
623     and usage_exception.start_date (usage_exception.pointer)
624 	< normal_pattern.end_date (normal_pattern.pointer) then
625       --
626       schedule.end_date (schedule.pointer)
627 	:= usage_exception.start_date (usage_exception.pointer) ;
628       --
629     -- Now check for calendar exceptions
630     --
631     elsif (not calendar_exception.run_out)
632     and calendar_exception.start_date (calendar_exception.pointer)
633 	< normal_pattern.end_date (normal_pattern.pointer) then
634       --
635       schedule.end_date (schedule.pointer) :=
636       calendar_exception.start_date (calendar_exception.pointer) ;
637       --
638     else
639       --
640       -- There are no exceptions before the normal pattern bit ends
641       --
642       schedule.end_date (schedule.pointer)
643 	:= normal_pattern.end_date (normal_pattern.pointer);
644       --
645     end if;
646     --
647   end if;
648   --
649   if schedule.end_date (schedule.pointer) > p_period_to then
650     --
651     -- Drag the end date back to the end of the period
652     --
653     schedule.end_date (schedule.pointer) := p_period_to;
654     --
655   end if;
656   --
657   -- Move on to the next bit of the schedule
658   --
659   cycle_date := schedule.end_date (schedule.pointer) + one_second ;
660   --
661   schedule.pointer := schedule.pointer +1;
662   --
663 end loop;
664 --
665 end reconcile_schedule;
666 --------------------------------------------------------------------------------
667 --
668 function START_DATE (row_number integer) return date is
669 --
670 -- Returns the start date of the pl/sql table row identified by the row_number
671 --
672 l_start_date	date;
673 --
674 begin
675 --
679 --
676 l_start_date := schedule.start_date (row_number);
677 --
678 return l_start_date;
680 exception
681 when no_data_found then
682 return null;
683 end start_date;
684 --------------------------------------------------------------------------------
685 --
686 function END_DATE (row_number integer) return date is
687 --
688 -- Returns the end date of the pl/sql table row identified by the row_number
689 --
690 begin
691 --
692 return schedule.end_date (row_number);
693 --
694 exception
695 when no_data_found then
696 return null;
697 end end_date;
698 --------------------------------------------------------------------------------
699 --
700 function AVAILABILITY_VALUE (row_number integer) return varchar2 is
701 --
702 -- Returns the availability of the pl/sql table row identified by the row_number
703 --
704 begin
705 --
706 return schedule.availability (row_number);
707 --
708 exception
709 when no_data_found then
710 return null;
711 end availability_value;
712 --------------------------------------------------------------------------------
713 --
714 function SCHEDULE_LEVEL_VALUE (row_number integer) return number is
715 --
716 -- Returns the level of the pl/sql table row identified by the row_number
717 --
718 begin
719 --
720 return schedule.level (row_number);
721 --
722 exception
723 when no_data_found then
724 return null;
725 end schedule_level_value;
726 --------------------------------------------------------------------------------
727 --
728 procedure DENORMALISE_CALENDAR (
729 --
730 -- Derive a denormalised calendar into an internal pl/sql data structure, for
731 -- the calendar usage passed in. Take into account the repetitive pattern on
732 -- which the calendar is based, and all exceptions for both the calendar itself
733 -- and for the usage.
734 -- NB This procedure is OVERLOADED 3 times! This one is called by SSP.
735 --
736 -- Bug 513292 - new cursor which returns both BG and person patterns depending
737 --              which parameters are passed in.
738 --
739 p_person_purpose_usage_id	number,
740 p_person_primary_key_value	number,
741 p_bg_purpose_usage_id   	number,
742 p_bg_primary_key_value     	number,
743 p_period_from			date,
744 p_period_to			date,
745 p_called_from_SSP               boolean default false) is
746 --
747 cursor calendar is
748 	--
749 	-- Get the calendars and usages
750 	--
751 	select	use.calendar_usage_id,
752 		use.calendar_id,
753 		use.start_date,
754 		use.end_date
755 	from	hr_calendar_usages 	USE
756 	where	use.purpose_usage_id = p_bg_purpose_usage_id
757 	and	use.primary_key_value = p_bg_primary_key_value
758 	and	use.start_date <= p_period_to
759 	and	use.end_date >= p_period_from
760 	UNION ALL
761         select  use.calendar_usage_id,
762                 use.calendar_id,
763                 use.start_date,
764                 use.end_date
765         from    hr_calendar_usages      USE
766         where   use.purpose_usage_id = p_person_purpose_usage_id
767         and     use.primary_key_value = p_person_primary_key_value
768         and     use.start_date <= p_period_to
769         and     use.end_date >= p_period_from
770         order by 3;
771 --
772 start_of_period	date;
773 end_of_period	date;
774 --
775 begin
776 --
777 -- Clear the data structures
778 --
779 schedule := empty_stack;
780 --
781 -- Denormalise the exceptions for the usage and hold them internally
782 --
783 for each_calendar_usage in calendar
784 LOOP
785    --
786    start_of_period := greatest (each_calendar_usage.start_date, p_period_from);
787    end_of_period := least (each_calendar_usage.end_date, p_period_to);
788    --
789    if initialise_flag <> true then
790       normal_pattern := empty_stack;
791       initialise_flag := true;
792       calendar_exception := empty_stack;
793       usage_exception := empty_stack;
794    end if;
795    --
796    derive_pattern_cycle(each_calendar_usage.calendar_id,
797                         start_of_period, end_of_period,
798                         p_called_from_SSP);
799    --
800    derive_calendar_exceptions(each_calendar_usage.calendar_id,
801                         start_of_period, end_of_period);
802    --
803    derive_usage_exceptions (each_calendar_usage.calendar_usage_id,
804                         start_of_period, end_of_period);
805    --
806    reconcile_schedule (start_of_period, end_of_period);
807    --
808 end loop;
809 --
810 end denormalise_calendar;
811 --------------------------------------------------------------------------------
812 --
813 procedure DENORMALISE_CALENDAR (
814 --
815 -- Derive a denormalised calendar into an internal pl/sql data structure, for
816 -- the calendar usage passed in. Take into account the repetitive pattern on
817 -- which the calendar is based, and all exceptions for both the calendar itself
818 -- and for the usage.
819 -- NB This procedure is OVERLOADED 3 times!
820 --
821 p_purpose_usage_id       number,
822 p_primary_key_value      number,
823 p_period_from            date,
827         --
824 p_period_to              date) is
825 --
826 cursor calendar is
828         -- Get the calendars and usages
829         --
830         select  use.calendar_usage_id,
831                 use.calendar_id,
832                 use.start_date,
833                 use.end_date
834         from    hr_calendar_usages      USE,
835                 hr_calendars            CAL
836         where   use.purpose_usage_id = p_purpose_usage_id
837         and     use.primary_key_value = p_primary_key_value
838         and     use.start_date <= p_period_to
839         and     use.end_date >= p_period_from
840         and     cal.calendar_id = use.calendar_id
841         order by use.start_date;
842 --
843 start_of_period date;
844 end_of_period   date;
845 --
846 begin
847 --
848 -- Bug 584613 - re-initialise global variables so that the Schedules window can
849 -- be re-queried.
850 --
851 g_period_from := null;
852 g_period_to   := null;
853 g_calendar_id := null;
854 --
855 -- Clear the data structures
856 --
857 schedule := empty_stack;
858 --
859 -- Denormalise the exceptions for the usage and hold them internally
860 --
861 for each_calendar_usage in calendar
862 LOOP
863   --
864   start_of_period := greatest (each_calendar_usage.start_date,
865                                 p_period_from);
866   end_of_period := least (each_calendar_usage.end_date,
867                                 p_period_to);
868                                 --
869   normal_pattern := empty_stack;
870   calendar_exception := empty_stack;
871   usage_exception := empty_stack;
872   --
873   derive_pattern_cycle  (each_calendar_usage.calendar_id,
874                         start_of_period,
875                         end_of_period);
876   --
877   derive_calendar_exceptions    (each_calendar_usage.calendar_id,
878                                 start_of_period,
879                                 end_of_period);
880   --
881   derive_usage_exceptions (each_calendar_usage.calendar_usage_id,
882                         start_of_period,
883                         end_of_period);
884 --
885   reconcile_schedule    (start_of_period,
886                         end_of_period);
887 --
888 end loop;
889 --
890 end denormalise_calendar;
891 ------------------------------------------------------------------------------
892 --
893 procedure DENORMALISE_CALENDAR (
894 --
895 -- Derive the denormalised calendar into an internal data structure. This
896 -- procedure does not require that usages be defined for the calendar and does
897 -- not take any usage exceptions into account.
898 -- NB This procedure is OVERLOADED 3 times!
899 --
900 p_calendar_id		number,
901 p_calendar_start_time	date,
902 p_period_from		date,
903 p_period_to		date) is
904 --
905 start_of_period	date := greatest (p_period_from, p_calendar_start_time);
906 end_of_period	date := p_period_to;
907 --
908 begin
909 -- Bug 584613 - re-initialise global variables so that the Schedules window can
910 -- be re-queried.
911 --
912 g_period_from := null;
913 g_period_to   := null;
914 g_calendar_id := null;
915 --
916 -- Clear the data structures
917 --
918 schedule := empty_stack;
919 usage_exception := empty_stack;
920 normal_pattern := empty_stack;
921 calendar_exception := empty_stack;
922 --
923 -- Get the pattern on which the calendar is based
924 --
925 derive_pattern_cycle	(p_calendar_id,
926                         start_of_period,
927 			end_of_period);
928 --
929 -- Get all the exceptions to the pattern which apply to the calendar
930 --
931 derive_calendar_exceptions	(p_calendar_id,
932 				start_of_period,
933 				end_of_period);
934 --
935 reconcile_schedule	(start_of_period,
936 			end_of_period);
937 --
938 end denormalise_calendar;
939 --------------------------------------------------------------------------------
940 --
941 function SCHEDULE_ROWCOUNT return number is
942 --
943 -- Returns the number of rows in the internal plsql data structure which stores
944 -- the denormalised calendar.
945 --
946 begin
947 --
948 return greatest (schedule.pointer -1,0);
949 --
950 end schedule_rowcount;
951 --------------------------------------------------------------------------------
952 --
953 function TOTAL_AVAILABILITY (
954 --
955 -- Returns the amount of time within a calendar for an individual that is
956 -- marked as having a specified availability. Eg how much time (in days) a
957 -- person is 'on-call'.
958 --
959 -- Bug 513292 - parameters added so that both BG and person patterns can be
960 --              returned for one (linked absence).
961 -- Bug 701750 - parameter p_processing_level to control amount of processing,
962 --              if called by SSP package SSP_SSP_PKG.
963 --
964 p_availability			varchar2,
965 p_person_purpose_usage_id	number,
966 p_person_primary_key_value	number,
967 p_bg_purpose_usage_id       	number,
968 p_bg_primary_key_value      	number,
969 p_period_from			date,
970 p_period_to			date,
974 l_called_from_SSP  boolean := false;
971 p_processing_level              number default 0) return number is
972 --
973 l_proc  varchar2 (42) := g_hc_package||'Total_Availability';
975 l_total            number :=0;
976 l_start_date date;
977 l_end_date   date;
978 --
979 begin
980 --
981 hr_utility.set_location('Entering:'||l_proc||'. Processing level: '||
982                          to_char(p_processing_level),1);
983 --
984 if p_processing_level > 0
985 then
986    l_called_from_SSP  := true;
987 end if;
988 --
989 -- derive the calendar for the required period
990 --
991 if p_processing_level <= 2 or g_period_from is null
992 then
993    denormalise_calendar(p_person_purpose_usage_id,
994                         p_person_primary_key_value,
995                         p_bg_purpose_usage_id,
996                         p_bg_primary_key_value,
997                         p_period_from,
998                         p_period_to,
999                         l_called_from_SSP);
1000 end if;
1001 --
1002 -- Loop through the schedule, adding up the duration of any period during
1003 -- which the availability matches the required availability value.
1004 --
1005 for this_row in 1..schedule_rowcount loop
1006 --   hr_utility.trace('Schedule rec: '||to_char(this_row) ||
1007 --                    '   Availability: '||schedule.availability (this_row));
1008 --   hr_utility.trace('       Dates: Start:'||
1009 --                    to_char(schedule.start_date (this_row)) || ', End:' ||
1010 --                    to_char(schedule.end_date (this_row)));
1011    --
1012    if schedule.availability (this_row) = p_availability then
1013       l_start_date := schedule.start_date(this_row);
1014       l_end_date   := schedule.end_date(this_row);
1015       --
1016       if p_processing_level > 1
1017       then
1018          if l_start_date < p_period_to
1019          then
1020             if l_end_date > p_period_from
1021             then
1022                if l_start_date < p_period_from
1023                then
1024                   l_start_date := p_period_from;
1025                end if;
1026 
1027                if l_end_date > p_period_to
1028                then
1029                   l_end_date := p_period_to;
1030                end if;
1031 
1032                l_total := l_total + (l_end_date - l_start_date);
1033 
1034                if p_processing_level = 3
1035                then
1036                   exit;
1037                end if;
1038             end if;
1039          else
1040             exit;
1041          end if;
1042       else
1043          l_total := l_total + (l_end_date - l_start_date);
1044       end if;
1045    end if;
1046 end loop;
1047 --
1048 hr_utility.set_location('Leaving :'||l_proc||'. Returning '||
1049                         substr(to_char(l_total),1,8)||' days.',100);
1050 --
1051 return l_total;
1052 --
1053 end total_availability;
1054 --------------------------------------------------------------------------------
1055 function AVAILABILITY (
1056 --
1057 -- Returns the availability value for an individual which is valid at a
1058 -- specified time. Eg At 8 o'clock on 12th March 1995, what is Fred Bloggs'
1059 -- availability?
1060 --
1061 	p_date_and_time		date,
1062 	p_purpose_usage_id	number,
1063 	p_primary_key_value	number)
1064 	--
1065 	return varchar2 is
1066 	--
1067 this_row	integer := 1;
1068 --
1069 begin
1070 --
1071 denormalise_calendar (	p_purpose_usage_id,
1072 			p_primary_key_value,
1073 			p_date_and_time-1,
1074 			p_date_and_time+1);
1075 --
1076 -- Find the row in the internal data structure which covers the required time
1077 --
1078 while this_row <> Schedule_rowcount LOOP
1079   --
1080   exit when p_date_and_time between schedule.start_date (this_row) and schedule.end_date (this_row);
1081   --
1082   this_row := this_row +1;
1083   --
1084 end loop;
1085 --
1086 return schedule.availability (this_row);
1087 --
1088 end availability;
1089 --------------------------------------------------------------------------------
1090 function PURPOSE_USAGE_ID (
1091 --
1092 -- Return the purpose usage id for a given entity name and pattern purpose
1093 --
1094 p_entity_name		varchar2,
1095 p_pattern_purpose	varchar2
1096 ) return number is
1097 --
1098 cursor csr_purpose_usage is
1099 	--
1100 	-- Get the pattern purpose usage id
1101 	--
1102 	select	purpose_usage_id
1103 	from	hr_pattern_purpose_usages
1104 	where	entity_name = p_entity_name
1105 	and	pattern_purpose = p_pattern_purpose;
1106 	--
1107 l_purpose_usage_id	number := null;
1108 --
1109 begin
1110 --
1111 open csr_purpose_usage;
1112 fetch csr_purpose_usage into l_purpose_usage_id;
1113 close csr_purpose_usage;
1114 --
1115 return l_purpose_usage_id;
1116 --
1117 end purpose_usage_id;
1118 --------------------------------------------------------------------------------
1119 --
1120 end hr_calendar_pkg;