DBA Data[Home] [Help]

PACKAGE BODY: APPS.CAC_AVLBLTY_PVT

Source


1 PACKAGE BODY CAC_AVLBLTY_PVT AS
2 /* $Header: caccapb.pls 120.7.12010000.7 2009/01/21 11:57:23 anangupt ship $ */
3 
4 /*******************************************************************************
5 ** Private APIs
6 *******************************************************************************/
7 
8 -- finish get_shift_bands method, use caching of objects
9 -- add sort for tasks/appointments in case of timezone conversion
10 
11 TYPE PERIOD_REC_TYPE IS RECORD
12 ( template_detail_id NUMBER
13 , period_id          NUMBER
14 , period_span_ms     NUMBER
15 , day_num            NUMBER
16 , day_start_ms       NUMBER
17 );
18 
19 TYPE PERIOD_TBL_TYPE IS TABLE OF PERIOD_REC_TYPE
20   INDEX BY BINARY_INTEGER;
21 
22 TYPE SCHDL_DETAILS_REC_TYPE IS RECORD
23 ( period_id        NUMBER
24 , start_date_time  DATE
25 , end_date_time    DATE
26 );
27 
28 TYPE SCHDL_DETAILS_TBL_TYPE IS TABLE OF SCHDL_DETAILS_REC_TYPE
29   INDEX BY BINARY_INTEGER;
30 
31 
32 FUNCTION ADJUST_FOR_TIMEZONE
33 ( p_source_tz_id     IN     NUMBER
34 , p_dest_tz_id       IN     NUMBER
35 , p_source_day_time  IN     DATE
36 )RETURN DATE
37 IS
38 
39   l_dest_day_time    DATE;
40   l_return_status    VARCHAR2(1);
41   l_msg_count        NUMBER;
42   l_msg_data         VARCHAR2(2000);
43 
44 BEGIN
45   IF (p_source_day_time IS NOT NULL)
46   THEN
47     --
48     -- Only adjust if the timezones are different and not NULL
49     --
50     IF (   (p_Source_tz_id IS NOT NULL)
51        AND (p_Source_tz_id <> p_dest_tz_id)
52        )
53     THEN
54       --
55       -- Call the API to get the adjusted date (this API is slow..)
56       --
57       HZ_TIMEZONE_PUB.Get_Time( p_api_version     => 1.0
58                               , p_init_msg_list   => FND_API.G_FALSE
59                               , p_source_tz_id    => p_Source_tz_id
60                               , p_dest_tz_id      => p_dest_tz_id
61                               , p_source_day_time => p_source_day_time
62                               , x_dest_day_time   => l_dest_day_time
63                               , x_return_status   => l_return_status
64                               , x_msg_count       => l_msg_count
65                               , x_msg_data        => l_msg_data
66                               );
67 
68       RETURN l_dest_day_time;
69 
70     ELSE
71       RETURN p_source_day_time;
72 
73     END IF;
74   ELSE
75     RETURN p_source_day_time;
76 
77   END IF;
78 
79 END ADJUST_FOR_TIMEZONE;
80 
81 
82 FUNCTION CONVERT_TO_MILLIS
83 /*******************************************************************************
84 **  CONVERT_TO_MILLIS
85 **
86 **  Will return the period + UOM in day so it can be added to an Oracle DATE.
87 *******************************************************************************/
88 ( p_Duration IN NUMBER
89 , p_UOM      IN VARCHAR2
90 )RETURN NUMBER
91 
92 IS
93 
94 BEGIN
95   IF (p_UOM = 'MIN')
96   THEN
97     RETURN (p_Duration*60*1000);
98   ELSIF (p_UOM = 'HR')
99   THEN
100     RETURN (p_Duration*3600*1000);
101   ELSIF (p_UOM = 'DAY')
102   THEN
103     RETURN (p_Duration*24*3600*1000);
104   ELSIF (p_UOM = 'WK')
105   THEN
106     RETURN (p_Duration*7*24*3600*1000);
107   ELSE
108     RETURN NULL;
109   END IF;
110 END CONVERT_TO_MILLIS;
111 
112 
113 FUNCTION GET_SHIFT_BANDS
114 /*******************************************************************************
115 **  GET_SHIFT_BANDS
116 **
117 **  Will create a new CAC_AVLBLTY_TIME_BAND_VARRAY collection.
118 *******************************************************************************/
119 ( p_period_id       IN NUMBER
120 ) RETURN CAC_AVLBLTY_TIME_BAND_VARRAY IS
121 
122   l_shift_bands        CAC_AVLBLTY_TIME_BAND_VARRAY;
123 
124 BEGIN
125 
126   l_shift_bands := CAC_AVLBLTY_TIME_BAND_VARRAY();
127 
128   RETURN l_shift_bands;
129 
130 END GET_SHIFT_BANDS;
131 
132 PROCEDURE CREATE_AVLBLTY_SUMMARY
133 /*******************************************************************************
134 **  CREATE_AVLBLTY_SUMMARY
135 **
136 **  Will create a new object in the CAC_AVLBLTY_SUMMARY_VARRAY collection.
137 *******************************************************************************/
138 ( p_blank_record    IN BOOLEAN
139 , p_start_dt        IN DATE
140 , p_end_dt          IN DATE
141 , p_category_id     IN NUMBER
142 , p_category_name   IN VARCHAR2
143 , p_free_busy       IN VARCHAR2
144 , p_display_color   IN VARCHAR2
145 , x_avlblty_summary IN OUT NOCOPY CAC_AVLBLTY_SUMMARY_VARRAY
146 , x_index           IN OUT NOCOPY NUMBER
147 ) IS
148 
149   l_summary_date  DATE;
150   l_detail_v      CAC_AVLBLTY_DETAIL_VARRAY;
151   l_daytime_v     CAC_AVLBLTY_DAY_TIME_VARRAY;
152   l_found_index   BOOLEAN;
153   l_last_index    NUMBER;
154   l_end_dt        DATE;
155   l_dt            DATE;
156 
157 BEGIN
158 
159   IF ((p_blank_record) OR (p_category_id IS NULL))
160   THEN
161     RETURN;
162   END IF;
163 
164   IF (x_index IS NULL)
165   THEN
166     x_index := 0;
167   ELSE
168     l_summary_date := x_avlblty_summary(x_index).SUMMARY_DATE;
169   END IF;
170 
171   IF (TRUNC(p_end_dt) > TRUNC(p_start_dt))
172   THEN
173     l_end_dt := TRUNC(p_start_dt) + 1;
174   ELSE
175     l_end_dt := p_end_dt;
176   END IF;
177 
178   IF (TRUNC(p_start_dt) = l_summary_date)
179   THEN
180     l_found_index := false;
181     l_detail_v := x_avlblty_summary(x_index).SUMMARY_LINES;
182     FOR i in l_detail_v.first..l_detail_v.last
183     LOOP
184       IF (l_detail_v(i).PERIOD_CATEGORY_ID = p_category_id)
185       THEN
186         l_found_index := true;
187         l_daytime_v   := l_detail_v(i).DAY_TIMES;
188         l_last_index  := l_daytime_v.COUNT;
189         IF (l_daytime_v(l_last_index).END_DATE_TIME = p_start_dt)
190         THEN
191           l_daytime_v(l_last_index).END_DATE_TIME := l_end_dt;
192         ELSE
193           l_daytime_v.EXTEND(1);
194           l_daytime_v(l_last_index+1) := CAC_AVLBLTY_DAY_TIME
195                                          (
196                                            START_DATE_TIME  => p_start_dt,
197                                            END_DATE_TIME    => l_end_dt
198                                          );
199         END IF;
200         l_detail_v(i).TOTAL_TIME_MS := l_detail_v(i).TOTAL_TIME_MS + (l_end_dt-p_start_dt)*24*3600*1000;
201         l_detail_v(i).DAY_TIMES     := l_daytime_v;
202         EXIT;
203       END IF;
204     END LOOP;
205     IF (NOT l_found_index)
206     THEN
207       l_last_index := l_detail_v.COUNT;
208       l_daytime_v := CAC_AVLBLTY_DAY_TIME_VARRAY();
209       l_daytime_v.EXTEND(1);
210       l_daytime_v(1) := CAC_AVLBLTY_DAY_TIME
211                         (
212                           START_DATE_TIME  => p_start_dt,
213                           END_DATE_TIME    => l_end_dt
214                         );
215       l_detail_v.EXTEND(1);
216       l_detail_v(l_last_index+1) := CAC_AVLBLTY_DETAIL
217                                      (
218                                        TOTAL_TIME_MS        => (l_end_dt-p_start_dt)*24*3600*1000,
219                                        PERIOD_CATEGORY_ID   => p_category_id,
220                                        PERIOD_CATEGORY_NAME => p_category_name,
221                                        FREE_BUSY_TYPE       => p_free_busy,
222                                        DISPLAY_COLOR        => p_display_color,
223                                        DAY_TIMES            => l_daytime_v
224                                      );
225     END IF;
226     x_avlblty_summary(x_index).SUMMARY_LINES := l_detail_v;
227   ELSE
228     x_index := x_index + 1;
229     l_daytime_v := CAC_AVLBLTY_DAY_TIME_VARRAY();
230     l_daytime_v.EXTEND(1);
231     l_daytime_v(1) := CAC_AVLBLTY_DAY_TIME
232                       (
233                         START_DATE_TIME  => p_start_dt,
234                         END_DATE_TIME    => l_end_dt
235                       );
236     l_detail_v := CAC_AVLBLTY_DETAIL_VARRAY();
237     l_detail_v.EXTEND(1);
238     l_detail_v(1) := CAC_AVLBLTY_DETAIL
239                      (
240                        TOTAL_TIME_MS        => (l_end_dt-p_start_dt)*24*3600*1000,
241                        PERIOD_CATEGORY_ID   => p_category_id,
242                        PERIOD_CATEGORY_NAME => p_category_name,
243                        FREE_BUSY_TYPE       => p_free_busy,
244                        DISPLAY_COLOR        => p_display_color,
245                        DAY_TIMES            => l_daytime_v
246                      );
247     x_avlblty_summary.EXTEND(1);
248     x_avlblty_summary(x_index) := CAC_AVLBLTY_SUMMARY
249                                   (
250                                     SUMMARY_DATE  => TRUNC(p_start_dt),
251                                     SUMMARY_LINES => l_detail_v
252                                   );
253   END IF;
254 
255   -- loop by incrementing a day
256   l_dt := TRUNC(p_start_dt) + 1;
257   WHILE (p_end_dt > l_dt)
258   LOOP
259     l_end_dt := l_dt + 1;
260     IF (l_end_dt > p_end_dt)
261     THEN
262       l_end_dt := p_end_dt;
263     END IF;
264     x_index := x_index + 1;
265     l_daytime_v := CAC_AVLBLTY_DAY_TIME_VARRAY();
266     l_daytime_v.EXTEND(1);
267     l_daytime_v(1) := CAC_AVLBLTY_DAY_TIME
268                       (
269                         START_DATE_TIME  => l_dt,
270                         END_DATE_TIME    => l_end_dt
271                       );
272     l_detail_v := CAC_AVLBLTY_DETAIL_VARRAY();
273     l_detail_v.EXTEND(1);
274     l_detail_v(1) := CAC_AVLBLTY_DETAIL
275                      (
276                        TOTAL_TIME_MS        => (l_end_dt-l_dt)*24*3600*1000,
277                        PERIOD_CATEGORY_ID   => p_category_id,
278                        PERIOD_CATEGORY_NAME => p_category_name,
279                        FREE_BUSY_TYPE       => p_free_busy,
280                        DISPLAY_COLOR        => p_display_color,
281                        DAY_TIMES            => l_daytime_v
282                      );
283     x_avlblty_summary.EXTEND(1);
284     x_avlblty_summary(x_index) := CAC_AVLBLTY_SUMMARY
285                                   (
286                                     SUMMARY_DATE  => TRUNC(l_dt),
287                                     SUMMARY_LINES => l_detail_v
288                                   );
289     l_dt := l_dt + 1;
290   END LOOP;
291 
292 END CREATE_AVLBLTY_SUMMARY;
293 
294 PROCEDURE CREATE_AVLBLTY_TIME
295 /*******************************************************************************
296 **  CREATE_AVLBLTY_TIME
297 **
298 **  Will create a new object in the CAC_AVLBLTY_TIME_VARRAY collection.
299 *******************************************************************************/
300 ( p_blank_record    IN BOOLEAN
301 , p_period_name     IN VARCHAR2
302 , p_start_dt        IN DATE
303 , p_end_dt          IN DATE
304 , p_duration        IN NUMBER
305 , p_category_id     IN NUMBER
306 , p_category_name   IN VARCHAR2
307 , p_free_busy       IN VARCHAR2
308 , p_display_color   IN VARCHAR2
309 , p_update_next     IN BOOLEAN
310 , p_shift_bands     IN CAC_AVLBLTY_TIME_BAND_VARRAY
311 , x_avlblty_time    IN OUT NOCOPY CAC_AVLBLTY_TIME_VARRAY
312 , x_index           IN OUT NOCOPY NUMBER
313 ) IS
314 
315   l_start_dt  DATE;
316 
317 BEGIN
318   IF (x_index IS NULL)
319   THEN
320     x_index := 1;
321   ELSE
322     IF (p_update_next)
323     THEN
324       -- see if the previous one should be merged with the current one
325       IF (((NOT p_blank_record) AND (x_avlblty_time(x_index).PERIOD_CATEGORY_ID =
326         p_category_id)) OR (p_blank_record AND
327         x_avlblty_time(x_index).PERIOD_CATEGORY_ID IS NULL))
328       THEN
329         x_avlblty_time(x_index).END_DATE_TIME := p_end_dt;
330         x_avlblty_time(x_index).DURATION_MS := x_avlblty_time(x_index).DURATION_MS +
331                                                (p_end_dt-p_start_dt)*24*3600*1000;
332         RETURN;
333       END IF;
334       x_avlblty_time(x_index).NEXT_OBJECT_INDEX := x_index + 1;
335       /*IF (x_avlblty_time(x_index).end_date_time < p_start_dt)
336       THEN
337         l_start_dt := x_avlblty_time(x_index).end_date_time;
338         x_index := x_index + 1;
339         x_avlblty_time.EXTEND(1);
340         x_avlblty_time(x_index) := CAC_AVLBLTY_TIME
341                                    (
342                                      PERIOD_NAME          => NULL,
343                                      START_DATE_TIME      => l_start_dt,
344                                      END_DATE_TIME        => p_start_dt,
345                                      DURATION_MS          => (p_start_dt-l_start_dt)*24*3600*1000,
346                                      PERIOD_CATEGORY_ID   => NULL,
347                                      PERIOD_CATEGORY_NAME => NULL,
348                                      FREE_BUSY_TYPE       => NULL,
349                                      DISPLAY_COLOR        => NULL,
350                                      SUPER_OBJECT_INDEX   => NULL,
351                                      SHIFT_BANDS          => NULL,
352                                      NEXT_OBJECT_INDEX    => x_index+1
353                                    );
354       END IF;*/
355     END IF;
356     x_index := x_index + 1;
357   END IF;
358   x_avlblty_time.EXTEND(1);
359 
360   IF (p_blank_record)
361   THEN
362     x_avlblty_time(x_index) := CAC_AVLBLTY_TIME
363                                (
364                                  PERIOD_NAME          => NULL,
365                                  START_DATE_TIME      => p_start_dt,
366                                  END_DATE_TIME        => p_end_dt,
367                                  DURATION_MS          => (p_end_dt-p_start_dt)*24*3600*1000,
368                                  PERIOD_CATEGORY_ID   => NULL,
369                                  PERIOD_CATEGORY_NAME => NULL,
370                                  FREE_BUSY_TYPE       => NULL,
371                                  DISPLAY_COLOR        => NULL,
372                                  SUPER_OBJECT_INDEX   => NULL,
373                                  SHIFT_BANDS          => NULL,
374                                  NEXT_OBJECT_INDEX    => NULL
375                                );
376   ELSE
377     x_avlblty_time(x_index) := CAC_AVLBLTY_TIME
378                                (
379                                  PERIOD_NAME          => p_period_name,
380                                  START_DATE_TIME      => p_start_dt,
381                                  END_DATE_TIME        => p_end_dt,
382                                  DURATION_MS          => p_duration,
383                                  PERIOD_CATEGORY_ID   => p_category_id,
384                                  PERIOD_CATEGORY_NAME => p_category_name,
385                                  FREE_BUSY_TYPE       => p_free_busy,
386                                  DISPLAY_COLOR        => p_display_color,
387                                  SUPER_OBJECT_INDEX   => NULL,
388                                  SHIFT_BANDS          => p_shift_bands,
389                                  NEXT_OBJECT_INDEX    => NULL
390                                );
391   END IF;
392 
393 END CREATE_AVLBLTY_TIME;
394 
395 
396 PROCEDURE GET_SCHEDULE_DATA
397 /*******************************************************************************
398 **
399 ** GET_SCHEDULE_DATA
400 **
401 **   returns the schedule for the given:
402 **   - Object Instance
403 **   - Schedule Type
404 **   - Period
405 **
406 *******************************************************************************/
407 ( p_Object_Type          IN     VARCHAR2             -- JTF OBJECTS type of the Object being queried
408 , p_Object_ID            IN     NUMBER               -- JTF OBJECTS select ID of the Object Instance being queried
409 , p_Start_Date_Time      IN     DATE                 -- start date and time of period of interest
410 , p_End_Date_Time        IN     DATE                 -- end date and time of period of interest
411 , p_Schdl_Cat            IN     VARCHAR2             -- Schedule Category of the schedule instance we'll look at
412 , p_Include_Exception    IN     VARCHAR2             -- 'T' or 'F' depending on whether the exceptions be included or not
413 , p_Busy_Tentative       IN     VARCHAR2             -- How to treat periods with FREEBUSYTYPE = BUSY TENTATIVE?
414                                                      -- FREE: BUSY TENTATIVE means FREE
415                                                      -- BUSY: BUSY TENTATIVE means BUSY
416                                                      -- NULL: leave the interpretation to caller
417 , p_return_type          IN     VARCHAR2             -- 'D': Detailed schedule
418                                                      -- 'S': Schedule Summary
419                                                      -- 'B': Both detailed and summary of schedule
420 , x_Schedule             OUT NOCOPY CAC_AVLBLTY_TIME_VARRAY
421 , x_Schedule_Summary     OUT NOCOPY CAC_AVLBLTY_SUMMARY_VARRAY
422                                                      --  return schedule
423 )
424 IS
425 
426   CURSOR C_SCHEDULE
427   (
428    b_schdl_cat      VARCHAR2,
429    b_object_type    VARCHAR2,
430    b_object_id      NUMBER,
431    b_start_dt       DATE,
432    b_end_dt         DATE,
433    b_busy_tentative VARCHAR2
434   ) IS
435    SELECT  CSSB.SCHEDULE_ID,
436            CSSD.START_DATE_TIME,
437            CSSD.END_DATE_TIME,
438            CSPVL.PERIOD_ID,
439            CSPVL.HAS_DETAILS,
440            CSPVL.DURATION,
441            CSPVL.DURATION_UOM,
442            NVL(CSPVL.PERIOD_NAME,FL.MEANING) AS PERIOD_NAME,
443            CSPCVL.PERIOD_CATEGORY_ID,
444            CSPCVL.PERIOD_CATEGORY_NAME,
445            DECODE(CSPCVL.FREE_BUSY_TYPE,'FREE','FREE','BUSY','BUSY',NVL(b_busy_tentative,'TENTATIVE')) FREE_BUSY_TYPE,
446            CSPCVL.DISPLAY_COLOR
447     FROM CAC_SR_SCHDL_OBJECTS CSSO,
448          CAC_SR_SCHEDULES_B CSSB,
449          CAC_SR_SCHDL_DETAILS CSSD,
450          CAC_SR_PERIODS_VL CSPVL,
451          CAC_SR_PERIOD_CATS_VL CSPCVL,
452          FND_LOOKUPS FL
453     WHERE CSSO.OBJECT_TYPE = b_object_type
454     AND CSSO.OBJECT_ID = b_object_id
455     AND CSSO.START_DATE_ACTIVE <= b_end_dt
456     AND CSSO.END_DATE_ACTIVE >= b_start_dt
457     AND CSSO.SCHEDULE_ID = CSSB.SCHEDULE_ID
458     AND CSSB.DELETED_DATE IS NULL
459     AND (CSSB.SCHEDULE_CATEGORY = b_schdl_cat
460          OR CSSB.SCHEDULE_ID IN (SELECT SCHEDULE_ID
461                                  FROM CAC_SR_PUBLISH_SCHEDULES
462                                  WHERE OBJECT_TYPE = b_object_type
463                                  AND OBJECT_ID = b_object_id
464                                  AND b_schdl_cat IS NULL
465                                 ))
466     AND CSSD.SCHEDULE_OBJECT_ID = CSSO.SCHEDULE_OBJECT_ID
467     AND CSSD.START_DATE_TIME < b_end_dt
468     AND CSSD.END_DATE_TIME > b_start_dt
469     AND CSPVL.PERIOD_ID = CSSD.PERIOD_ID
470     AND CSPCVL.PERIOD_CATEGORY_ID = CSPVL.PERIOD_CATEGORY_ID
471     AND FL.LOOKUP_TYPE(+) = 'CAC_SR_WEEK_DAY'
472     AND FL.LOOKUP_CODE(+) = CSPVL.week_day_num
473     ORDER BY CSSD.START_DATE_TIME;
474 
475   CURSOR C_EXCEPTION
476   (
477    b_schdl_cat      VARCHAR2,
478    b_object_type    VARCHAR2,
479    b_object_id      NUMBER,
480    b_start_dt       DATE,
481    b_end_dt         DATE,
482    b_busy_tentative VARCHAR2
483   ) IS
484     SELECT CSEVL.EXCEPTION_ID,
485            CSEVL.START_DATE_TIME,
486            DECODE(CSEVL.WHOLE_DAY_FLAG,'N',CSEVL.END_DATE_TIME,CSEVL.END_DATE_TIME+1) END_DATE_TIME, -- Add 24 hrs if it's whole day
487            CSEVL.EXCEPTION_NAME,
488            CSPVL.PERIOD_CATEGORY_ID,
489            CSPVL.PERIOD_CATEGORY_NAME,
490            DECODE(CSPVL.FREE_BUSY_TYPE,'FREE','FREE','BUSY','BUSY',NVL(b_busy_tentative,'TENTATIVE')) FREE_BUSY_TYPE,
491            CSPVL.DISPLAY_COLOR,
492            CSEVL.HR_CAL_EVENT_TYPE,
493            CSEVL.HR_CAL_EVENT_ID,
494            DECODE(CSSE.SCHEDULE_OBJECT_ID,NULL,
495              DECODE(CSEVL.HR_CAL_EVENT_TYPE,NULL,
496                DECODE(CSEVL.HR_CAL_EVENT_ID,NULL,3,2),1),
497              DECODE(CSEVL.HR_CAL_EVENT_TYPE,NULL,
498                DECODE(CSEVL.HR_CAL_EVENT_ID,NULL,6,5),4)) LEVEL_IND
499     FROM CAC_SR_SCHDL_OBJECTS CSSO,
500          CAC_SR_SCHEDULES_B CSSB,
501          CAC_SR_SCHDL_EXCEPTIONS CSSE,
502          CAC_SR_EXCEPTIONS_VL CSEVL,
503          CAC_SR_PERIOD_CATS_VL CSPVL
504     WHERE CSSO.OBJECT_TYPE = b_object_type
505     AND CSSO.OBJECT_ID = b_object_id
506     AND CSSO.START_DATE_ACTIVE <= b_end_dt
507     AND CSSO.END_DATE_ACTIVE >= b_start_dt
508     AND CSSO.SCHEDULE_ID = CSSB.SCHEDULE_ID
509     AND CSSB.DELETED_DATE IS NULL
510     AND (CSSB.SCHEDULE_CATEGORY = b_schdl_cat
511          OR CSSB.SCHEDULE_ID IN (SELECT SCHEDULE_ID
512                                  FROM CAC_SR_PUBLISH_SCHEDULES
513                                  WHERE OBJECT_TYPE = b_object_type
514                                  AND OBJECT_ID = b_object_id
515                                  AND b_schdl_cat IS NULL
516                                 ))
517     AND ( ((CSSE.SCHEDULE_ID = CSSB.SCHEDULE_ID) AND (CSSE.SCHEDULE_OBJECT_ID IS NULL OR CSSE.SCHEDULE_OBJECT_ID = CSSO.SCHEDULE_OBJECT_ID))
518         OR CSSE.SCHEDULE_OBJECT_ID = CSSO.SCHEDULE_OBJECT_ID)
519     AND CSEVL.EXCEPTION_ID = CSSE.EXCEPTION_ID
520     AND CSPVL.PERIOD_CATEGORY_ID = CSEVL.PERIOD_CATEGORY_ID
521     ORDER BY LEVEL_IND,CSEVL.START_DATE_TIME;
522 
523   l_index          NUMBER;
524   l_excp_start_dt  DATE;
525   l_excp_end_dt    DATE;
526   l_excp_fb        VARCHAR2(30);
527   l_schdl_id       NUMBER;
528   l_start_dt       DATE;
529   l_end_dt         DATE;
530   l_period_id      NUMBER;
531   l_has_details    VARCHAR2(1);
532   l_duration_num   NUMBER;
533   l_duration_uom   VARCHAR2(30);
534   l_fb             VARCHAR2(30);
535   l_duration_ms    NUMBER;
536   l_rec_processed  BOOLEAN;
537   l_shift_bands    CAC_AVLBLTY_TIME_BAND_VARRAY;
538   l_super_recs     CAC_AVLBLTY_TIME_VARRAY;
539   l_excp_recs      CAC_AVLBLTY_TIME_VARRAY;
540   l_super_index    NUMBER;
541   l_period_name    VARCHAR2(2000);
542   l_category_id    NUMBER;
543   l_category_name  VARCHAR2(2000);
544   l_color          VARCHAR2(30);
545   l_summary_index  NUMBER;
546   l_pre_schedule   BOOLEAN;
547   l_temp_end_dt    DATE;
548   l_temp_dt        DATE;
549   l_excp_idx       NUMBER;
550   l_hr_cal_events  CAC_HR_CAL_EVENTS_PVT.HR_CAL_EVENT_TBL_TYPE;
551   l_idx            NUMBER;
552   l_excp_duration  NUMBER;
553   l_temp_excp_rec  CAC_AVLBLTY_TIME;
554   l_temp_temp_excp_rec  CAC_AVLBLTY_TIME;
555   k NUMBER;
556 
557 BEGIN
558 
559   x_Schedule := CAC_AVLBLTY_TIME_VARRAY();
560   x_Schedule_Summary := CAC_AVLBLTY_SUMMARY_VARRAY();
561   l_excp_recs := CAC_AVLBLTY_TIME_VARRAY();
562 
563   IF (NVL(p_Include_Exception,'T') = 'T')
564   THEN
565     l_excp_idx := 0;
566     FOR ref_excp IN C_EXCEPTION(p_Schdl_Cat,p_Object_Type,p_Object_ID,p_Start_Date_Time,p_End_Date_Time,p_Busy_Tentative)
567     LOOP
568       l_hr_cal_events.DELETE;
569       IF (ref_excp.HR_CAL_EVENT_TYPE IS NOT NULL)
570       THEN
571         CAC_HR_CAL_EVENTS_PVT.GET_HR_CAL_EVENTS
572         (
573           p_Object_Type     => p_Object_Type
574         , p_Object_ID       => p_Object_ID
575         , p_Start_Date      => p_Start_Date_Time
576         , p_End_Date        => p_End_Date_Time
577         , p_Event_Type      => ref_excp.HR_CAL_EVENT_TYPE
578         , p_Event_Id        => NULL
579         , x_hr_cal_events   => l_hr_cal_events
580         );
581       ELSIF (ref_excp.HR_CAL_EVENT_ID IS NOT NULL)
582       THEN
583         CAC_HR_CAL_EVENTS_PVT.GET_HR_CAL_EVENTS
584         (
585           p_Object_Type     => p_Object_Type
586         , p_Object_ID       => p_Object_ID
587         , p_Start_Date      => p_Start_Date_Time
588         , p_End_Date        => p_End_Date_Time
589         , p_Event_Type      => NULL
590         , p_Event_Id        => ref_excp.HR_CAL_EVENT_ID
591         , x_hr_cal_events   => l_hr_cal_events
592         );
593       ELSE
594         l_hr_cal_events(1).START_DATE_TIME := ref_excp.START_DATE_TIME;
595         l_hr_cal_events(1).END_DATE_TIME := ref_excp.END_DATE_TIME;
596       END IF;
597       IF (l_hr_cal_events.COUNT > 0)
598       THEN
599         FOR i IN l_hr_cal_events.FIRST..l_hr_cal_events.LAST
600         LOOP
601           IF ((l_hr_cal_events(i).END_DATE_TIME > l_hr_cal_events(i).START_DATE_TIME)
602             AND NOT (((l_hr_cal_events(i).START_DATE_TIME < p_Start_Date_Time) AND
603               (l_hr_cal_events(i).END_DATE_TIME < p_Start_Date_Time)) OR
604               ((l_hr_cal_events(i).START_DATE_TIME > p_End_Date_Time) AND
605               (l_hr_cal_events(i).END_DATE_TIME > p_End_Date_Time))))
606           THEN
607             IF (l_excp_idx = 0)
608             THEN
609              l_excp_recs.EXTEND(1);
610               l_excp_idx := 1;
611               l_excp_recs(1) := CAC_AVLBLTY_TIME
612                                (
613                                  PERIOD_NAME          => ref_excp.EXCEPTION_NAME,
614                                  START_DATE_TIME      => l_hr_cal_events(i).START_DATE_TIME,
615                                  END_DATE_TIME        => l_hr_cal_events(i).END_DATE_TIME,
616                                  DURATION_MS          => (l_hr_cal_events(i).END_DATE_TIME-l_hr_cal_events(i).START_DATE_TIME)*24*3600*1000,
617                                  PERIOD_CATEGORY_ID   => ref_excp.PERIOD_CATEGORY_ID,
618                                  PERIOD_CATEGORY_NAME => ref_excp.PERIOD_CATEGORY_NAME,
619                                  FREE_BUSY_TYPE       => ref_excp.FREE_BUSY_TYPE,
620                                  DISPLAY_COLOR        => ref_excp.DISPLAY_COLOR,
621                                  SUPER_OBJECT_INDEX   => NULL,
622                                  SHIFT_BANDS          => NULL,
623                                  NEXT_OBJECT_INDEX    => NULL
624                                );
625             ELSE
626               l_idx := l_excp_idx;
627               FOR j IN 1..l_idx
628               LOOP
629                 IF (l_hr_cal_events(i).START_DATE_TIME <= l_excp_recs(j).START_DATE_TIME)
630                 THEN
631                   -- move all the items
632                   l_temp_excp_rec := l_excp_recs(j);
633                   l_excp_recs(j) := CAC_AVLBLTY_TIME
634                                    (
635                                      PERIOD_NAME          => ref_excp.EXCEPTION_NAME,
636                                      START_DATE_TIME      => l_hr_cal_events(i).START_DATE_TIME,
637                                      END_DATE_TIME        => l_hr_cal_events(i).END_DATE_TIME,
638                                      DURATION_MS          => (l_hr_cal_events(i).END_DATE_TIME-l_hr_cal_events(i).START_DATE_TIME)*24*3600*1000,
639                                      PERIOD_CATEGORY_ID   => ref_excp.PERIOD_CATEGORY_ID,
640                                      PERIOD_CATEGORY_NAME => ref_excp.PERIOD_CATEGORY_NAME,
641                                      FREE_BUSY_TYPE       => ref_excp.FREE_BUSY_TYPE,
642                                      DISPLAY_COLOR        => ref_excp.DISPLAY_COLOR,
643                                      SUPER_OBJECT_INDEX   => NULL,
644                                      SHIFT_BANDS          => NULL,
645                                      NEXT_OBJECT_INDEX    => NULL
646                                    );
647                   k := j+1;
648                   WHILE k <= l_idx
649                   LOOP
650                     IF (l_excp_recs(k).START_DATE_TIME >= l_hr_cal_events(i).END_DATE_TIME)
651                     THEN
652                       l_temp_temp_excp_rec := l_excp_recs(k);
653                       l_excp_recs(k) := l_temp_excp_rec;
654                       l_temp_excp_rec := l_temp_temp_excp_rec;
655                     ELSE
656                       l_temp_excp_rec := NULL;
657                       IF (l_excp_recs(k).END_DATE_TIME <= l_hr_cal_events(i).END_DATE_TIME)
658                       THEN
659                         -- k should be deleted
660                         FOR l IN k+1..l_idx
661                         LOOP
662                           l_excp_recs(k) := l_excp_recs(l);
663                         END LOOP;
664                         l_excp_recs.trim(1);
665                         l_idx := l_idx - 1;
666                         l_excp_idx := l_excp_idx - 1;
667                         k := k - 1;
668                       ELSE
669                         -- partial overwritten
670                         l_excp_recs(k).START_DATE_TIME := l_hr_cal_events(i).END_DATE_TIME;
671                         EXIT;
672                       END IF;
673                     END IF;
674                     k := k + 1;
675                   END LOOP;
676                   IF (l_temp_excp_rec IS NOT NULL)
677                   THEN
678                     l_excp_recs.EXTEND(1);
679                     l_excp_idx := l_excp_idx + 1;
680                     l_excp_recs(l_excp_idx) := l_temp_excp_rec;
681                   END IF;
682                   l_hr_cal_events(i).START_DATE_TIME := l_hr_cal_events(i).END_DATE_TIME;
683                   EXIT;
684                 ELSE
685                   IF (l_hr_cal_events(i).START_DATE_TIME < l_excp_recs(j).END_DATE_TIME)
686                   THEN
687                     -- overwrite
688                     l_excp_recs(j).END_DATE_TIME := l_hr_cal_events(i).START_DATE_TIME;
689                   END IF;
690                 END IF;
691               END LOOP;
692               IF (l_hr_cal_events(i).END_DATE_TIME > l_hr_cal_events(i).START_DATE_TIME)
693               THEN
694                 l_excp_recs.EXTEND(1);
695                 l_excp_idx := l_excp_idx + 1;
696                 l_excp_recs(l_excp_idx) := CAC_AVLBLTY_TIME
697                                            (
698                                              PERIOD_NAME          => ref_excp.EXCEPTION_NAME,
699                                              START_DATE_TIME      => l_hr_cal_events(i).START_DATE_TIME,
700                                              END_DATE_TIME        => l_hr_cal_events(i).END_DATE_TIME,
701                                              DURATION_MS          => (l_hr_cal_events(i).END_DATE_TIME-l_hr_cal_events(i).START_DATE_TIME)*24*3600*1000,
702                                              PERIOD_CATEGORY_ID   => ref_excp.PERIOD_CATEGORY_ID,
703                                              PERIOD_CATEGORY_NAME => ref_excp.PERIOD_CATEGORY_NAME,
704                                              FREE_BUSY_TYPE       => ref_excp.FREE_BUSY_TYPE,
705                                              DISPLAY_COLOR        => ref_excp.DISPLAY_COLOR,
706                                              SUPER_OBJECT_INDEX   => NULL,
707                                              SHIFT_BANDS          => NULL,
708                                              NEXT_OBJECT_INDEX    => NULL
709                                            );
710               END IF;
711             END IF;
712           END IF;
713         END LOOP;
714       END IF;
715     END LOOP;
716   END IF;
717 
718   l_excp_idx := l_excp_recs.first;
719 
720   l_pre_schedule := FALSE;
721   OPEN C_SCHEDULE(p_Schdl_Cat,p_Object_Type,p_Object_ID,p_Start_Date_Time,p_End_Date_Time,p_Busy_Tentative);
722   FETCH C_SCHEDULE
723     INTO l_schdl_id, l_start_dt, l_end_dt, l_period_id, l_has_details, l_duration_num, l_duration_uom, l_period_name, l_category_id, l_category_name, l_fb, l_color;
724 
725   IF C_SCHEDULE%NOTFOUND
726   THEN
727     -- no schedule found, so assume free
728     l_schdl_id     := NULL;
729     l_start_dt     := p_Start_Date_Time;
730     l_end_dt       := p_End_Date_Time;
731     l_fb           := NULL;
732     l_period_id    := NULL;
733     l_has_details  := NULL;
734     l_duration_num := NULL;
735     l_duration_uom := NULL;
736     l_period_name  := NULL;
737     l_category_id  := NULL;
738     l_category_name:= NULL;
739     l_color        := NULL;
740   ELSIF (l_start_dt > p_Start_Date_Time)
741   THEN
742     l_pre_schedule := TRUE;
743     l_temp_end_dt  := l_end_dt;
744     l_end_dt       := l_start_dt;
745     l_start_dt     := p_Start_Date_Time;
746   ELSIF (l_start_dt < p_Start_Date_Time)
747   THEN
748     l_start_dt := p_Start_Date_Time;
749   END IF;
750 
751   -- loop through the schedule data
752   WHILE (l_start_dt < p_End_Date_Time)
753   LOOP
754     -- Reset the records start and end within the query start and end
755     IF (l_end_dt > p_End_Date_Time)
756     THEN
757       l_end_dt := p_End_Date_Time;
758     END IF;
759 
760     -- Fetch shift bands if needed
761     IF (p_return_type IN ('B','D'))
762     THEN
763       IF ((l_has_details = 'Y') AND (NOT l_pre_schedule))
764       THEN
765         l_shift_bands := GET_SHIFT_BANDS(l_period_id);
766       ELSE
767         l_shift_bands := NULL;
768       END IF;
769     END IF;
770 
771     l_rec_processed := FALSE;
772     -- loop through the exceptions which lie within the current record
773     -- note that if no exception is fetched then l_excp_start_dt will be NULL
774     WHILE ((l_excp_idx IS NOT NULL) AND (l_excp_recs(l_excp_idx).START_DATE_TIME < l_end_dt))
775     LOOP
776       IF (l_excp_recs(l_excp_idx).END_DATE_TIME <= l_start_dt)
777       THEN
778         -- this exception is before current record so fetch the next one
779         -- Note that here we're not checking for p_Include_Exception as
780         -- this part will not be executed if the flag is set to false
781         -- or there are no exceptions
782         l_excp_idx := l_excp_recs.NEXT(l_excp_idx);
783       ELSE
784         -- this exception ends after the record start
785         -- now check how to split the record
786         IF (l_excp_recs(l_excp_idx).START_DATE_TIME > l_start_dt)
787         THEN
788           -- exception starts after the schedule record start
789           -- so create a schedule record for the first part
790           IF (p_return_type IN ('B','D'))
791           THEN
792             CREATE_AVLBLTY_TIME
793             (
794               l_pre_schedule,
795               l_period_name,
796               l_start_dt,
797               l_excp_recs(l_excp_idx).START_DATE_TIME,
798               (l_excp_recs(l_excp_idx).START_DATE_TIME - l_start_dt)*24*3600*1000,
799               l_category_id,
800               l_category_name,
801               l_fb,
802               l_color,
803               true,
804               NULL,
805               x_Schedule,
806               l_index
807             );
808           END IF;
809           IF (p_return_type IN ('B','S'))
810           THEN
811             CREATE_AVLBLTY_SUMMARY
812             (
813               l_pre_schedule,
814               l_start_dt,
815               l_excp_recs(l_excp_idx).START_DATE_TIME,
816               l_category_id,
817               l_category_name,
818               l_fb,
819               l_color,
820               x_Schedule_Summary,
821               l_summary_index
822             );
823           END IF;
824           -- reset the schedule record start to the exception start
825           l_start_dt := l_excp_recs(l_excp_idx).START_DATE_TIME;
826         END IF;
827         -- now check where the exception ends and split the remaining record
828         IF (l_excp_recs(l_excp_idx).END_DATE_TIME = l_end_dt)
829         THEN
830           -- exception ends at the same time, so the whole record will be overwritten
831           IF (p_return_type IN ('B','D'))
832           THEN
833             CREATE_AVLBLTY_TIME
834             (
835               FALSE,
836               l_excp_recs(l_excp_idx).PERIOD_NAME,
837               l_start_dt,
838               l_end_dt,
839               (l_end_dt - l_start_dt)*24*3600*1000,
840               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_ID,
841               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_NAME,
842               l_excp_recs(l_excp_idx).FREE_BUSY_TYPE,
843               l_excp_recs(l_excp_idx).DISPLAY_COLOR,
844               true,
845               NULL,
846               x_Schedule,
847               l_index
848             );
849           END IF;
850           IF (p_return_type IN ('B','S'))
851           THEN
852             CREATE_AVLBLTY_SUMMARY
853             (
854               FALSE,
855               l_start_dt,
856               l_end_dt,
857               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_ID,
858               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_NAME,
859               l_excp_recs(l_excp_idx).FREE_BUSY_TYPE,
860               l_excp_recs(l_excp_idx).DISPLAY_COLOR,
861               x_Schedule_Summary,
862               l_summary_index
863             );
864           END IF;
865           -- fetch the next exception and quit exception loop
866           l_excp_idx := l_excp_recs.NEXT(l_excp_idx);
867           -- quit exception loop and go to the next schedule record
868           l_rec_processed := TRUE;
869           EXIT;
870         ELSIF (l_excp_recs(l_excp_idx).END_DATE_TIME > l_end_dt)
871         THEN
872           -- exception ends after the record, so the whole record will be overwritten
873           IF (p_return_type IN ('B','D'))
874           THEN
875             CREATE_AVLBLTY_TIME
876             (
877               FALSE,
878               l_excp_recs(l_excp_idx).PERIOD_NAME,
879               l_start_dt,
880               l_end_dt,
881               (l_end_dt - l_start_dt)*24*3600*1000,
882               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_ID,
883               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_NAME,
884               l_excp_recs(l_excp_idx).FREE_BUSY_TYPE,
885               l_excp_recs(l_excp_idx).DISPLAY_COLOR,
886               true,
887               NULL,
888               x_Schedule,
889               l_index
890             );
891           END IF;
892           IF (p_return_type IN ('B','S'))
893           THEN
894             CREATE_AVLBLTY_SUMMARY
895             (
896               FALSE,
897               l_start_dt,
898               l_end_dt,
899               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_ID,
900               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_NAME,
901               l_excp_recs(l_excp_idx).FREE_BUSY_TYPE,
902               l_excp_recs(l_excp_idx).DISPLAY_COLOR,
903               x_Schedule_Summary,
904               l_summary_index
905             );
906           END IF;
907           -- reset the exception to the part where it's not used
908           l_excp_recs(l_excp_idx).START_DATE_TIME := l_end_dt;
909           -- quit exception loop and go to the next schedule record
910           l_rec_processed := TRUE;
911           EXIT;
912         ELSE
913           -- exception ends before the end of the record, so split into two
914           IF (p_return_type IN ('B','D'))
915           THEN
916             CREATE_AVLBLTY_TIME
917             (
918               FALSE,
919               l_excp_recs(l_excp_idx).PERIOD_NAME,
920               l_start_dt,
921               l_excp_recs(l_excp_idx).END_DATE_TIME,
922               (l_excp_recs(l_excp_idx).END_DATE_TIME - l_start_dt)*24*3600*1000,
923               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_ID,
924               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_NAME,
925               l_excp_recs(l_excp_idx).FREE_BUSY_TYPE,
926               l_excp_recs(l_excp_idx).DISPLAY_COLOR,
927               true,
928               NULL,
929               x_Schedule,
930               l_index
931             );
932           END IF;
933           IF (p_return_type IN ('B','S'))
934           THEN
935             CREATE_AVLBLTY_SUMMARY
936             (
937               FALSE,
938               l_start_dt,
939               l_excp_recs(l_excp_idx).END_DATE_TIME,
940               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_ID,
941               l_excp_recs(l_excp_idx).PERIOD_CATEGORY_NAME,
942               l_excp_recs(l_excp_idx).FREE_BUSY_TYPE,
943               l_excp_recs(l_excp_idx).DISPLAY_COLOR,
944               x_Schedule_Summary,
945               l_summary_index
946             );
947           END IF;
948           -- this is the second part. there could possibly be more exceptions
949           -- in this part, so set the start of the record to the end of
950           -- exception and fetch the next exception
951           l_start_dt := l_excp_recs(l_excp_idx).END_DATE_TIME;
952           l_excp_idx := l_excp_recs.NEXT(l_excp_idx);
953         END IF;
954       END IF;
955     END LOOP;
956     -- now create an item if the record was not completely processed
957     IF NOT l_rec_processed
958     THEN
959       l_duration_ms := CONVERT_TO_MILLIS(l_duration_num,l_duration_uom);
960       -- use the minimum of the durations
961       IF (((l_end_dt - l_start_dt)*24*3600*1000) > NVL(l_duration_ms,0))
962       THEN
963         l_duration_ms := (l_end_dt - l_start_dt)*24*3600*1000;
964       END IF;
965       IF (p_return_type IN ('B','D'))
966       THEN
967         CREATE_AVLBLTY_TIME
968         (
969           l_pre_schedule,
970           l_period_name,
971           l_start_dt,
972           l_end_dt,
973           l_duration_ms,
974           l_category_id,
975           l_category_name,
976           l_fb,
977           l_color,
978           true,
979           NULL,
980           x_Schedule,
981           l_index
982         );
983       END IF;
984       IF (p_return_type IN ('B','S'))
985       THEN
986         CREATE_AVLBLTY_SUMMARY
987         (
988           l_pre_schedule,
989           l_start_dt,
990           l_end_dt,
991           l_category_id,
992           l_category_name,
993           l_fb,
994           l_color,
995           x_Schedule_Summary,
996           l_summary_index
997         );
998       END IF;
999     END IF;
1000     IF (l_pre_schedule)
1001     THEN
1002       l_pre_schedule := FALSE;
1003       l_start_dt     := l_end_dt;
1004       l_end_dt       := l_temp_end_dt;
1005       -- if there was an schedule then fetch the next record or else just quit
1006     ELSIF (l_schdl_id IS NOT NULL)
1007     THEN
1008       l_temp_end_dt  := l_end_dt;
1009       FETCH C_SCHEDULE
1010         INTO l_schdl_id, l_start_dt, l_end_dt, l_period_id, l_has_details, l_duration_num, l_duration_uom, l_period_name, l_category_id, l_category_name, l_fb, l_color;
1011       IF C_SCHEDULE%NOTFOUND
1012       THEN
1013         l_schdl_id     := NULL;
1014         l_start_dt     := l_end_dt;
1015         l_end_dt       := p_End_Date_Time;
1016         l_fb           := NULL;
1017         l_period_id    := NULL;
1018         l_has_details  := NULL;
1019         l_duration_num := NULL;
1020         l_duration_uom := NULL;
1021         l_period_name  := NULL;
1022         l_category_id  := NULL;
1023         l_category_name:= NULL;
1024         l_color        := NULL;
1025       ELSE
1026         IF (l_start_dt > l_temp_end_dt)
1027         THEN
1028           l_temp_dt      := l_start_dt;
1029           l_start_dt     := l_temp_end_dt;
1030           l_temp_end_dt  := l_end_dt;
1031           l_end_dt       := l_temp_dt;
1032           l_pre_schedule := TRUE;
1033         END IF;
1034       END IF;
1035     ELSE
1036       EXIT;
1037     END IF;
1038   END LOOP;
1039 
1040   IF C_SCHEDULE%ISOPEN
1041   THEN
1042     CLOSE C_SCHEDULE;
1043   END IF;
1044 
1045   IF C_EXCEPTION%ISOPEN
1046   THEN
1047     CLOSE C_EXCEPTION;
1048   END IF;
1049 
1050 END GET_SCHEDULE_DATA;
1051 
1052 
1053 /**
1054 PROCEDURE getBookingData
1055 /*******************************************************************************
1056 **
1057 ** getBookingData
1058 **
1059 **   returns all Bookings and appointments in task tables for the given:
1060 **   - Object Instance
1061 **   - Period
1062 **
1063 *******************************************************************************
1064 ( p_api_version         IN     NUMBER                -- API version you coded against
1065 , p_init_msg_list       IN     VARCHAR2 DEFAULT 'F'  -- Create a new error stack?
1066 , p_ObjectType          IN     VARCHAR2              -- JTF OBJECTS type of the Object being queried
1067 , p_ObjectID            IN     NUMBER                -- JTF OBJECTS select ID of the Object Instance being queried
1068 , p_PeriodStartDateTime IN     DATE                  -- start date and time of period of interest
1069 , p_PeriodEndDateTime   IN     DATE                  -- end date and time of period of interest
1070 , p_OpagueBkngCat       IN     JTF_NUMBER_TABLE      -- Booking Categories (i.e. task types) that should be considered OPAGUE
1071 , p_BookingStatus       IN     VARCHAR2              -- Are we looking for Firm or Soft bookings
1072 , p_BusyTentative       IN     VARCHAR2              -- How to treat FREEBUSYTIME objects with FREEBUSYTYPE = BUSY TENTATIVE?
1073                                                      -- FREE: BUSY TENTATIVE means FREE
1074                                                      -- BUSY: BUSY TENTATIVE means BUSY
1075                                                      -- NULL: leave the interpretation to caller
1076 , x_BookingData         IN OUT CAC_SR_FREEBUSYTIME_VARRAY
1077                                                      -- returns the existings bookings for the Object Instance
1078 , x_return_status          OUT NOCOPY VARCHAR2              -- 'S': API completed without errors
1079                                                      -- 'E': API completed with recoverable errors; explanation on errorstack (Warnings)
1080                                                      -- 'U': API completed with UN recoverable errors: error message on error stack
1081 , x_msg_count              OUT NOCOPY NUMBER                -- Number of messages on the errorstack, if 1 then x_msg_data contains the message
1082 , x_msg_data               OUT NOCOPY VARCHAR2              -- contains message if x_msg_count = 1
1083 )
1084 IS
1085  TYPE c_Bookings_type IS REF CURSOR;
1086 
1087   c_Bookings  c_Bookings_type;
1088 
1089   l_FreeBusyTime   CAC_SR_FREEBUSYTIME;
1090 
1091   i NUMBER := 0;
1092 
1093   --
1094   -- This is the base query for picking up all opague records from the task table
1095   --
1096   l_query  VARCHAR2(2000) :=
1097 
1098   'SELECT GREATEST( CAC_AVLBLTY_PVT.AdjustForTimezone( jtb.timezone_id '          ||
1099                                                     ', :b_ToTimeZone '            ||
1100                                                     ', jtb.calendar_start_date '  ||
1101                                                     ') '                          ||
1102                  ', :b_PeriodStartDateTime '                                      ||
1103                  ') StartDateTime '                                               ||
1104   ',         LEAST( CAC_AVLBLTY_PVT.AdjustForTimezone( jtb.timezone_id '          ||
1105                                                     ', :b_ToTimeZone '            ||
1106                                                     ', jtb.calendar_end_date '    ||
1107                                                     ') '                          ||
1108                  ', :b_PeriodEndDateTime '                                        ||
1109                  ') EndDateTime '                                                 ||
1110   ',      DECODE( jta.free_busy_type, ''FREE'',''FREE'' '                         ||
1111                                    ', ''BUSY'',''BUSY'' '                         ||
1112                                    ', ''TENTATIVE'',NVL(:b_BusyTentative,''TENTATIVE'') '       ||
1113                                    ')                               FBType '      ||
1114   ',      jtb.task_type_id                                          CategoryID '  ||
1115   ',      jtb.entity                                                CategoryType '||
1116   'FROM jtf_task_all_assignments  jta '                                           ||
1117   ',    jtf_tasks_b               jtb '                                           ||
1118   ',    ( SELECT jts.task_status_id '                                             ||
1119   '       FROM   jtf_task_statuses_b jts '                                        ||
1120   '       WHERE  jts.assignment_status_flag    = ''Y'' '                          ||
1121   '       AND    NVL(jts.closed_flag,''N'')    = ''N'' '                          ||
1122   '       AND    NVL(jts.completed_flag,''N'') = ''N'' '                          ||
1123   '       AND    NVL(jts.rejected_flag,''N'')  = ''N'' '                          ||
1124   '       AND    NVL(jts.on_hold_flag,''N'')   = ''N'' '                          ||
1125   '       AND    NVL(jts.cancelled_flag,''N'') = ''N'' '                          ||
1126   '     ) jto '                                                                   ||
1127   'WHERE jta.resource_type_code   = :b_ObjectType '                               ||
1128   'AND   jta.resource_id          = :b_ObjectID '                                 ||
1129   'AND   jta.assignment_status_id = jto.task_status_id '                          ||
1130   'AND   jta.task_id              = jtb.task_id '                                 ||
1131   'AND   jtb.open_flag            = ''Y'' '                                       ||
1132   'AND   jtb.calendar_end_date   >= :b_StartDate '                                ||
1133   'AND   jtb.calendar_start_date <= :b_EndDate '                                  ||
1134   'AND   jtb.entity IN (''BOOKING'',''TASK'',''APPOINTMENT'') '; -- Add appointment here once they go to servertimezone
1135 
1136   l_opague VARCHAR2(2000);
1137   l_status VARCHAR2(200);
1138   l_order  VARCHAR2(200) := 'ORDER BY 1';
1139 
1140   l_ServerTimeZone NUMBER := TO_NUMBER(FND_PROFILE.Value('SERVER_TIMEZONE_ID'));
1141 
1142 BEGIN
1143 
1144   IF (x_BookingData IS NULL)
1145   THEN
1146     x_BookingData := CAC_SR_FREEBUSYTIME_VARRAY();
1147   END IF;
1148 
1149   --
1150   -- the list of OPAGUE tasks may have been restricted to the booking categories
1151   -- (task types) in p_OpagueXcptnPeriodCat
1152   --
1153   IF ((p_OpagueBkngCat IS NOT NULL) AND (p_OpagueBkngCat.COUNT > 0))
1154   THEN
1155     l_opague := 'AND jtb.task_type_id IN (';
1156     FOR i IN 1..p_OpagueBkngCat.LAST
1157     LOOP
1158       IF (i < p_OpagueBkngCat.LAST)
1159       THEN
1160         l_opague := l_opague || p_OpagueBkngCat(i)||',';
1161       ELSE
1162         l_opague := l_opague || p_OpagueBkngCat(i)||') ';
1163       END IF;
1164     END LOOP;
1165   END IF;
1166 
1167   --
1168   -- We'll need to change the query to look for either Firm or Soft bookings:
1169   -- - free_busy_type = 'BUSY' means the booking is Firm
1170   -- - free_busy_type = 'TENTATIVE' means the booking is Soft
1171   --
1172   IF (p_BookingStatus IS NOT NULL)
1173   THEN
1174     l_status := 'AND   jta.free_busy_type = '''||p_BookingStatus||''' ';
1175 
1176   END IF;
1177 
1178   --
1179   -- Build the query
1180   --
1181   l_query := l_query || l_opague || l_Status || l_order;
1182 
1183   --
1184   -- Initialize the  CAC_SR_FREEBUSYTIME object
1185   --
1186   l_FreeBusyTime := CAC_SR_FREEBUSYTIME(NULL,NULL,NULL,NULL,NULL);
1187 
1188   OPEN c_Bookings FOR l_query USING l_ServerTimeZone
1189                               ,     (p_PeriodStartDateTime - 1)  -- for timezone adjustments
1190                               ,     l_ServerTimeZone
1191                               ,     (p_PeriodEndDateTime + 1)  -- for timezone adjustments
1192                               ,     p_BusyTentative
1193                               ,     p_ObjectType
1194                               ,     p_ObjectID
1195                               ,     (p_PeriodStartDateTime - 1)  -- for timezone adjustments
1196                               ,     (p_PeriodEndDateTime + 1);  -- for timezone adjustments
1197 
1198   <<BOOKINGS>>
1199   LOOP -- Bookings
1200     FETCH c_Bookings INTO l_FreeBusyTime.StartDatetime
1201                      ,    l_FreeBusyTime.EndDateTime
1202                      ,    l_FreeBusyTime.FBType
1203                      ,    l_FreeBusyTime.CategoryID
1204                      ,    l_FreeBusyTime.CategoryType;
1205 
1206     IF (c_Bookings%FOUND)
1207     THEN
1208       --
1209       -- If after timezone adjustment it is still within the query period use it
1210       --
1211       IF  (   ( l_FreeBusyTime.StartDatetime <= p_PeriodEndDateTime )
1212           AND ( l_FreeBusyTime.EndDateTime   >  p_PeriodStartDateTime)
1213           )
1214       THEN
1215         --
1216         -- stick it in FreeBusyList
1217         --
1218         Extend( p_varray  => x_BookingData
1219               , p_element => l_FreeBusyTime
1220               , p_index   => i
1221               );
1222       END IF;
1223 
1224     ELSE -- (c_Bookings%NOTFOUND)
1225       CLOSE c_Bookings;
1226       EXIT BOOKINGS; -- exit Bookings loop
1227 
1228     END IF;
1229   END LOOP;-- end Bookings loop
1230 
1231   --
1232   -- Remove any null element that extend may have added
1233   --
1234   Trim( p_varray  => x_BookingData
1235       , p_index   => i
1236       );
1237 
1238 END getBookingData;
1239 **/
1240 
1241 
1242 PROCEDURE INSERT_SCHEDULE_DETAILS
1243 /*******************************************************************************
1244 **
1245 ** INSERT_SCHEDULE_DETAILS
1246 **
1247 ** popluates the schedule details table from the pl/sql table
1248 **
1249 *******************************************************************************/
1250 ( p_Schedule_Id          IN     NUMBER               -- id of the schedule
1251 , p_Schedule_Object_Id   IN     NUMBER
1252 , p_Schedule_Details     IN     SCHDL_DETAILS_TBL_TYPE
1253 ) IS
1254 
1255   l_created_by         NUMBER;
1256   l_creation_date      DATE;
1257   l_last_updated_by    NUMBER;
1258   l_last_update_date   DATE;
1259   l_last_update_login  NUMBER;
1260 
1261 BEGIN
1262 
1263   l_created_by         := FND_GLOBAL.USER_ID;
1264   l_creation_date      := SYSDATE;
1265   l_last_updated_by    := FND_GLOBAL.USER_ID;
1266   l_last_update_date   := SYSDATE;
1267   l_last_update_login  := FND_GLOBAL.LOGIN_ID;
1268 
1269   FOR i IN p_Schedule_Details.FIRST..p_Schedule_Details.LAST
1270   LOOP
1271     INSERT INTO CAC_SR_SCHDL_DETAILS
1272     (
1273       SCHEDULE_DETAIL_ID,
1274       SCHEDULE_ID,
1275       SCHEDULE_OBJECT_ID,
1276       PERIOD_ID,
1277       START_DATE_TIME,
1278       END_DATE_TIME,
1279       CREATED_BY,
1280       CREATION_DATE,
1281       LAST_UPDATED_BY,
1282       LAST_UPDATE_DATE,
1283       LAST_UPDATE_LOGIN
1284     )
1285     VALUES
1286     (
1287       CAC_SR_SCHDL_DETAILS_S.NEXTVAL,
1288       p_schedule_id,
1289       p_schedule_object_id,
1290       p_Schedule_Details(i).period_id,
1291       p_Schedule_Details(i).start_date_time,
1292       p_Schedule_Details(i).end_date_time,
1293       l_created_by,
1294       l_creation_date,
1295       l_last_updated_by,
1296       l_last_update_date,
1297       l_last_update_login
1298     );
1299   END LOOP;
1300 
1301 END INSERT_SCHEDULE_DETAILS;
1302 
1303 
1304 PROCEDURE CREATE_PERIOD_DATA_DUR
1305 /*******************************************************************************
1306 **
1307 ** CREATE_PERIOD_DATA_DUR
1308 **
1309 ** popluates the period data pl/sql table by expanding the template
1310 ** should be called for duration based template
1311 **
1312 *******************************************************************************/
1313 ( p_tmpl_id         IN  NUMBER
1314 , x_period_data     OUT NOCOPY PERIOD_TBL_TYPE
1315 ) IS
1316 
1317   CURSOR C_TMPL_DETAILS
1318   (
1319     b_tmpl_id    NUMBER
1320   ) IS
1321   SELECT DTLS.TEMPLATE_DETAIL_ID,
1322          DTLS.TEMPLATE_DETAIL_SEQ,
1323          DTLS.TEMPLATE_ID,
1324          DTLS.CHILD_PERIOD_ID,
1325          DTLS.CHILD_TEMPLATE_ID,
1326          CSPB.DURATION,
1327          CSPB.DURATION_UOM
1328   FROM CAC_SR_PERIODS_B CSPB,
1329         (SELECT CSTD.TEMPLATE_DETAIL_ID,
1330                CSTD.TEMPLATE_DETAIL_SEQ,
1331                CSTD.TEMPLATE_ID,
1332                CSTD.CHILD_PERIOD_ID,
1333                CSTD.CHILD_TEMPLATE_ID
1334         FROM CAC_SR_TMPL_DETAILS CSTD
1335         START WITH CSTD.TEMPLATE_ID = b_tmpl_id
1336         CONNECT BY PRIOR CSTD.CHILD_TEMPLATE_ID = CSTD.TEMPLATE_ID
1337         ORDER SIBLINGS BY TEMPLATE_DETAIL_SEQ) DTLS
1338   WHERE CSPB.PERIOD_ID(+) = DTLS.CHILD_PERIOD_ID
1339   ORDER BY TEMPLATE_DETAIL_SEQ;     --ADDED FOR BUG#7491187
1340 
1341 
1342   i         BINARY_INTEGER;
1343 
1344 BEGIN
1345 
1346   i := 0;
1347 
1348   FOR REF_TMPL_DTLS IN C_TMPL_DETAILS(p_tmpl_id)
1349   LOOP
1350     IF (REF_TMPL_DTLS.CHILD_PERIOD_ID IS NOT NULL)
1351     THEN
1352       -- this is a period, so add a new record
1353       i:= i+1;
1354       x_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1355       x_period_data(i).period_id          := REF_TMPL_DTLS.CHILD_PERIOD_ID;
1356       x_period_data(i).period_span_ms     := CONVERT_TO_MILLIS(REF_TMPL_DTLS.DURATION,REF_TMPL_DTLS.DURATION_UOM);
1357     ELSE
1358       -- this is a template, so add a dummy record
1359       i:= i+1;
1360       x_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1361       x_period_data(i).period_id          := NULL;
1362       x_period_data(i).period_span_ms     := 0;
1363     END IF;
1364   END LOOP;
1365 
1366 END CREATE_PERIOD_DATA_DUR;
1367 
1368 
1369 PROCEDURE CREATE_PERIOD_DATA_CAL
1370 /*******************************************************************************
1371 **
1372 ** CREATE_PERIOD_DATA_CAL
1373 **
1374 ** popluates the period data pl/sql table by expanding the template
1375 ** should be called for calendar based template
1376 **
1377 *******************************************************************************/
1378 ( p_tmpl_id         IN  NUMBER
1379 , p_tmpl_length     IN  NUMBER
1380 , x_period_data     OUT NOCOPY PERIOD_TBL_TYPE
1381 ) IS
1382 
1383   CURSOR C_TMPL_DETAILS
1384   (
1385     b_tmpl_id    NUMBER
1386   ) IS
1387   SELECT DTLS.TEMPLATE_DETAIL_ID,
1388          DTLS.TEMPLATE_DETAIL_SEQ,
1389          DTLS.TEMPLATE_ID,
1390          DTLS.CHILD_PERIOD_ID,
1391          DTLS.CHILD_TEMPLATE_ID,
1392          CSPB.WEEK_DAY_NUM,
1393          CSPB.START_TIME_MS,
1394          CSPB.DURATION,
1395          CSPB.DURATION_UOM,
1396          CSTB.TEMPLATE_LENGTH_DAYS
1397   FROM CAC_SR_TEMPLATES_B CSTB,
1398         CAC_SR_PERIODS_B CSPB,
1399         (SELECT CSTD.TEMPLATE_DETAIL_ID,
1400                CSTD.TEMPLATE_DETAIL_SEQ,
1401                CSTD.TEMPLATE_ID,
1402                CSTD.CHILD_PERIOD_ID,
1403                CSTD.CHILD_TEMPLATE_ID
1404         FROM CAC_SR_TMPL_DETAILS CSTD
1405         START WITH CSTD.TEMPLATE_ID = b_tmpl_id
1406         CONNECT BY PRIOR CSTD.CHILD_TEMPLATE_ID = CSTD.TEMPLATE_ID
1407         ORDER SIBLINGS BY TEMPLATE_DETAIL_SEQ) DTLS
1408   WHERE CSTB.TEMPLATE_ID(+) = DTLS.CHILD_TEMPLATE_ID
1409   AND CSPB.PERIOD_ID(+) = DTLS.CHILD_PERIOD_ID
1410   ORDER BY  TEMPLATE_DETAIL_SEQ;    --ADDED FOR BUG#7491187
1411 
1412   i                     BINARY_INTEGER;
1413   i_first               BINARY_INTEGER;
1414   i_last                BINARY_INTEGER;
1415   l_last_tmpl_id        NUMBER;
1416   l_last_tmpl_length_ms NUMBER;
1417   l_total_length_ms     NUMBER;
1418   l_duration_gap_ms     NUMBER;
1419 
1420 BEGIN
1421 
1422   i := 0;
1423   l_total_length_ms     := 0;
1424   -- do we need length based logic? it seems, it'll work without it
1425   l_last_tmpl_id        := p_tmpl_id;
1426   l_last_tmpl_length_ms := p_tmpl_length * 24 * 3600 * 1000;
1427 
1428   FOR REF_TMPL_DTLS IN C_TMPL_DETAILS(p_tmpl_id)
1429   LOOP
1430     IF (REF_TMPL_DTLS.CHILD_PERIOD_ID IS NOT NULL)
1431     THEN
1432       -- this is a period, so add a new record
1433       -- but before that check if there is a gap between the
1434       -- previous record and this one and fill it
1435       IF (i > 0)
1436       THEN
1437         -- calculate the gap
1438         IF (REF_TMPL_DTLS.WEEK_DAY_NUM >= x_period_data(i).day_num)
1439         THEN
1440           l_duration_gap_ms := (REF_TMPL_DTLS.WEEK_DAY_NUM - x_period_data(i).day_num) * 24 * 3600 * 1000
1441                                + REF_TMPL_DTLS.START_TIME_MS - x_period_data(i).day_start_ms
1442                                - x_period_data(i).period_span_ms;
1443         ELSE
1444           l_duration_gap_ms := (7 + REF_TMPL_DTLS.WEEK_DAY_NUM - x_period_data(i).day_num) * 24 * 3600 * 1000
1445                                + REF_TMPL_DTLS.START_TIME_MS - x_period_data(i).day_start_ms
1446                                - x_period_data(i).period_span_ms;
1447         END IF;
1448         IF (l_duration_gap_ms > 0)
1449         THEN
1450           -- create a new record for this gap
1451           i:= i+1;
1452           x_period_data(i).template_detail_id := NULL;
1453           x_period_data(i).period_id          := NULL;
1454           x_period_data(i).period_span_ms     := l_duration_gap_ms;
1455           x_period_data(i).day_start_ms       := NULL;
1456           x_period_data(i).day_num            := NULL;
1457           -- increment the total length
1458           l_total_length_ms := l_total_length_ms + x_period_data(i).period_span_ms;
1459         END IF;
1460       ELSE
1461         -- this is the first record
1462         -- so prefill the array assuming week starts on sunday
1463         l_duration_gap_ms := (REF_TMPL_DTLS.WEEK_DAY_NUM - 1)*24*3600*1000 + REF_TMPL_DTLS.START_TIME_MS;
1464         IF (l_duration_gap_ms > 0)
1465         THEN
1466           -- create a new record for this gap
1467           i:= i+1;
1468           x_period_data(i).template_detail_id := NULL;
1469           x_period_data(i).period_id          := NULL;
1470           x_period_data(i).period_span_ms     := l_duration_gap_ms;
1471           x_period_data(i).day_start_ms       := 0;
1472           x_period_data(i).day_num            := 1;
1473           -- increment the total length
1474           l_total_length_ms := l_total_length_ms + x_period_data(i).period_span_ms;
1475         END IF;
1476       END IF;
1477       -- create an actual period record
1478       i:= i+1;
1479       x_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1480       x_period_data(i).period_id          := REF_TMPL_DTLS.CHILD_PERIOD_ID;
1481       x_period_data(i).period_span_ms     := CONVERT_TO_MILLIS(REF_TMPL_DTLS.DURATION,REF_TMPL_DTLS.DURATION_UOM);
1482       x_period_data(i).day_start_ms       := REF_TMPL_DTLS.START_TIME_MS;
1483       x_period_data(i).day_num            := REF_TMPL_DTLS.WEEK_DAY_NUM;
1484       -- increment the total length
1485       l_total_length_ms := l_total_length_ms + x_period_data(i).period_span_ms;
1486     ELSE
1487       -- this is a template, so store the tmpl id and length for future records
1488       l_last_tmpl_id        := REF_TMPL_DTLS.CHILD_TEMPLATE_ID;
1489       l_last_tmpl_length_ms := REF_TMPL_DTLS.TEMPLATE_LENGTH_DAYS * 24 * 3600 * 1000;
1490       -- also create a dummy row
1491       IF (i = 0)
1492       THEN
1493         i := 1;
1494         x_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1495         x_period_data(i).period_id          := NULL;
1496         x_period_data(i).period_span_ms     := 0;
1497         x_period_data(i).day_start_ms       := 0;
1498         x_period_data(i).day_num            := 1;
1499       ELSE
1500         i := i+1;
1501         x_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1502         x_period_data(i).period_id          := NULL;
1503         x_period_data(i).period_span_ms     := 0;
1504         x_period_data(i).day_start_ms       := x_period_data(i-1).day_start_ms + x_period_data(i-1).period_span_ms;
1505         x_period_data(i).day_num            := x_period_data(i-1).day_num;
1506         --reset if it's crossing the day
1507         IF (x_period_data(i).day_start_ms > 24 * 3600 * 1000)
1508         THEN
1509           x_period_data(i).day_num      := x_period_data(i).day_num + TRUNC(x_period_data(i).day_start_ms / (24 * 3600 * 1000));
1510           x_period_data(i).day_start_ms := x_period_data(i).day_start_ms - (x_period_data(i).day_num - x_period_data(i-1).day_num) * 24 * 3600 * 1000;
1511           IF (x_period_data(i).day_num > 7)
1512           THEN
1513             x_period_data(i).day_num    := x_period_data(i).day_num - 7;
1514           END IF;
1515         END IF;
1516       END IF;
1517     END IF;
1518   END LOOP;
1519 
1520   -- now calculate the gap between the first and last record and
1521   -- fill it so that the template becomes curcular
1522   IF (i > 0)
1523   THEN
1524     l_duration_gap_ms := p_tmpl_length * 24 * 3600 * 1000 - l_total_length_ms;
1525     IF (l_duration_gap_ms > 0)
1526     THEN
1527       -- create a new record for this gap
1528       i:= i+1;
1529       x_period_data(i).template_detail_id := NULL;
1530       x_period_data(i).period_id          := NULL;
1531       x_period_data(i).period_span_ms     := l_duration_gap_ms;
1532       x_period_data(i).day_start_ms       := NULL;
1533       x_period_data(i).day_num            := NULL;
1534     END IF;
1535   END IF;
1536 
1537 END CREATE_PERIOD_DATA_CAL;
1538 
1539 
1540 PROCEDURE CREATE_PERIOD_DATA_DAY
1541 /*******************************************************************************
1542 **
1543 ** CREATE_PERIOD_DATA_DAY
1544 **
1545 ** popluates the period data pl/sql table by expanding the template
1546 ** should be called for day based template
1547 **
1548 *******************************************************************************/
1549 ( p_tmpl_id         IN  NUMBER
1550 , p_tmpl_length     IN  NUMBER
1551 , x_period_data     OUT NOCOPY PERIOD_TBL_TYPE
1552 ) IS
1553 
1554   CURSOR C_TMPL_DETAILS
1555   (
1556     b_tmpl_id    NUMBER
1557   ) IS
1558   SELECT DTLS.TEMPLATE_DETAIL_ID,
1559          DTLS.TEMPLATE_DETAIL_SEQ,
1560          DTLS.TEMPLATE_ID,
1561          DTLS.CHILD_PERIOD_ID,
1562          DTLS.CHILD_TEMPLATE_ID,
1563          DTLS.DAY_START,
1564          DTLS.DAY_STOP,
1565          CSPB.START_TIME_MS,
1566          CSPB.END_TIME_MS,
1567          CSPB.DURATION,
1568          CSPB.DURATION_UOM
1569   FROM CAC_SR_PERIODS_B CSPB,
1570         (SELECT CSTD.TEMPLATE_DETAIL_ID,
1571                CSTD.TEMPLATE_DETAIL_SEQ,
1572                CSTD.TEMPLATE_ID,
1573                CSTD.CHILD_PERIOD_ID,
1574                CSTD.CHILD_TEMPLATE_ID,
1575                CSTD.DAY_START,
1576                CSTD.DAY_STOP
1577         FROM CAC_SR_TMPL_DETAILS CSTD
1578         START WITH CSTD.TEMPLATE_ID = b_tmpl_id
1579         CONNECT BY PRIOR CSTD.CHILD_TEMPLATE_ID = CSTD.TEMPLATE_ID
1580         ORDER SIBLINGS BY TEMPLATE_DETAIL_SEQ) DTLS
1581   WHERE CSPB.PERIOD_ID(+) = DTLS.CHILD_PERIOD_ID
1582   ORDER BY CHILD_PERIOD_ID NULLS FIRST , TEMPLATE_DETAIL_SEQ;  --ADDED FOR BUG#7491187
1583                                                                --MODIFIED FOR BUG#7758438
1584 
1585   TYPE NUMBER_TBL_TYPE IS TABLE OF NUMBER
1586     INDEX BY BINARY_INTEGER;
1587 
1588   i                     BINARY_INTEGER;
1589   l_tmpl_offset         NUMBER_TBL_TYPE;
1590   l_period_data         PERIOD_TBL_TYPE;
1591   l_duration_gap_ms     NUMBER;
1592 
1593 BEGIN
1594 
1595   i := 0;
1596   l_tmpl_offset(p_tmpl_id) := 0;
1597 
1598   FOR REF_TMPL_DTLS IN C_TMPL_DETAILS(p_tmpl_id)
1599   LOOP
1600     IF (REF_TMPL_DTLS.CHILD_PERIOD_ID IS NOT NULL)
1601     THEN
1602       -- this is a period, so add a new record
1603       FOR ref_i IN REF_TMPL_DTLS.DAY_START..REF_TMPL_DTLS.DAY_STOP
1604       LOOP
1605         i := i+1;
1606         l_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1607         l_period_data(i).period_id          := REF_TMPL_DTLS.CHILD_PERIOD_ID;
1608         IF (REF_TMPL_DTLS.DURATION IS NULL)
1609         THEN
1610           l_period_data(i).period_span_ms   := REF_TMPL_DTLS.END_TIME_MS - REF_TMPL_DTLS.START_TIME_MS;
1611         ELSE
1612           l_period_data(i).period_span_ms   := CONVERT_TO_MILLIS(REF_TMPL_DTLS.DURATION,REF_TMPL_DTLS.DURATION_UOM);
1613         END IF;
1614         l_period_data(i).day_start_ms       := NVL(REF_TMPL_DTLS.START_TIME_MS,0);
1615         l_period_data(i).day_num            := l_tmpl_offset(REF_TMPL_DTLS.TEMPLATE_ID) + ref_i;
1616       END LOOP;
1617     ELSE
1618       -- this is a template, so store the tmpl offset for future records
1619       l_tmpl_offset(REF_TMPL_DTLS.CHILD_TEMPLATE_ID) := REF_TMPL_DTLS.DAY_START - 1;
1620       -- add a dummy record
1621       l_period_data(i).template_detail_id := REF_TMPL_DTLS.TEMPLATE_DETAIL_ID;
1622       l_period_data(i).period_id          := NULL;
1623       l_period_data(i).day_start_ms       := 0;
1624       l_period_data(i).day_num            := REF_TMPL_DTLS.DAY_START;
1625       l_period_data(i).period_span_ms     := 0;
1626     END IF;
1627   END LOOP;
1628 
1629   i := 0;
1630   -- loop through the entire template length, find periods for those
1631   -- days and fill up gaps
1632   FOR ref_i IN 1..p_tmpl_length
1633   LOOP
1634     FOR ref_j IN l_period_data.FIRST..l_period_data.LAST
1635     LOOP
1636       IF (ref_i = l_period_data(ref_j).day_num)
1637       THEN
1638         IF (i = 0)
1639         THEN
1640           -- this is the first record being added
1641           -- check if it needs to be prefilled
1642           l_duration_gap_ms := (ref_i - 1) * 24 * 3600 * 1000
1643                                + l_period_data(ref_j).day_start_ms;
1644           IF (l_duration_gap_ms > 0)
1645           THEN
1646             i := 1;
1647             x_period_data(i).template_detail_id := NULL;
1648             x_period_data(i).period_id          := NULL;
1649             x_period_data(i).period_span_ms     := l_duration_gap_ms;
1650             x_period_data(i).day_start_ms       := 0;
1651             x_period_data(i).day_num            := 1;
1652           END IF;
1653         ELSE
1654           -- check if there is any gap between this and the previous record
1655           -- and fill it
1656           l_duration_gap_ms := (ref_i - x_period_data(i).day_num) * 24 * 3600 * 1000
1657                                - (x_period_data(i).day_start_ms + x_period_data(i).period_span_ms)
1658                                + l_period_data(ref_j).day_start_ms;
1659           IF (l_duration_gap_ms > 0)
1660           THEN
1661             i := i+1;
1662             x_period_data(i).template_detail_id := NULL;
1663             x_period_data(i).period_id          := NULL;
1664             x_period_data(i).period_span_ms     := l_duration_gap_ms;
1665             x_period_data(i).day_start_ms       := NULL;
1666             x_period_data(i).day_num            := NULL;
1667           END IF;
1668         END IF;
1669         i := i+1;
1670         x_period_data(i).template_detail_id := l_period_data(ref_j).template_detail_id;
1671         x_period_data(i).period_id          := l_period_data(ref_j).period_id;
1672         x_period_data(i).period_span_ms     := l_period_data(ref_j).period_span_ms;
1673         x_period_data(i).day_start_ms       := l_period_data(ref_j).day_start_ms;
1674         x_period_data(i).day_num            := l_period_data(ref_j).day_num;
1675       END IF;
1676     END LOOP;
1677   END LOOP;
1678 
1679   -- check if the last part needs to be filled
1680   -- i should be the last index
1681   IF (i = 0)
1682   THEN
1683     x_period_data(1).template_detail_id := NULL;
1684     x_period_data(1).period_id          := NULL;
1685     x_period_data(1).period_span_ms     := p_tmpl_length * 24 * 3600 * 1000;
1686     x_period_data(1).day_start_ms       := 0;
1687     x_period_data(1).day_num            := 1;
1688   ELSE
1689     l_duration_gap_ms := (p_tmpl_length+1 - x_period_data(i).day_num) * 24 * 3600 * 1000
1690                          - (x_period_data(i).day_start_ms + x_period_data(i).period_span_ms);
1691     IF (l_duration_gap_ms > 0)
1692     THEN
1693       i := i+1;
1694       x_period_data(i).template_detail_id := NULL;
1695       x_period_data(i).period_id          := NULL;
1696       x_period_data(i).period_span_ms     := l_duration_gap_ms;
1697       x_period_data(i).day_start_ms       := NULL;
1698       x_period_data(i).day_num            := NULL;
1699     END IF;
1700   END IF;
1701 
1702 END CREATE_PERIOD_DATA_DAY;
1703 
1704 
1705 PROCEDURE GET_PERIOD_START_DUR
1706 /*******************************************************************************
1707 **
1708 ** GET_PERIOD_START_DUR
1709 **
1710 ** get the starting index of the pl/sql table to use
1711 ** should be called for duration based template
1712 **
1713 *******************************************************************************/
1714 ( p_Schdl_Start_Date          IN  DATE
1715 , p_period_data               IN  PERIOD_TBL_TYPE
1716 , p_start_template_detail_id  IN  NUMBER
1717 , x_start_index               OUT NOCOPY BINARY_INTEGER
1718 , x_ms_to_use                 OUT NOCOPY NUMBER
1719 ) IS
1720 
1721   l_day_ms            NUMBER;
1722   l_total_ms          NUMBER;
1723 
1724 BEGIN
1725 
1726   x_start_index  := p_period_data.FIRST;
1727   x_ms_to_use    := p_period_data(x_start_index).period_span_ms;
1728 
1729   IF p_start_template_detail_id IS NOT NULL
1730   THEN
1731     -- loop through the records and find out where this date starts
1732     -- the assumption here is that the records start on first day
1733     FOR i IN p_period_data.FIRST..p_period_data.LAST
1734     LOOP
1735       IF (p_start_template_detail_id = p_period_data(i).template_detail_id)
1736       THEN
1737         -- current record will be used
1738         x_start_index := i;
1739         -- calculate how much time should be used
1740         x_ms_to_use := p_period_data(x_start_index).period_span_ms;
1741         -- quit the loop
1742         EXIT;
1743       END IF;
1744     END LOOP;
1745   END IF;
1746 
1747 END GET_PERIOD_START_DUR;
1748 
1749 
1750 PROCEDURE GET_PERIOD_START_CAL
1751 /*******************************************************************************
1752 **
1753 ** GET_PERIOD_START_CAL
1754 **
1755 ** get the starting index of the pl/sql table to use
1756 ** should be called for calendar based template
1757 **
1758 *******************************************************************************/
1759 ( p_Schdl_Start_Date          IN  DATE
1760 , p_period_data               IN  PERIOD_TBL_TYPE
1761 , p_start_template_detail_id  IN  NUMBER
1762 , x_start_index               OUT NOCOPY BINARY_INTEGER
1763 , x_ms_to_use                 OUT NOCOPY NUMBER
1764 , x_ms_use_blank              OUT NOCOPY BOOLEAN
1765 ) IS
1766 
1767   l_sunday_date       DATE;
1768   l_day_number        NUMBER;
1769   l_day_ms            NUMBER;
1770   l_total_ms          NUMBER;
1771   l_start_calc        BOOLEAN;
1772 
1773 BEGIN
1774 
1775   x_start_index  := p_period_data.FIRST;
1776   x_ms_to_use    := p_period_data(x_start_index).period_span_ms;
1777   x_ms_use_blank := FALSE;
1778 
1779   -- get a known sunday
1780   l_sunday_date := TO_DATE('1995/01/01','yyyy/mm/dd');
1781   -- calculate the day number, 1 - sunday, 2 - monday etc.
1782   l_day_number  := MOD((TRUNC(p_Schdl_Start_Date) - l_sunday_date),7);
1783   IF (l_day_number >= 0)
1784   THEN
1785     l_day_number := 1 + l_day_number;
1786   ELSE
1787     l_day_number := 1 - l_day_number;
1788   END IF;
1789 
1790   -- calculate the time, using the day part and time part
1791   l_day_ms := (l_day_number - 1) * 24 * 3600 * 1000
1792              + (p_Schdl_Start_Date - TRUNC(p_Schdl_Start_Date)) * 24 * 3600 * 1000;
1793 
1794   -- loop through the records and find out where this date starts
1795   -- the assumption here is that the records start on sunday
1796   l_start_calc := FALSE;
1797   l_total_ms := 0;
1798   FOR i IN p_period_data.FIRST..p_period_data.LAST
1799   LOOP
1800     IF ((NOT l_start_calc) AND ((p_start_template_detail_id IS NULL) OR
1801        (p_start_template_detail_id = p_period_data(i).template_detail_id)))
1802     THEN
1803       l_start_calc  := TRUE;
1804       x_start_index := i;
1805 	  IF (l_total_ms > l_day_ms)
1806 	  THEN
1807 	    x_ms_to_use    := l_total_ms - l_day_ms;
1808 		x_ms_use_blank := TRUE;
1809 		EXIT;
1810 	  END IF;
1811     END IF;
1812 	l_total_ms := l_total_ms + p_period_data(i).period_span_ms;
1813     IF (l_start_calc)
1814     THEN
1815       IF (l_total_ms > l_day_ms)
1816       THEN
1817 	    x_start_index := i;
1818         -- calculate how much time should be used
1819         x_ms_to_use   := l_total_ms - l_day_ms;
1820         -- quit the loop
1821         EXIT;
1822       END IF;
1823     END IF;
1824   END LOOP;
1825 
1826 END GET_PERIOD_START_CAL;
1827 
1828 
1829 PROCEDURE GET_PERIOD_START_DAY
1830 /*******************************************************************************
1831 **
1832 ** GET_PERIOD_START_DAY
1833 **
1834 ** get the starting index of the pl/sql table to use
1835 ** should be called for day based template
1836 **
1837 *******************************************************************************/
1838 ( p_Schdl_Start_Date          IN  DATE
1839 , p_period_data               IN  PERIOD_TBL_TYPE
1840 , p_start_template_detail_id  IN  NUMBER
1841 , x_start_index               OUT NOCOPY BINARY_INTEGER
1842 , x_ms_to_use                 OUT NOCOPY NUMBER
1843 , x_ms_use_blank              OUT NOCOPY BOOLEAN
1844 ) IS
1845 
1846   l_day_ms            NUMBER;
1847   l_total_ms          NUMBER;
1848   l_start_calc        BOOLEAN;
1849 
1850 BEGIN
1851 
1852   x_start_index  := p_period_data.FIRST;
1853   x_ms_to_use    := p_period_data(x_start_index).period_span_ms;
1854   x_ms_use_blank := FALSE;
1855 
1856   -- calculate the time, using the day part and time part
1857   l_day_ms := (p_Schdl_Start_Date - TRUNC(p_Schdl_Start_Date)) * 24 * 3600 * 1000;
1858 
1859   -- loop through the records and find out where this date starts
1860   -- the assumption here is that the records start on first day
1861   l_start_calc := FALSE;
1862   l_total_ms   := 0;
1863   FOR i IN p_period_data.FIRST..p_period_data.LAST
1864   LOOP
1865     IF ((NOT l_start_calc) AND ((p_start_template_detail_id IS NULL) OR
1866        (p_start_template_detail_id = p_period_data(i).template_detail_id)))
1867     THEN
1868       l_start_calc  := TRUE;
1869       x_start_index := i;
1870 	  IF (p_period_data(i).day_start_ms > l_day_ms)
1871 	  THEN
1872 	    -- this means that the previous record should be used
1873 		x_ms_to_use    := p_period_data(i).day_start_ms - l_day_ms;
1874 		x_ms_use_blank := TRUE;
1875 		EXIT;
1876 	  END IF;
1877       l_total_ms   := p_period_data(i).day_start_ms;
1878     END IF;
1879     IF (l_start_calc)
1880     THEN
1881       l_total_ms := l_total_ms + p_period_data(i).period_span_ms;
1882       IF (l_total_ms > l_day_ms)
1883       THEN
1884         -- current record will be used
1885         x_start_index := i;
1886         -- calculate how much time should be used
1887         x_ms_to_use := l_total_ms - l_day_ms;
1888         -- quit the loop
1889         EXIT;
1890       END IF;
1891     END IF;
1892   END LOOP;
1893 
1894 END GET_PERIOD_START_DAY;
1895 
1896 
1897 PROCEDURE GENERATE_SCHEDULE_DETAILS
1898 /*******************************************************************************
1899 **
1900 ** GENERATE_SCHEDULE_DETAILS
1901 **
1902 **   generates the schedule details
1903 **   - Schedule
1904 **   - template
1905 **   - duration
1906 **
1907 *******************************************************************************/
1908 ( p_period_data               IN  PERIOD_TBL_TYPE
1909 , p_Schdl_Tmpl_Type           IN  VARCHAR2
1910 , p_Schdl_Start_Date          IN  DATE
1911 , p_Schdl_End_Date            IN  DATE
1912 , p_start_template_detail_id  IN  NUMBER
1913 , x_schedule_details          OUT NOCOPY SCHDL_DETAILS_TBL_TYPE
1914 ) IS
1915 
1916   l_rec_start        DATE;
1917   l_rec_end          DATE;
1918   l_schdl_dtls_data  SCHDL_DETAILS_TBL_TYPE;
1919   l_schdl_i          BINARY_INTEGER;
1920   l_period_i         BINARY_INTEGER;
1921   l_ms_to_use        NUMBER;
1922   l_use_blank        BOOLEAN;
1923 
1924 BEGIN
1925 
1926   IF (p_period_data.COUNT > 0)
1927   THEN
1928     IF (p_Schdl_Tmpl_Type = 'DUR')
1929     THEN
1930       GET_PERIOD_START_DUR(p_Schdl_Start_Date,p_period_data,p_start_template_detail_id,l_period_i,l_ms_to_use);
1931       l_use_blank := FALSE;
1932 	ELSIF (p_Schdl_Tmpl_Type = 'CAL')
1933     THEN
1934       GET_PERIOD_START_CAL(p_Schdl_Start_Date,p_period_data,p_start_template_detail_id,l_period_i,l_ms_to_use,l_use_blank);
1935     ELSIF (p_Schdl_Tmpl_Type = 'DAY')
1936     THEN
1937       GET_PERIOD_START_DAY(p_Schdl_Start_Date,p_period_data,p_start_template_detail_id,l_period_i,l_ms_to_use,l_use_blank);
1938     END IF;
1939 
1940     l_schdl_i   := 0;
1941 
1942     l_rec_start := p_Schdl_Start_Date;
1943 
1944     WHILE (l_rec_start < p_Schdl_End_Date+1)
1945     LOOP
1946       -- add the period span to calculate end of the schdl detail record
1947       l_rec_end := l_rec_start + l_ms_to_use / (24*3600*1000.0);
1948       -- if the end is after schedule end then reset it.
1949       -- note tha addition of 1 day, as the end date of schedule has 00 in
1950       -- time part, but it's actually till end of that day
1951       IF (l_rec_end > p_Schdl_End_Date+1)
1952       THEN
1953         l_rec_end := p_Schdl_End_Date+1;
1954       END IF;
1955 
1956       IF (l_schdl_i = 0)
1957       THEN
1958         -- create a new record
1959         l_schdl_i := 1;
1960 		IF (l_use_blank)
1961 		THEN
1962           l_schdl_dtls_data(l_schdl_i).period_id     := NULL;
1963 		ELSE
1964           l_schdl_dtls_data(l_schdl_i).period_id     := p_period_data(l_period_i).period_id;
1965           IF (l_period_i = p_period_data.LAST)
1966           THEN
1967             l_period_i := p_period_data.FIRST;
1968           ELSE
1969             l_period_i := l_period_i + 1;
1970           END IF;
1971         END IF;
1972 		l_schdl_dtls_data(l_schdl_i).start_date_time := l_rec_start;
1973         l_schdl_dtls_data(l_schdl_i).end_date_time   := l_rec_end;
1974       ELSE
1975         IF (NVL(l_schdl_dtls_data(l_schdl_i).period_id,-1) =
1976            NVL(p_period_data(l_period_i).period_id,-1))
1977         THEN
1978           -- if the previous record's period id is same as this one
1979           -- then increment the end of previous record
1980           l_schdl_dtls_data(l_schdl_i).end_date_time := l_rec_end;
1981         ELSE
1982           -- create a new record
1983           l_schdl_i := l_schdl_i + 1;
1984           l_schdl_dtls_data(l_schdl_i).period_id       := p_period_data(l_period_i).period_id;
1985           l_schdl_dtls_data(l_schdl_i).start_date_time := l_rec_start;
1986           l_schdl_dtls_data(l_schdl_i).end_date_time   := l_rec_end;
1987         END IF;
1988         IF (l_period_i = p_period_data.LAST)
1989         THEN
1990           l_period_i := p_period_data.FIRST;
1991         ELSE
1992           l_period_i := l_period_i + 1;
1993         END IF;
1994       END IF;
1995 
1996       -- set the start of next record to the end of this record
1997       l_rec_start := l_rec_end;
1998       l_ms_to_use := p_period_data(l_period_i).period_span_ms;
1999     END LOOP;
2000   ELSE
2001     l_schdl_dtls_data(1).period_id       := NULL;
2002     l_schdl_dtls_data(1).start_date_time := p_Schdl_Start_Date;
2003     l_schdl_dtls_data(1).end_date_time   := p_Schdl_End_Date + 1;
2004   END IF;
2005 
2006   x_schedule_details := l_schdl_dtls_data;
2007 
2008 END GENERATE_SCHEDULE_DETAILS;
2009 
2010 
2011 PROCEDURE POPULATE_SCHEDULE_DETAILS
2012 /*******************************************************************************
2013 **
2014 ** POPULATE_SCHEDULE_DETAILS
2015 **
2016 **   expands the schedule for the given:
2017 **   - Schedule
2018 **   - template
2019 **   - duration
2020 **
2021 *******************************************************************************/
2022 ( p_Schedule_Id          IN     NUMBER               -- id of the schedule
2023 , p_Schdl_Tmpl_Id        IN     NUMBER
2024 , p_Schdl_Tmpl_Length    IN     NUMBER
2025 , p_Schdl_Tmpl_Type      IN     VARCHAR2
2026 , p_Schdl_Start_Date     IN     DATE
2027 , p_Schdl_End_Date       IN     DATE                 -- end date of the schedule
2028                                                      -- 24 hrs will be added to this as it should be till end of that day
2029 ) IS
2030 
2031   CURSOR c_get_schdl_objects
2032   (
2033     b_schedule_id    NUMBER
2034   ) IS
2035   SELECT SCHEDULE_OBJECT_ID
2036        , START_DATE_ACTIVE
2037        , END_DATE_ACTIVE
2038        , START_TEMPLATE_DETAIL_ID
2039   FROM   CAC_SR_SCHDL_OBJECTS
2040   WHERE  SCHEDULE_ID = b_schedule_id;
2041 
2042   l_period_data      PERIOD_TBL_TYPE;
2043   l_schdl_dtls_data  SCHDL_DETAILS_TBL_TYPE;
2044   l_obj_schdl_dtls   SCHDL_DETAILS_TBL_TYPE;
2045 
2046 BEGIN
2047 
2048   IF (p_Schdl_Tmpl_Type = 'DUR')
2049   THEN
2050     CREATE_PERIOD_DATA_DUR(p_Schdl_Tmpl_Id,l_period_data);
2051   ELSIF (p_Schdl_Tmpl_Type = 'CAL')
2052   THEN
2053     CREATE_PERIOD_DATA_CAL(p_Schdl_Tmpl_Id,p_Schdl_Tmpl_Length,l_period_data);
2054   ELSIF (p_Schdl_Tmpl_Type = 'DAY')
2055   THEN
2056     CREATE_PERIOD_DATA_DAY(p_Schdl_Tmpl_Id,p_Schdl_Tmpl_Length,l_period_data);
2057   END IF;
2058 
2059   GENERATE_SCHEDULE_DETAILS
2060   (
2061     l_period_data,
2062     p_Schdl_Tmpl_Type,
2063     p_Schdl_Start_Date,
2064     p_Schdl_End_Date,
2065     NULL,
2066     l_schdl_dtls_data
2067   );
2068 
2069   INSERT_SCHEDULE_DETAILS
2070   (
2071     p_Schedule_id,
2072     NULL,
2073     l_schdl_dtls_data
2074   );
2075 
2076   FOR ref_schdl_objects IN c_get_schdl_objects(p_schedule_id)
2077   LOOP
2078     IF ((ref_schdl_objects.start_date_active = p_Schdl_Start_Date) AND
2079         (ref_schdl_objects.end_date_active = p_Schdl_End_Date) AND
2080         (ref_schdl_objects.start_template_detail_id IS NULL))
2081     THEN
2082       INSERT_SCHEDULE_DETAILS
2083       (
2084         p_Schedule_id,
2085         ref_schdl_objects.schedule_object_id,
2086         l_schdl_dtls_data
2087       );
2088     ELSE
2089       GENERATE_SCHEDULE_DETAILS
2090       (
2091         l_period_data,
2092         p_Schdl_Tmpl_Type,
2093         ref_schdl_objects.start_date_active,
2094         ref_schdl_objects.end_date_active,
2095         ref_schdl_objects.start_template_detail_id,
2096         l_obj_schdl_dtls
2097       );
2098 
2099       INSERT_SCHEDULE_DETAILS
2100       (
2101         p_Schedule_id,
2102         ref_schdl_objects.schedule_object_id,
2103         l_obj_schdl_dtls
2104       );
2105     END IF;
2106   END LOOP;
2107 
2108 END POPULATE_SCHEDULE_DETAILS;
2109 
2110 
2111 PROCEDURE POPULATE_OBJECT_SCHDL_DETAILS
2112 /*******************************************************************************
2113 **
2114 ** POPULATE_OBJECT_SCHDL_DETAILS
2115 **
2116 **   expands the schedule for the given:
2117 **   - Resource
2118 **   - Schedule
2119 **
2120 *******************************************************************************/
2121 ( p_Schedule_Id               IN     NUMBER               -- id of the schedule
2122 , p_Schedule_Object_Id        IN     NUMBER
2123 , p_Object_Start_Date         IN     DATE
2124 , p_Object_End_Date           IN     DATE
2125 , p_Start_Template_Detail_Id  IN     NUMBER
2126 ) IS
2127 
2128   CURSOR c_get_schdl
2129   (
2130     b_schedule_id    NUMBER
2131   ) IS
2132   SELECT CSTB.TEMPLATE_ID
2133        , CSTB.TEMPLATE_TYPE
2134        , CSTB.TEMPLATE_LENGTH_DAYS
2135        , CSSB.START_DATE_ACTIVE
2136        , CSSB.END_DATE_ACTIVE
2137   FROM   CAC_SR_SCHEDULES_B CSSB
2138        , CAC_SR_TEMPLATES_B CSTB
2139   WHERE  CSSB.SCHEDULE_ID = b_schedule_id
2140   AND    CSTB.TEMPLATE_ID = CSSB.TEMPLATE_ID;
2141 
2142   l_period_data       PERIOD_TBL_TYPE;
2143   l_schdl_dtls_data   SCHDL_DETAILS_TBL_TYPE;
2144   l_Schdl_Tmpl_Id     NUMBER;
2145   l_Schdl_Tmpl_Type   VARCHAR2(30);
2146   l_Schdl_Tmpl_Length NUMBER;
2147   l_Schdl_Start_Date  DATE;
2148   l_Schdl_End_Date    DATE;
2149 
2150 BEGIN
2151 
2152   DELETE FROM CAC_SR_SCHDL_DETAILS
2153     WHERE SCHEDULE_OBJECT_ID = p_schedule_object_id;
2154 
2155   OPEN c_get_schdl(p_Schedule_Id);
2156   FETCH c_get_schdl
2157     INTO l_Schdl_Tmpl_Id,l_Schdl_Tmpl_Type,l_Schdl_Tmpl_Length,l_Schdl_Start_Date,l_Schdl_End_Date;
2158   CLOSE c_get_schdl;
2159 
2160   IF (l_Schdl_Tmpl_Type = 'DUR')
2161   THEN
2162     CREATE_PERIOD_DATA_DUR(l_Schdl_Tmpl_Id,l_period_data);
2163   ELSIF (l_Schdl_Tmpl_Type = 'CAL')
2164   THEN
2165     CREATE_PERIOD_DATA_CAL(l_Schdl_Tmpl_Id,l_Schdl_Tmpl_Length,l_period_data);
2166   ELSIF (l_Schdl_Tmpl_Type = 'DAY')
2167   THEN
2168     CREATE_PERIOD_DATA_DAY(l_Schdl_Tmpl_Id,l_Schdl_Tmpl_Length,l_period_data);
2169   END IF;
2170 
2171   GENERATE_SCHEDULE_DETAILS
2172   (
2173     l_period_data,
2174     l_Schdl_Tmpl_Type,
2175     p_Object_Start_Date,
2176     p_Object_End_Date,
2177     p_Start_Template_Detail_Id,
2178     l_schdl_dtls_data
2179   );
2180 
2181   INSERT_SCHEDULE_DETAILS
2182   (
2183     p_Schedule_id,
2184     p_Schedule_Object_Id,
2185     l_schdl_dtls_data
2186   );
2187 
2188 END POPULATE_OBJECT_SCHDL_DETAILS;
2189 
2190 
2191 PROCEDURE POST_CREATE_SCHEDULE
2192 /*******************************************************************************
2193 **
2194 ** POST_CREATE_SCHEDULE
2195 **
2196 **   expands the schedule for the given:
2197 **   - Schedule
2198 **   - template
2199 **   - duration
2200 **   and submits business events
2201 **
2202 *******************************************************************************/
2203 ( p_Schedule_Id          IN     NUMBER               -- id of the schedule
2204 , p_Schedule_Category    IN     VARCHAR2
2205 , p_Schdl_Tmpl_Id        IN     NUMBER
2206 , p_Schdl_Tmpl_Length    IN     NUMBER
2207 , p_Schdl_Tmpl_Type      IN     VARCHAR2
2208 , p_Schdl_Start_Date     IN     DATE
2209 , p_Schdl_End_Date       IN     DATE
2210 )
2211 IS
2212 
2213   CURSOR c_get_schdl_objects
2214   (
2215     b_schedule_id    NUMBER
2216   ) IS
2217   SELECT OBJECT_TYPE
2218        , OBJECT_ID
2219        , START_DATE_ACTIVE
2220        , END_DATE_ACTIVE
2221   FROM   CAC_SR_SCHDL_OBJECTS
2222   WHERE  SCHEDULE_ID = b_schedule_id;
2223 
2224 BEGIN
2225 
2226   POPULATE_SCHEDULE_DETAILS
2227   (
2228     p_Schedule_Id,
2229     p_Schdl_Tmpl_Id,
2230     p_Schdl_Tmpl_Length,
2231     p_Schdl_Tmpl_Type,
2232     p_Schdl_Start_Date,
2233     p_Schdl_End_Date
2234   );
2235 
2236   CAC_AVLBLTY_EVENTS_PVT.RAISE_CREATE_SCHEDULE
2237   (
2238     p_Schedule_Id,
2239     p_Schedule_Category,
2240     p_Schdl_Start_Date,
2241     p_Schdl_End_Date
2242   );
2243 
2244   FOR ref_objects IN c_get_schdl_objects(p_Schedule_Id)
2245   LOOP
2246     CAC_AVLBLTY_EVENTS_PVT.RAISE_ADD_RESOURCE
2247     (
2248       p_Schedule_Id,
2249       p_Schedule_Category,
2250       p_Schdl_Start_Date,
2251       p_Schdl_End_Date,
2252       ref_objects.object_type,
2253       ref_objects.object_id,
2254       ref_objects.start_date_active,
2255       ref_objects.end_date_active
2256     );
2257   END LOOP;
2258 
2259 END POST_CREATE_SCHEDULE;
2260 
2261 
2262 PROCEDURE POST_UPDATE_SCHEDULE
2263 /*******************************************************************************
2264 **
2265 ** POST_UPDATE_SCHEDULE
2266 **
2267 **   expands the schedule for the given:
2268 **   - Schedule
2269 **   - template
2270 **   - duration
2271 **   and submits business events
2272 **
2273 *******************************************************************************/
2274 ( p_Schedule_Id          IN     NUMBER               -- id of the schedule
2275 , p_Schedule_Category    IN     VARCHAR2
2276 , p_Schdl_Tmpl_Id        IN     NUMBER
2277 , p_Schdl_Tmpl_Length    IN     NUMBER
2278 , p_Schdl_Tmpl_Type      IN     VARCHAR2
2279 , p_Schdl_Start_Date     IN     DATE
2280 , p_Schdl_End_Date       IN     DATE
2281 )
2282 IS
2283 
2284   CURSOR c_get_schdl_objects
2285   (
2286     b_schedule_id    NUMBER
2287   ) IS
2288   SELECT CSSO.OBJECT_TYPE
2289        , CSSO.OBJECT_ID
2290        , CSSO.START_DATE_ACTIVE
2291        , CSSO.END_DATE_ACTIVE
2292        , CSSD.SCHEDULE_OBJECT_ID
2293   FROM   CAC_SR_SCHDL_OBJECTS CSSO,
2294          (SELECT SCHEDULE_OBJECT_ID, MIN(START_DATE_TIME)
2295           FROM CAC_SR_SCHDL_DETAILS
2296           WHERE SCHEDULE_ID = b_schedule_id
2297          ) CSSD
2298   WHERE  CSSO.SCHEDULE_ID = b_schedule_id
2299   AND    CSSD.SCHEDULE_OBJECT_ID(+) = CSSO.SCHEDULE_OBJECT_ID;
2300 
2301 BEGIN
2302 
2303   DELETE FROM CAC_SR_SCHDL_DETAILS
2304   WHERE SCHEDULE_ID = p_schedule_id;
2305 
2306   POPULATE_SCHEDULE_DETAILS
2307   (
2308     p_Schedule_Id,
2309     p_Schdl_Tmpl_Id,
2310     p_Schdl_Tmpl_Length,
2311     p_Schdl_Tmpl_Type,
2312     p_Schdl_Start_Date,
2313     p_Schdl_End_Date
2314   );
2315 
2316   CAC_AVLBLTY_EVENTS_PVT.RAISE_UPDATE_SCHEDULE
2317   (
2318     p_Schedule_Id,
2319     p_Schedule_Category,
2320     p_Schdl_Start_Date,
2321     p_Schdl_End_Date
2322   );
2323 
2324 END POST_UPDATE_SCHEDULE;
2325 
2326 
2327 PROCEDURE POST_DELETE_SCHEDULE
2328 /*******************************************************************************
2329 **
2330 ** POST_DELETE_SCHEDULE
2331 **
2332 **   submits business events
2333 **
2334 *******************************************************************************/
2335 ( p_Schedule_Id          IN     NUMBER               -- id of the schedule
2336 , p_Schedule_Category    IN     VARCHAR2
2337 , p_Schdl_Start_Date     IN     DATE
2338 , p_Schdl_End_Date       IN     DATE
2339 )
2340 IS
2341 
2342 BEGIN
2343 
2344   CAC_AVLBLTY_EVENTS_PVT.RAISE_DELETE_SCHEDULE
2345   (
2346     p_Schedule_Id,
2347     p_Schedule_Category,
2348     p_Schdl_Start_Date,
2349     p_Schdl_End_Date
2350   );
2351 
2352 END POST_DELETE_SCHEDULE;
2353 
2354 
2355 END CAC_AVLBLTY_PVT;