DBA Data[Home] [Help]

PACKAGE BODY: APPS.AHL_VWP_TIMES_PVT

Source


1 PACKAGE BODY AHL_VWP_TIMES_PVT AS
2  /* $Header: AHLVTMSB.pls 120.3 2007/12/31 10:32:48 rnahata ship $ */
3 
4 -----------------------------------------------------------------
5 --   Define Global CONSTANTS                                   --
6 -----------------------------------------------------------------
7 G_APP_NAME            CONSTANT VARCHAR2(3) := 'AHL';
8 G_PKG_NAME            CONSTANT VARCHAR2(30) := 'AHL_VWP_TIMES_PVT';
9 
10 G_SECS_IN_DAY         CONSTANT NUMBER := 86400; --Seconds in a day
11 G_HOLIDAY_TYPE        CONSTANT NUMBER := 2;
12 
13 -- Package level Global Variables used in time calculations
14 G_CURRENT_DEPT_ID     NUMBER := NULL;  -- Cached department id, so to know whether to reload
15 
16 G_CAL_START           DATE   := NULL;  -- Calendar start date for shift data
17 G_CAL_END             DATE   := NULL;  -- Calendar end date for shift data
18 G_SHIFT_START         NUMBER := NULL;  -- Shift start in .decimal value of days
19 G_SHIFT_END           NUMBER := NULL;  -- Shift end in .decimal value of days
20 G_DAYS_ON             NUMBER := NULL;  -- Number of Days on
21 G_DAYS_OFF            NUMBER := NULL;  -- Number of Days off
22 G_VISIT_START_DATE    DATE   := NULL;  -- The visit start date
23 G_VISIT_DEPT_ID       NUMBER := NULL;  -- The visit department
24 G_VISIT_STATUS        VARCHAR2(30):= NULL;  --The visit status
25 G_RESET_SYSDATE_FLAG  VARCHAR2(1);
26 
27 /*Added by sowsubra*/
28 G_ASSOC_TYPE_ROUTE      CONSTANT VARCHAR2(30) := 'ROUTE';
29 G_ASSOC_TYPE_OPERATION  CONSTANT VARCHAR2(30) := 'OPERATION';
30 
31 -- Table type for all the Dates while deriving visit and task times
32 TYPE Dates_Tbl_Type IS TABLE OF DATE
33     INDEX BY BINARY_INTEGER;
34 TYPE Number_Tbl_Type IS TABLE OF NUMBER
35     INDEX BY BINARY_INTEGER;
36 
37 G_EXCEPTION_DATES_TBL Dates_Tbl_Type; -- Stores the holidays for dept
38 G_STAGES_TBL  Number_Tbl_Type;        -- Stores the stage offsets for visit
39 ------------------------------------
40 -- Common constants and variables --
41 ------------------------------------
42 l_log_current_level     NUMBER      := fnd_log.g_current_runtime_level;
43 l_log_statement         NUMBER      := fnd_log.level_statement;
44 l_log_procedure         NUMBER      := fnd_log.level_procedure;
45 l_log_error             NUMBER      := fnd_log.level_error;
46 l_log_unexpected        NUMBER      := fnd_log.level_unexpected;
47 -----------------------------------------------------------------------
48 /*procedure adbug(p_msg_txt in varchar2 , p_message in date)
49 is
50 begin
51     if (true) then
52      dbms_output.put_line(p_msg_txt || to_char(p_message,'dd:mm:yyyy hh24:mi:ss'));
53     end if;
54 end adbug;
55 
56 procedure adbug(p_message in varchar2)
57 is
58 begin
59     if (true) then
60      dbms_output.put_line(p_message);
61    end if;
62 end adbug;
63 */
64 --------------------------------------------------------------------
65 -- Define local procedures signature                              --
66 --------------------------------------------------------------------
67 --------------------------------------------------------------------
68 --Initializes the global variables based on the department id
69 --------------------------------------------------------------------
70 PROCEDURE Init_Shift_Data(p_department_id IN number);
71 
72 --------------------------------------------------------------------
73 --Internal recursion code for setting task times
74 --------------------------------------------------------------------
75 PROCEDURE Adjust_Task_Times_Internal(p_task_id IN NUMBER);
76 
77 --------------------------------------------------------------------
78 -- Define local functions signature                               --
79 --------------------------------------------------------------------
80 
81 ----------------------------------------------------------------------
82 -- Gets the duration of a Route from its timespan column
83 ---------------------------------------------------------------------
84 -- Determines if a specific date is a holiday
85 FUNCTION Is_Dept_Holiday(l_curr_date DATE) RETURN BOOLEAN;
86 
87 ----------------------------------------------------------
88 -- Derive the shift start date based on shift timing.
89 ------------------------------------------------------------
90 FUNCTION get_shift_start_date(p_date IN DATE)
91 RETURN DATE
92 IS
93 BEGIN
94  --If it's an overnight shift and time is before shift ends on the same day,
95   --the shift started a day earlier
96   IF (G_SHIFT_END < G_SHIFT_START AND
97      p_date < trunc(p_date)+G_SHIFT_END) THEN
98         RETURN TRUNC(p_date) -1;
99   ELSE
100         RETURN TRUNC(p_date);
101   END IF;
102 END get_shift_start_date;
103 --------------------------------------------------------------------
104 -- Define procedures body                                   --
105 --------------------------------------------------------------------
106 --------------------------------------------------------------------
107 --  Function name    : Get_Visit_Start_Time
108 --  Type             : Public
109 --  Purpose          : Fetches Master Work Order Actual Start Date if the
110 --                     Visit is Closed, else RETURNs the Visit Start Date.
111 --
112 --  Parameters  :
113 --        p_visit_id   Visit ID to fetch the data
114 --
115 --  Version :
116 --     17 September, 2007   RNAHATA  Initial Version - 1.0
117 --
118 --  Added for Bug 6430038
119 --------------------------------------------------------------------
120 function Get_Visit_Start_Time(
121      p_visit_id   IN   NUMBER
122  )
123 RETURN DATE
124 IS
125 --
126 -- To get the Start Date and Status of the Visit
127 CURSOR c_visit_csr (c_visit_id IN NUMBER) IS
128  SELECT START_DATE_TIME, STATUS_CODE
129  FROM AHL_VISITS_B
130  WHERE VISIT_ID = c_visit_id;
131 
132 -- Actual Visit Start Date
133 CURSOR get_actual_start_date_csr(c_visit_id IN NUMBER) IS
134  SELECT ACTUAL_START_DATE
135  FROM AHL_WORKORDERS
136  WHERE VISIT_ID = c_visit_id
137   AND VISIT_TASK_ID IS NULL
138   AND MASTER_WORKORDER_FLAG = 'Y';
139 
140 --
141 l_actual_start_date DATE := null;
142 c_visit_rec c_visit_csr%ROWTYPE;
143 L_API_NAME    CONSTANT VARCHAR2(30)  := 'Get_Visit_Start_Time';
144 L_DEBUG_KEY   CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
145 --
146 BEGIN
147 
148    IF (l_log_procedure >= l_log_current_level) THEN
149       fnd_log.string(l_log_procedure,
150                      L_DEBUG_KEY ||'.begin',
151                      'At the start of PL SQL function. Visit Id = ' || p_visit_id);
152    END IF;
153 
154    OPEN c_visit_csr(p_visit_id);
155    FETCH c_visit_csr INTO c_visit_rec;
156    CLOSE c_visit_csr;
157 
158    -- Closed
159    IF c_visit_rec.STATUS_CODE ='CLOSED' THEN
160       OPEN get_actual_start_date_csr (p_visit_id);
161       FETCH get_actual_start_date_csr INTO l_actual_start_date;
162       CLOSE get_actual_start_date_csr;
163       IF (l_log_procedure >= l_log_current_level) THEN
164          fnd_log.string(l_log_procedure,
165                         L_DEBUG_KEY ||'.end',
166                         'At the end of PL SQL function. Visit Start Date = ' || l_actual_start_date);
167       END IF;
168       RETURN l_actual_start_date;
169 
170    -- Planning/Released/Partially Released/Cancelled
171    ELSE
172       IF (l_log_procedure >= l_log_current_level) THEN
173          fnd_log.string(l_log_procedure,
174                         L_DEBUG_KEY ||'.end',
175                         'At the end of PL SQL function. Visit Start Date = ' || c_visit_rec.START_DATE_TIME);
176       END IF;
177       RETURN c_visit_rec.START_DATE_TIME;
178    END IF;
179 
180 END Get_Visit_Start_Time;
181 
182 --------------------------------------------------------------------
183 -- Define procedures body
184 --------------------------------------------------------------------
185 --------------------------------------------------------------------
186 --  Function name    : Get_Visit_End_Time
187 --  Type             : Public
188 --  Purpose          : To RETURN the End Date for the visit.
189 --                     For Unit Affectivity API it returns
190 --                      Master Work Order Actual End Date when visit is Closed
191 --                      and NVL(Visit Close Date,Max(Task End Times))
192 --                     For VWP it returns
193 --                      Max(Task End Times) when Visit is in Planning
194 --                      Max(Max(WO Released Job Completion Date),Max(Task End Times))
195 --
196 --  Parameters  :
197 --       p_visit_id    Visit ID to fetch the data
198 --       p_use_actual  This is a boolean value equal to FND_API.G_FALSE
199 --                     when the call is made from UA or FND_API.G_TRUE
200 --                     the call is made internally from VWP.
201 --
202 --------------------------------------------------------------------
203 FUNCTION Get_Visit_End_Time(
204       p_visit_id     IN   NUMBER,
205       p_use_actuals  IN   VARCHAR2 := FND_API.G_TRUE
206   )
207 RETURN DATE
208 IS
209 --
210 -- To find visit related information
211 CURSOR c_visit_csr (c_id IN NUMBER) IS
212 SELECT CLOSE_DATE_TIME, START_DATE_TIME, DEPARTMENT_ID, status_code
213 FROM AHL_VISITS_B
214 WHERE VISIT_ID = c_id;
215 --
216 CURSOR get_end_date_csr(c_visit_id IN NUMBER) IS
217  SELECT MAX(end_date_time)
218  FROM AHL_VISIT_TASKS_B
219  WHERE VISIT_ID = c_visit_id
220  AND STATUS_CODE NOT IN ('RELEASED','DELETED'); -- Modified by rnahata for Bug 6369279
221  -- AND STATUS_CODE <> 'RELEASED';
222 --
223 -- Added by yazhou Sept-21-2004
224 CURSOR get_wo_end_date_csr(c_visit_id IN NUMBER) IS
225     SELECT MAX(WIP.SCHEDULED_COMPLETION_DATE)
226     FROM AHL_WORKORDERS WO,
227          WIP_DISCRETE_JOBS WIP,
228          AHL_VISIT_TASKS_B VT
229     WHERE vt.status_code = 'RELEASED'
230     AND vt.VISIT_ID = c_visit_id
231     AND vt.visit_task_id = wo.VISIT_TASK_ID
232 --  AND wo.MASTER_WORKORDER_FLAG = 'N'
233     AND WIP.WIP_ENTITY_ID = WO.WIP_ENTITY_ID
234     AND wo.status_code not in ('22','7');
235 
236 -- Begin changes by rnahata for Bug 6430038
237 -- Actual Visit End Date
238 CURSOR get_actual_end_date_csr(c_visit_id IN NUMBER) IS
239  SELECT ACTUAL_END_DATE
240  FROM AHL_WORKORDERS
241  WHERE VISIT_ID = c_visit_id
242   AND VISIT_TASK_ID IS NULL
243   AND MASTER_WORKORDER_FLAG = 'Y';
244 --
245 CURSOR get_valid_visit_tasks_csr(c_visit_id IN NUMBER) IS
246  SELECT count(*)
247  FROM AHL_VISIT_TASKS_B
248  WHERE VISIT_ID = c_visit_id
249  AND STATUS_CODE <>'DELETED';
250 -- End changes by rnahata for Bug 6430038
251 
252   l_end_date    DATE := null; --The visit end date
253   l_wo_end_date DATE := null; --The last WO end date
254   c_visit_rec c_visit_csr%ROWTYPE;
255   l_cnt         NUMBER := 0;
256   L_API_NAME    CONSTANT VARCHAR2(30)  := 'Get_Visit_End_Time';
257   L_DEBUG_KEY   CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
258 --
259 BEGIN
260 
261    IF (l_log_procedure >= l_log_current_level) THEN
262       fnd_log.string(l_log_procedure,
263                      L_DEBUG_KEY ||'.begin',
264                      'At the start of PL SQL function. Visit Id = ' || p_visit_id ||
265                      ', p_use_actuals = ' || p_use_actuals);
266    END IF;
267 
268    --Fetch the visit information
269    OPEN c_visit_csr(p_visit_id);
270    FETCH c_visit_csr INTO c_visit_rec;
271    CLOSE c_visit_csr;
272 
273    IF (c_visit_rec.START_DATE_TIME IS NOT NULL
274        AND c_visit_rec.START_DATE_TIME <> Fnd_Api.G_MISS_DATE
275        AND c_visit_rec.DEPARTMENT_ID IS NOT NULL
276        AND c_visit_rec.DEPARTMENT_ID <> Fnd_Api.G_MISS_NUM) THEN
277 
278       OPEN get_end_date_csr (p_visit_id);
279       FETCH get_end_date_csr INTO l_end_date;
280       CLOSE get_end_date_csr;
281    END IF;
282 
283    IF ((p_use_actuals IS NOT NULL AND    --p_use_actuals is not null and
284       NOT(FND_API.TO_BOOLEAN(p_use_actuals)))) THEN --p_use_actuals is false
285       -- Begin changes by rnahata for Bug 6430038
286 
287       -- Closed Visit
288       IF c_visit_rec.STATUS_CODE ='CLOSED' THEN
289          OPEN get_actual_end_date_csr (p_visit_id);
290          FETCH get_actual_end_date_csr INTO l_end_date;
291          CLOSE get_actual_end_date_csr;
292          RETURN l_end_date;
293 
294       -- Planning/Released/Partially Released/Cancelled Visit
295       ELSE
296          IF (c_visit_rec.CLOSE_DATE_TIME IS NOT NULL) THEN
297             RETURN c_visit_rec.CLOSE_DATE_TIME;
298          ELSE
299             OPEN get_valid_visit_tasks_csr (p_visit_id);
300             FETCH get_valid_visit_tasks_csr INTO l_cnt;
301             CLOSE get_valid_visit_tasks_csr;
302 
303             IF ( l_cnt > 0 ) THEN
304               RETURN l_end_date;
305             ELSE
306               RETURN c_visit_rec.START_DATE_TIME;
307             END IF;
308          END IF;
309       END IF;
310       -- End changes by rnahata for Bug 6430038
311    END IF;
312 
313    -- Added by yazhou Sept-21-2004
314    IF c_visit_rec.status_code ='PLANNING' THEN
315       RETURN l_end_date;
316    ELSE  -- Released/Partially Released/Closed/Cancelled
317 
318       OPEN get_wo_end_date_csr (p_visit_id);
319       FETCH get_wo_end_date_csr INTO l_wo_end_date;
320       CLOSE get_wo_end_date_csr;
321 
322       IF l_end_date IS NULL THEN
323          RETURN  l_wo_end_date;
324       END IF;
325 
326       IF l_wo_end_date IS NULL THEN
327           RETURN  l_end_date;
328       END IF;
329 
330       IF l_wo_end_date > l_end_date THEN
331          RETURN l_wo_end_date;
332       ELSE
333          RETURN l_end_date;
334       END IF;
335 
336    END IF;
337 END Get_Visit_End_Time;
338 
339 -------------------------------------------------------------------
340 --  Procedure name    : Calculate_Task_Times
341 --  Type              : Private
342 --  Function          : Derive the start and end times/hours of tasks
343 --                      and the end_date_time of the visit
344 --  Parameters  :
345 --
346 --  Standard OUT Parameters :
347 --      x_return_status       OUT     VARCHAR2     Required
348 --      x_msg_count           OUT     NUMBER       Required
349 --      x_msg_data            OUT     VARCHAR2     Required
350 --
351 --  Calculate_Task_Times Parameters:
352 --      p_visit_id            IN      NUMBER       Required
353 --         The id of the visit whose associated tasks' start and end times or hours
354 --         need to be derived
355 --  Version :
356 --      Initial Version   1.0
357 --
358 -- ASSUMPTIONS:
359 --   A Task can appear only once for a given visit (ahl_visit_tasks_b)
360 --   A Department can have only one shift (ahl_department_shifts)
361 --   Shift_Num is unique in bom_shift_times
362 --
363 -------------------------------------------------------------------
364 PROCEDURE Calculate_Task_Times
365 (
366     p_api_version      IN         NUMBER,
367     p_init_msg_list    IN         VARCHAR2  := Fnd_Api.G_FALSE,
368     p_commit           IN         VARCHAR2  := Fnd_Api.G_FALSE,
369     p_validation_level IN         NUMBER    := Fnd_Api.G_VALID_LEVEL_FULL,
370     x_return_status    OUT NOCOPY VARCHAR2,
371     x_msg_count        OUT NOCOPY NUMBER,
372     x_msg_data         OUT NOCOPY VARCHAR2,
373     p_visit_id         IN         NUMBER)
374 IS
375 --
376 --Fetch basic visit data
377 CURSOR get_visit_data_csr(p_visit_id IN NUMBER) IS
378 SELECT v.start_date_time, v.department_id
379 FROM AHL_VISITS_B v, AHL_DEPARTMENT_SHIFTS shifts
380 WHERE v.department_id = shifts.department_id
381 AND v.visit_id = p_visit_id;
382 --
383 --Cursor for deriving all the stage start hours
384 CURSOR get_stage_data_csr(P_VISIT_ID IN number)
385 IS
386 SELECT stage_id, duration
387 --, sum(duration) over(order by stage_num) CUMUL_DURATION
388 from ahl_vwp_stages_vl
389 where visit_id = p_visit_id
390 order by stage_num;
394 IS
391 -----------
392 --Fetch the tasks for the visit in tech dependency sorted sequence
393 CURSOR get_task_data_csr(p_visit_id IN NUMBER)
395 SELECT dtl.visit_task_id,
396        max(dtl.task_level) task_level,
397        max(NVL(vtsk.start_from_hour,0)) start_from_hour,
398        /*sowsubra*/
399        max(NVL(vtsk.duration, NVL(Get_task_duration(vtsk.quantity, routes.route_id), 0))) duration,
400        max(vtsk.stage_id) stage_id,
401        max(vtsk.department_id) department_id
402 FROM AHL_VISIT_TASKS_B vtsk,
403          ahl_routes_app_v routes, ahl_mr_routes_app_v mr,
404    (SELECT visit_task_id, level+1 task_level
405      FROM ahl_task_links tl
406      WHERE visit_task_id in (
407        SELECT visit_task_id from ahl_visit_tasks_b vt
408          where (VT.STATUS_CODE IS NULL OR (VT.STATUS_CODE  <> 'DELETED' AND VT.STATUS_CODE  <> 'RELEASED')))
409      START WITH tl.parent_task_id in
410       (SELECT visit_task_id from ahl_visit_tasks_b vt
411          where  vt.visit_id=p_visit_id
412            AND  vt.visit_task_id not in (SELECT visit_task_id from ahl_task_links)
413            and (VT.STATUS_CODE IS NULL OR (VT.STATUS_CODE  <> 'DELETED' AND VT.STATUS_CODE  <> 'RELEASED'))
414            AND vt.TASK_TYPE_CODE <> 'SUMMARY')
415      CONNECT BY tl.parent_task_id = prior tl.visit_task_id
416      union
417      SELECT vt.visit_task_id, 1 task_level
418      FROM ahl_visit_tasks_b vt
419      WHERE vt.visit_task_id not in (SELECT visit_task_id from ahl_task_links)
420      AND vt.visit_id =p_visit_id
421      AND (VT.STATUS_CODE IS NULL OR (VT.STATUS_CODE  <> 'DELETED' AND VT.STATUS_CODE  <> 'RELEASED'))
422      AND vt.TASK_TYPE_CODE <> 'SUMMARY'
423  ) dtl
424  WHERE dtl.visit_task_id = vtsk.visit_task_id
425    AND routes.route_id (+)= mr.route_id
426    AND mr.mr_route_id (+) = vtsk.mr_route_id
427  group by dtl.visit_task_id
428  order by task_level;
429 
430 --
431 --This cursor uses the technical dependencies and finds the parent task
432 -- that finishes last.
433 CURSOR get_tech_dependency_csr(p_task_id IN NUMBER) IS
434 SELECT max(vt.end_date_time)
435 FROM AHL_VISIT_TASKS_B vt, AHL_TASK_LINKS tl
436 WHERE vt.visit_task_id = tl.parent_task_id
437 AND tl.visit_task_id = p_task_id;
438 --
439 
440 --Cursor for deriving all the tasks in production
441 CURSOR get_wo_data_csr(P_VISIT_ID IN number)
442 IS
443     SELECT vt.VISIT_TASK_ID,
444           WIP.SCHEDULED_START_DATE,
445           WIP.SCHEDULED_COMPLETION_DATE
446     FROM AHL_WORKORDERS WO,
447          WIP_DISCRETE_JOBS WIP,
448          AHL_VISIT_TASKS_B VT
449     WHERE vt.status_code = 'RELEASED'
450     AND   vt.VISIT_ID = P_VISIT_ID
451     AND   vt.visit_task_id = wo.VISIT_TASK_ID(+)
452 --  AND   wo.MASTER_WORKORDER_FLAG = 'N'
453     AND   WIP.WIP_ENTITY_ID(+) = WO.WIP_ENTITY_ID
454     AND   wo.status_code not in ('22','7');
455 
456 -- Define local variables
457   l_api_version CONSTANT NUMBER := 1.0;
458   L_API_NAME    CONSTANT VARCHAR2(30) := 'Calculate_Task_Times';
459   L_DEBUG_KEY   CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
460   l_start_date           DATE;   --Task start date
461   l_end_date             DATE;   --Task end date
462   l_temp_date            DATE;   --temporary local variable
463   l_cum_duration         NUMBER :=0;
464   l_task_data_rec        get_task_data_csr%ROWTYPE;
465   l_stage_data_rec       get_stage_data_csr%ROWTYPE;
466   l_wo_data_rec          get_wo_data_csr%ROWTYPE;
467 --
468 BEGIN
469 
470    SAVEPOINT calculate_task_Times_pvt;
471 
472    IF (l_log_procedure >= l_log_current_level) THEN
473       fnd_log.string(l_log_procedure,
474                      L_DEBUG_KEY ||'.begin',
475                      'At the start of PL SQL procedure. Visit Id = ' || p_visit_id);
476    END IF;
477 
478    -- Standard call to check for call compatibility
479    IF NOT Fnd_Api.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
480                                      G_PKG_NAME) THEN
481        RAISE Fnd_Api.G_EXC_UNEXPECTED_ERROR;
482    END IF;
483 
484    -- Initialize message list if p_init_msg_list is set to TRUE
485    IF Fnd_Api.To_Boolean(p_init_msg_list) THEN
486       Fnd_Msg_Pub.Initialize;
487    END IF;
488 
489    -- Initialize API RETURN status to success
490    x_return_status := Fnd_Api.G_RET_STS_SUCCESS;
491 
492    -- Calculate Task time for tasks in Planning Status
493    -- Begin Processing
494    -- 1. Fetch the Visit's deparment id and visit start date
495     OPEN get_visit_data_csr(p_visit_id);
496     FETCH get_visit_data_csr INTO G_VISIT_START_DATE, G_VISIT_DEPT_ID;
497     IF (get_visit_data_csr%NOTFOUND) THEN
498 
499        UPDATE AHL_VISIT_TASKS_B
500        SET START_DATE_TIME = Null,
501            END_DATE_TIME = Null,
502            object_version_number = object_version_number +1
503        WHERE visit_id = p_visit_id
507        --Fnd_Message.Set_Token('VISIT_ID', p_visit_id);
504        AND nvl(Status_Code, 'X') <>'DELETED';
505 
506        --Fnd_Message.Set_Name('AHL','AHL_LTP_VISIT_ID_INVALID');
508        --Fnd_Msg_Pub.ADD;
509        CLOSE get_visit_data_csr;
510        RETURN;
511     END IF;
512     CLOSE get_visit_data_csr;
513 
514     /*
515     --Can not evaluate if either visit start date or visit department is null
516     IF (G_VISIT_START_DATE IS NULL) THEN
517         --Fnd_Message.Set_Name('AHL','AHL_LTP_VISIT_ST_DATE_NULL');
518         --Fnd_Msg_Pub.ADD;
519         RETURN;
520     ELSIF (G_VISIT_DEPT_ID IS NULL) THEN
521         --Fnd_Message.Set_Name('AHL','AHL_LTP_VISIT_DEPT_NULL');
522         --Fnd_Msg_Pub.ADD;
523         RETURN;
524     END IF;
525     */
526 
527     --Clear up previous calculated task start/end date if visit start date or dept is missing
528     IF (G_VISIT_START_DATE IS NULL) OR (G_VISIT_DEPT_ID IS NULL) THEN
529        UPDATE AHL_VISIT_TASKS_B
530        SET START_DATE_TIME = Null,
531            END_DATE_TIME = Null,
532            object_version_number = object_version_number +1
533        WHERE visit_id = p_visit_id
534        AND nvl(Status_Code, 'X') <>'DELETED';
535        RETURN;
536     END IF;
537 
538    --2. Derive the stage time durations
539    FOR l_stage_data_rec in get_stage_data_csr(p_visit_id)
540    LOOP
541      G_STAGES_TBL(l_stage_data_rec.stage_id) := l_cum_duration;
542      l_cum_duration := l_cum_duration + l_stage_data_rec.duration;
543    END LOOP; -- get_stage_data_csr;
544 
545    --3. Fetch all the tasks sorted by the dependency hierarchy.
546    FOR l_task_data_rec in get_task_data_csr(p_visit_id)
547    LOOP
548 
549       --Add the stage offset 1st to the visit date and use visit department id
550       IF (l_task_data_rec.stage_id IS NOT NULL) THEN
551          l_start_date := Compute_Date (G_VISIT_START_DATE, G_VISIT_DEPT_ID, G_STAGES_TBL(l_task_data_rec.stage_id));
552       ELSE
553          l_start_date := G_VISIT_START_DATE;
554       END IF;
555 
556       --Compute using the department id of the task for task offset number
557       l_start_date := Compute_Date(l_start_date, nvl(l_task_data_rec.department_id, G_VISIT_DEPT_ID), l_task_data_rec.start_from_hour);
558 
559       --3a. Find the max end time of the dependent parents. All parents should be calculated
560       -- because of the sort order of the task cursor query.
561       OPEN get_tech_dependency_csr(l_task_data_rec.visit_task_id);
562       FETCH get_tech_dependency_csr INTO l_temp_date;
563       IF (get_tech_dependency_csr%FOUND AND
564          l_temp_date IS NOT NULL) THEN
565          --If stage offset is later than technical dependencies.
566          --Conform the task end date to the shift times
567          IF (l_temp_date > l_start_date) THEN
568             l_start_date := Compute_Date(l_temp_date, nvl(l_task_data_rec.department_id, G_VISIT_DEPT_ID),0);
569          END IF;
570       END IF;
571       CLOSE get_tech_dependency_csr;
572 
573       --3c. Now derive the end date based on the start date
574       l_end_date := compute_date(l_start_date,
575                            nvl(l_task_data_rec.department_id, G_VISIT_DEPT_ID),
576                            l_task_data_rec.duration);
577 
578       --3d Update the tasks table with the new dates and times.
579       UPDATE AHL_VISIT_TASKS_B
580       SET START_DATE_TIME = l_start_date,
581           END_DATE_TIME = l_end_date
582       WHERE visit_task_id = l_task_data_rec.visit_task_id;
583 
584    END LOOP; --get_task_data_csr;
585 
586    -- Added by yazhou Sept-21-2004
587    -- Derive Task time for tasks in Released Status
588    FOR l_wo_data_rec in get_wo_data_csr(p_visit_id)
589    LOOP
590        --Update the tasks table with the new dates and times.
591        UPDATE AHL_VISIT_TASKS_B
592        SET START_DATE_TIME = l_wo_data_rec.SCHEDULED_START_DATE,
593            END_DATE_TIME = l_wo_data_rec.SCHEDULED_COMPLETION_DATE
594        WHERE visit_task_id = l_wo_data_rec.visit_task_id;
595 
596    END LOOP; --get_wo_data_csr;
597 
598   -- Standard check of p_commit
599   IF Fnd_Api.TO_BOOLEAN(p_commit) THEN
600      COMMIT WORK;
601   END IF;
602 
603   -- Standard call to get message count and if count is 1, get message info
604   Fnd_Msg_Pub.Count_And_Get
605     ( p_count => x_msg_count,
606       p_data  => x_msg_data,
607       p_encoded => Fnd_Api.g_false
608     );
609 
610   IF (l_log_procedure >= l_log_current_level) THEN
611      fnd_log.string(l_log_procedure,
612                     L_DEBUG_KEY ||'.end',
613                     'At the end of PL SQL procedure. RETURN Status = ' || x_return_status);
614   END IF;
615 
616 EXCEPTION
617  WHEN Fnd_Api.G_EXC_ERROR THEN
618    ROLLBACK TO calculate_task_Times_pvt;
619    x_return_status := Fnd_Api.G_RET_STS_ERROR;
620    Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
621                               p_data  => x_msg_data,
622                               p_encoded => Fnd_Api.g_false);
623 
624  WHEN Fnd_Api.G_EXC_UNEXPECTED_ERROR THEN
625    ROLLBACK TO calculate_task_Times_pvt;
626    x_return_status := Fnd_Api.G_RET_STS_UNEXP_ERROR;
627    Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
628                               p_data  => x_msg_data,
629                               p_encoded => Fnd_Api.g_false);
630 
631  WHEN OTHERS THEN
635        Fnd_Msg_Pub.add_exc_msg(p_pkg_name       => G_PKG_NAME,
632     ROLLBACK TO calculate_task_Times_pvt;
633     x_return_status := Fnd_Api.G_RET_STS_UNEXP_ERROR;
634     IF Fnd_Msg_Pub.check_msg_level(Fnd_Msg_Pub.G_MSG_LVL_UNEXP_ERROR) THEN
636                                p_procedure_name => 'Calculate_Task_Times',
637                                p_error_text     => SUBSTR(SQLERRM,1,240));
638     END IF;
639     Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
640                                p_data  => x_msg_data,
641                                p_encoded => Fnd_Api.g_false);
642 END Calculate_Task_Times;
643 
644 --------------------------------------------------------------------
645 --  Procedure name    : Adjust_task_times
646 --  Type              : Private
647 --  Purpose           : Adjusts tasks times and all dependent task times
648 --  Parameters  :
649 --
650 --  Standard OUT Parameters :
651 --   x_return_status        OUT     VARCHAR2     Required,
652 --
653 --  Validate_bef_Times_Derive IN Parameters :
654 --  p_task_id             IN  NUMBER     Required
655 --
656 --  Version :
657 --      Initial Version   1.0
658 --
659 --------------------------------------------------------------------
660 PROCEDURE Adjust_Task_Times
661 (
662     p_api_version        IN         NUMBER,
663     p_init_msg_list      IN         VARCHAR2  := Fnd_Api.G_FALSE,
664     p_commit             IN         VARCHAR2  := Fnd_Api.G_FALSE,
665     p_validation_level   IN         NUMBER    := Fnd_Api.G_VALID_LEVEL_FULL,
666     x_return_status      OUT NOCOPY VARCHAR2,
667     x_msg_count          OUT NOCOPY NUMBER,
668     x_msg_data           OUT NOCOPY VARCHAR2,
669     p_task_id            IN         NUMBER,
670     p_reset_sysdate_flag IN         VARCHAR2 := FND_API.G_FALSE)
671 IS
672 --
673 --Cursor for fetching visit info
674 CURSOR get_visit_data_csr(p_task_id IN NUMBER) IS
675 SELECT v.start_date_time, v.department_id, v.visit_id, v.status_code
676 FROM AHL_VISITS_B v, AHL_VISIT_TASKS_B vt, AHL_DEPARTMENT_SHIFTS dept
677 WHERE v.visit_id = vt.visit_id
678 AND dept.department_id = v.department_id
679 AND vt.visit_task_id = p_task_id;
680 --
681 --Cursor for deriving all the stage start hours
682 CURSOR get_stage_data_csr(p_task_ID IN number)
683 IS
684 SELECT st.stage_id, st.duration
685 --,  sum(st.duration) over(order by st.stage_num) CUMUL_DURATION
686 from ahl_vwp_stages_vl st, ahl_visit_tasks_b vt
687 where st.visit_id = vt.visit_id
688 AND vt.visit_task_id = p_task_id
689 order by st.stage_num;
690 -- Define local variables
691   l_api_version CONSTANT NUMBER := 1.0;
692   L_API_NAME    CONSTANT VARCHAR2(30) := 'Adjust_Task_Times';
693   L_DEBUG_KEY   CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
694   l_visit_id             NUMBER;
695   l_cum_duration         NUMBER :=0;
696 --
697 BEGIN
698 
699    SAVEPOINT Adjust_Task_Times_pvt;
700 
701    IF (l_log_procedure >= l_log_current_level) THEN
702       fnd_log.string(l_log_procedure,
703                      L_DEBUG_KEY ||'.begin',
704                      'At the start of PL SQL procedure. Task Id = ' || p_task_id);
705    END IF;
706 
707    -- Standard call to check for call compatibility
708    IF NOT Fnd_Api.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
709                                      G_PKG_NAME) THEN
710        RAISE Fnd_Api.G_EXC_UNEXPECTED_ERROR;
711    END IF;
712 
713    -- Initialize message list if p_init_msg_list is set to TRUE
714    IF Fnd_Api.To_Boolean(p_init_msg_list) THEN
715       Fnd_Msg_Pub.Initialize;
716    END IF;
717 
718    -- Initialize API RETURN status to success
719    x_return_status := Fnd_Api.G_RET_STS_SUCCESS;
720 
721    --Start Processing here
722    -- 1. Fetch the Visit's deparment id and visit start date
723     OPEN get_visit_data_csr(p_task_id);
724     FETCH get_visit_data_csr INTO G_VISIT_START_DATE, G_VISIT_DEPT_ID, l_visit_id, G_VISIT_STATUS;
725     IF (get_visit_data_csr%NOTFOUND) THEN
726        --Fnd_Message.Set_Name('AHL','AHL_LTP_VISIT_ID_INVALID');
727        --Fnd_Message.Set_Token('VISIT_ID', l_visit_id);
728        --Fnd_Msg_Pub.ADD;
729        CLOSE get_visit_data_csr;
730        RETURN;
731     END IF;
732     CLOSE get_visit_data_csr;
733 
734     --Can not evaluate if either visit start date or visit department is null
735     IF (G_VISIT_START_DATE IS NULL)THEN
736         --Fnd_Message.Set_Name('AHL','AHL_LTP_VISIT_ST_DATE_NULL');
737         --Fnd_Msg_Pub.ADD;
738         RETURN;
739     ELSIF (G_VISIT_DEPT_ID IS NULL) THEN
740         --Fnd_Message.Set_Name('AHL','AHL_LTP_VISIT_DEPT_NULL');
741         --Fnd_Msg_Pub.ADD;
742         RETURN;
743     END IF;
744 
745    --2. Derive the stage time durations
746    FOR l_stage_data_rec in get_stage_data_csr(p_task_id)
747    LOOP
748      G_STAGES_TBL(l_stage_data_rec.stage_id) := l_cum_duration;
749        l_cum_duration := l_cum_duration + l_stage_data_rec.duration;
750    END LOOP; -- get_stage_data_csr;
751 
752    G_RESET_SYSDATE_FLAG := p_reset_sysdate_flag;
753 
754    --3. Call the internal recursive loop on task time adjustment
755    Adjust_Task_Times_Internal(p_task_id);
756 
757    -- Standard check of p_commit
758    IF Fnd_Api.TO_BOOLEAN(p_commit) THEN
759       COMMIT WORK;
763   Fnd_Msg_Pub.Count_And_Get
760    END IF;
761 
762   -- Standard call to get message count and if count is 1, get message info
764     ( p_count => x_msg_count,
765       p_data  => x_msg_data,
766       p_encoded => Fnd_Api.g_false
767     );
768 
769   IF (l_log_procedure >= l_log_current_level) THEN
770      fnd_log.string(l_log_procedure,
771                     L_DEBUG_KEY ||'.end',
772                     'At the end of PL SQL procedure. RETURN Status = ' || x_return_status);
773   END IF;
774 
775 EXCEPTION
776  WHEN Fnd_Api.G_EXC_ERROR THEN
777    ROLLBACK TO Adjust_Task_Times_pvt;
778    x_return_status := Fnd_Api.G_RET_STS_ERROR;
779    Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
780                               p_data  => x_msg_data,
781                               p_encoded => Fnd_Api.g_false);
782 
783  WHEN Fnd_Api.G_EXC_UNEXPECTED_ERROR THEN
784    ROLLBACK TO Adjust_Task_Times_pvt;
785    x_return_status := Fnd_Api.G_RET_STS_UNEXP_ERROR;
786    Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
787                               p_data  => x_msg_data,
788                               p_encoded => Fnd_Api.g_false);
789 
790  WHEN OTHERS THEN
791     ROLLBACK TO Adjust_Task_Times_pvt;
792     x_return_status := Fnd_Api.G_RET_STS_UNEXP_ERROR;
793     IF Fnd_Msg_Pub.check_msg_level(Fnd_Msg_Pub.G_MSG_LVL_UNEXP_ERROR) THEN
794        Fnd_Msg_Pub.add_exc_msg(p_pkg_name       => G_PKG_NAME,
795                                p_procedure_name => 'Adjust_Task_Times',
796                                p_error_text     => SUBSTR(SQLERRM,1,240));
797     END IF;
798     Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
799                                p_data  => x_msg_data,
800                                p_encoded => Fnd_Api.g_false);
801 END Adjust_Task_Times;
802 
803 -----------------------------------------------------------------------------
804 --Function:         Private Method for recursion of task derivation
805 ------------------------------------------------------------------------------
806 
807 PROCEDURE Adjust_Task_Times_Internal(p_task_id IN NUMBER)
808 IS
809 --Fetch basic visit data
810 CURSOR get_task_data_csr(p_task_id IN NUMBER) IS
811 SELECT vt.start_date_time, vt.end_date_time,
812    nvl(vt.department_id, v.department_id),
813    /*B6182718 - sowsubra*/
814    nvl(vt.duration, NVL(Get_task_duration(vt.quantity, routes.route_id), 0)) duration,
815    vt.stage_id,
816    nvl(vt.start_from_hour, 0)
817 FROM AHL_VISIT_TASKS_B vt, AHL_VISITS_B v,
818      ahl_routes_app_v routes, ahl_mr_routes_app_v mr
819 WHERE vt.visit_id = v.visit_id
820 AND routes.route_id (+) = mr.route_id
821 AND mr.mr_route_id (+)= vt.mr_route_id
822 AND  vt.visit_task_id = p_task_id
823 AND vt.task_type_code <> 'SUMMARY'
824 AND (VT.STATUS_CODE IS NULL OR VT.STATUS_CODE <> 'DELETED');
825 --
826 --This cursor uses the technical dependencies and finds the parent task
827 -- that finishes last.
828 CURSOR get_tech_dependency_csr(p_task_id IN NUMBER) IS
829 SELECT max(vt.end_date_time)
830 FROM AHL_VISIT_TASKS_B vt, AHL_TASK_LINKS tl
831 WHERE vt.visit_task_id = tl.parent_task_id
832 AND tl.visit_task_id = p_task_id;
833 --
834 --Cursor which fetches all child technical dependent tasks
835 CURSOR get_child_dependency_csr(p_task_id IN NUMBER) IS
836 SELECT visit_task_id
837 FROM AHL_TASK_LINKS
838 WHERE parent_task_id = p_task_id;
839 --
840 l_old_task_start       DATE;   --Existing task start time
841 l_old_task_end         DATE;   --Existing task end time
842 l_task_dept_id         NUMBER; --Existing task department
843 l_task_duration        NUMBER; --Tasks duration
844 l_task_stage_id        NUMBER; --Tasks stage id
845 l_task_offset          NUMBER; --Number of hours offset based on stage.
846 l_start_date           DATE;   --Newly derived task start date
847 l_end_date             DATE;   --Newly derived task end date
848 l_temp_date            DATE;    --Temporary date for comparison purposes
849 l_child_task_id        NUMBER; --Child task id
850 L_API_VERSION CONSTANT NUMBER        := 1.0;
851 L_API_NAME    CONSTANT VARCHAR2(30)  := 'Adjust_Task_Times_Internal';
852 L_DEBUG_KEY   CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
853 --
854 BEGIN
855     IF (l_log_procedure >= l_log_current_level) THEN
856        fnd_log.string(l_log_procedure,
857                       L_DEBUG_KEY ||'.begin',
858                       'At the start of PL SQL procedure. Visit Task Id = ' || p_task_id);
859     END IF;
860 
861     -- 1. Fetch the task's old info and task related info
862     OPEN get_task_data_csr(p_task_id);
863     FETCH get_task_data_csr INTO l_old_task_start, l_old_task_end, l_task_dept_id,
864                             l_task_duration, l_task_stage_id , l_task_offset;
865 
866     --If it is a valid task
867     IF (get_task_data_csr%FOUND) THEN
868 
869      --2. Check the task stage time value
870      --Get stage offset if stage id is not null
871      IF (l_task_stage_id IS NOT NULL) THEN
872         l_start_date := Compute_Date (G_VISIT_START_DATE, G_VISIT_DEPT_ID, G_STAGES_TBL(l_task_stage_id));
873      ELSE
874         l_start_date := G_VISIT_START_DATE;
875      END IF;
876 
877     --Adjust the start date to the task offset
878     l_start_date := Compute_Date (l_start_date, nvl(l_task_dept_id, G_VISIT_DEPT_ID), l_task_offset);
879 
883      IF (get_tech_dependency_csr%FOUND) THEN
880      --3. Find the max end time of the dependent parents. Adjust based on parent
881      OPEN get_tech_dependency_csr(p_task_id);
882      FETCH get_tech_dependency_csr INTO l_temp_date;
884         l_temp_date := Compute_Date (l_temp_date, nvl(l_task_dept_id, G_VISIT_DEPT_ID),0);
885 
886         --If shift adjusted dependency date is later than stage offset date
887         IF (l_temp_date > l_start_date) THEN
888            l_start_date := l_temp_date;
889         END IF;
890      END IF;
891      CLOSE get_tech_dependency_csr;
892 
893      --Adjust start date for partially released/released tasks to sysdate start date
894      IF ((G_VISIT_STATUS = 'PARTIALLY RELEASED' OR G_VISIT_STATUS = 'RELEASED')
895         AND Fnd_Api.TO_BOOLEAN(G_RESET_SYSDATE_FLAG)) THEN
896         IF (l_start_date < sysdate) THEN
897             l_start_date := COMPUTE_DATE(sysdate, nvl(l_task_dept_id, G_VISIT_DEPT_ID),0);
898         END IF;
899      END IF;
900 
901      --4. Now derive the end date
902      l_end_date := compute_date(l_start_date, l_task_dept_id, l_task_duration);
903      IF (l_log_statement >= l_log_current_level) THEN
904         fnd_log.string(l_log_statement,
905                        L_DEBUG_KEY,
906                        'Start Date = ' || l_start_date ||
907                        '. End Date = ' || l_end_date);
908      END IF;
909 
910      --5. Update the record if it has been changed and call child tasks
911      IF (l_old_task_start IS NULL OR
912          l_old_task_end IS NULL OR
913          l_start_date <> l_old_task_start OR
914          l_end_date <> l_old_task_end) THEN
915 
916        --3d Update the tasks table with the new dates and times.
917        UPDATE AHL_VISIT_TASKS_B
918        SET START_DATE_TIME = l_start_date,
919            END_DATE_TIME = l_end_date
920        WHERE visit_task_id = p_task_id;
921 
922        --If the end date has changed, recursively call the child tasks
923        -- To see if they need to be adjusted. Potentially expensive.
924        IF (l_old_task_end IS NULL OR
925            l_end_date <>  l_old_task_end) THEN
926           OPEN get_child_dependency_csr(p_task_id);
927           LOOP
928             FETCH get_child_dependency_csr INTO l_child_task_id;
929             EXIT WHEN get_child_dependency_csr%NOTFOUND;
930             IF (l_log_statement >= l_log_current_level) THEN
931                fnd_log.string(l_log_statement,
932                               L_DEBUG_KEY,
933                               'Calling child task: ' || l_child_task_id);
934             END IF;
935             Adjust_Task_Times_Internal(l_child_task_id);
936           END LOOP;
937           CLOSE get_child_dependency_csr;
938         END IF;
939       END IF; --start time has changed;
940 
941    END IF; --end found
942    CLOSE get_task_data_csr;
943 
944    IF (l_log_procedure >= l_log_current_level) THEN
945       fnd_log.string(l_log_procedure,
946                      L_DEBUG_KEY ||'.end',
947                      'At the end of PL SQL procedure.');
948    END IF;
949 
950 END Adjust_Task_Times_Internal;
951 -------------------------------------------------------------------
952 --  Procedure name    : Calculate_Task_Times_For_Dept
953 --  Type              : Private
954 --  Function          : Recalculate all Visits for Dept for Task Times
955 --  Parameters  :
956 --
957 --  Standard OUT Parameters :
958 --      x_return_status       OUT     VARCHAR2     Required
959 --      x_msg_count           OUT     NUMBER       Required
960 --      x_msg_data            OUT     VARCHAR2     Required
961 --
962 --  Derive_Visit_Task_Times Parameters:
963 --      p_dept_id            IN      NUMBER       Required
964 --         The dept id which need to have all its visits recalculated.
965 --     Need to be called from concurrent program due to performance issues.
966 --
967 -------------------------------------------------------------------
968 PROCEDURE Calculate_Task_Times_For_Dept
969 (
970     p_api_version      IN         NUMBER,
971     p_init_msg_list    IN         VARCHAR2  := Fnd_Api.G_FALSE,
972     p_commit           IN         VARCHAR2  := Fnd_Api.G_FALSE,
973     p_validation_level IN         NUMBER    := Fnd_Api.G_VALID_LEVEL_FULL,
974     x_return_status    OUT NOCOPY VARCHAR2,
975     x_msg_count        OUT NOCOPY NUMBER,
976     x_msg_data         OUT NOCOPY VARCHAR2,
977     p_dept_id          IN         NUMBER)
978 IS
979 --
980 CURSOR get_all_visits_csr(p_dept_id IN NUMBER) IS
981 SELECT visit_id
982 FROM AHL_VISITS_B
983 WHERE DEPARTMENT_ID = p_dept_id
984 UNION
985 SELECT visit_id
986 FROM AHL_VISIT_TASKS_B
987 WHERE department_id = p_dept_id;
988 --
989 -- Define local variables
990 l_api_version CONSTANT NUMBER := 1.0;
991 L_API_NAME    CONSTANT VARCHAR2(30)  := 'Calculate_Task_Times_For_Dept';
992 L_DEBUG_KEY   CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
993 l_visit_id             NUMBER;
994 --
995 BEGIN
996    SAVEPOINT Calculate_Times_for_dept_pvt;
997 
998    IF (l_log_procedure >= l_log_current_level) THEN
999       fnd_log.string(l_log_procedure,
1000                      L_DEBUG_KEY ||'.begin',
1001                      'At the start of PL SQL procedure. Dept Id = ' || p_dept_id);
1002    END IF;
1003 
1004    -- Standard call to check for call compatibility
1008    END IF;
1005    IF NOT Fnd_Api.Compatible_API_Call(l_api_version, p_api_version, l_api_name,
1006                                      G_PKG_NAME) THEN
1007       RAISE Fnd_Api.G_EXC_UNEXPECTED_ERROR;
1009 
1010    -- Initialize message list if p_init_msg_list is set to TRUE
1011    IF Fnd_Api.To_Boolean(p_init_msg_list) THEN
1012       Fnd_Msg_Pub.Initialize;
1013    END IF;
1014 
1015    -- Initialize API RETURN status to success
1016    x_return_status := Fnd_Api.G_RET_STS_SUCCESS;
1017 
1018    OPEN get_all_visits_csr(p_dept_id);
1019    LOOP
1020       FETCH get_all_visits_csr INTO l_visit_id;
1021       EXIT WHEN get_all_visits_csr%NOTFOUND;
1022 
1023       IF (l_log_statement >= l_log_current_level) THEN
1024          fnd_log.string(l_log_statement,
1025                         L_DEBUG_KEY,
1026                         'Before calling CALCULATE_TASK_TIMES.');
1027       END IF;
1028 
1029       Calculate_Task_Times(p_api_version      => 1.0,
1030                            p_init_msg_list    => Fnd_Api.G_FALSE,
1031                            p_commit           => Fnd_Api.G_FALSE,
1032                            p_validation_level => Fnd_Api.G_VALID_LEVEL_FULL,
1033                            x_return_status    => x_return_status,
1034                            x_msg_count        => x_msg_count,
1035                            x_msg_data         => x_msg_data,
1036                            p_visit_id         => l_visit_id);
1037 
1038       IF (l_log_statement >= l_log_current_level) THEN
1039          fnd_log.string(l_log_statement,
1040                         L_DEBUG_KEY,
1041                         'After calling CALCULATE_TASK_TIMES. RETURN Status = ' ||
1042                         x_return_status);
1043       END IF;
1044 
1045       IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
1046          IF (l_log_statement >= l_log_current_level) THEN
1047             fnd_log.string(l_log_statement,
1048                            L_DEBUG_KEY,
1049                            'Errors from CALCULATE_TASK_TIMES. Message count: ' ||
1050                            x_msg_count || ', message data: ' || x_msg_data);
1051          END IF;
1052          CLOSE get_all_visits_csr;
1053          IF x_return_status = FND_API.G_RET_STS_ERROR THEN
1054             RAISE FND_API.G_EXC_ERROR;
1055          ELSE
1056             RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
1057          END IF;
1058       END IF;
1059    END LOOP;
1060    CLOSE get_all_visits_csr;
1061 
1062    -- Standard check of p_commit
1063    IF Fnd_Api.TO_BOOLEAN(p_commit) THEN
1064       COMMIT WORK;
1065    END IF;
1066 
1067    -- Standard call to get message count and if count is 1, get message info
1068    Fnd_Msg_Pub.Count_And_Get
1069      ( p_count => x_msg_count,
1070        p_data  => x_msg_data,
1071        p_encoded => Fnd_Api.g_false
1072      );
1073 
1074    IF (l_log_procedure >= l_log_current_level) THEN
1075       fnd_log.string(l_log_procedure,
1076                      L_DEBUG_KEY ||'.end',
1077                      'At the end of PL SQL procedure. RETURN Status = ' || x_return_status);
1078    END IF;
1079 
1080 EXCEPTION
1081  WHEN Fnd_Api.G_EXC_ERROR THEN
1082    ROLLBACK TO calculate_Times_for_dept_pvt;
1083    x_return_status := Fnd_Api.G_RET_STS_ERROR;
1084    Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
1085                               p_data  => x_msg_data,
1086                               p_encoded => Fnd_Api.g_false);
1087 
1088  WHEN Fnd_Api.G_EXC_UNEXPECTED_ERROR THEN
1089    ROLLBACK TO calculate_Times_for_dept_pvt;
1090    x_return_status := Fnd_Api.G_RET_STS_UNEXP_ERROR;
1091    Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
1092                               p_data  => x_msg_data,
1093                               p_encoded => Fnd_Api.g_false);
1094 
1095  WHEN OTHERS THEN
1096     ROLLBACK TO calculate_Times_for_dept_pvt;
1097     x_return_status := Fnd_Api.G_RET_STS_UNEXP_ERROR;
1098     IF Fnd_Msg_Pub.check_msg_level(Fnd_Msg_Pub.G_MSG_LVL_UNEXP_ERROR) THEN
1099        Fnd_Msg_Pub.add_exc_msg( p_pkg_name       => G_PKG_NAME,
1100                                 p_procedure_name => 'Calculate_Task_Times_For_Dept',
1101                                 p_error_text     => SUBSTR(SQLERRM,1,240));
1102     END IF;
1103     Fnd_Msg_Pub.count_and_get( p_count => x_msg_count,
1104                                p_data  => x_msg_data,
1105                                p_encoded => Fnd_Api.g_false);
1106 END Calculate_Task_Times_For_Dept;
1107 
1108 ----------------END OF TASK/VISIT SECTION ----------------------------------------
1109 
1110 
1111 ----------------START OF SHIFT DATE TIME SECTION------------------------------------
1112 
1113 -----------------------------------------------------------
1114 --  Function Name:  Compute_Date
1115 --  Type:           Private
1116 --  Function:       Converts date+duration and department into end date/time
1117 --                  Has to be super-efficient as this is called repeatedly.
1118 --                  Performance tuning is top priority for this method.
1119 --                  - no debug code or debug checks.
1120 --                  - code inlined as much as possible, use memory instead of queries
1121 --
1122 --  Compute_Date Parameters:
1123 --      p_start_date  IN  NUMBER  Required
1124 --      The start date of the compute date value
1125 --      p_dept_id     IN  NUMBER  Required
1129 --   RETURNs the department shift adjusted end date of p_start_date+p_duration
1126 --      The department id to calculate the date for
1127 --      p_duration    IN  NUMBER
1128 --      The duration in hours of the tasks offset
1130 --
1131 ---------------------------------------------------------
1132 FUNCTION Compute_Date(
1133     p_start_date date,
1134     p_dept_id number,
1135     p_duration number)
1136   RETURN DATE
1137 IS
1138 --
1139 --Get the number of holiday days that falls under the duration
1140  CURSOR get_holiday_csr(p_department_id IN NUMBER,
1141                          p_start_date IN DATE,
1142                          p_end_date IN DATE) IS
1143     SELECT COUNT(ex.EXCEPTION_DATE)
1144     FROM bom_calendar_exceptions ex, ahl_department_shifts dept
1145     WHERE ex.CALENDAR_CODE = dept.calendar_code
1146     AND EXCEPTION_TYPE = G_HOLIDAY_TYPE
1147     AND dept.department_id = p_department_id
1148     AND ex.exception_date > p_start_date
1149     AND ex.exception_date <= p_end_date;
1150 --
1151 l_start_date         DATE;   -- The p_start_date adjusted for different department.
1152 l_shift_start_date   DATE;   --The date that the shift started.
1153 l_end_date           DATE;   --The end date that is being calculated.
1154 l_end_hour           NUMBER; --Ending hour
1155 l_curr_wday          NUMBER; --current wday
1156 l_num_of_weekends    NUMBER; --Number of weekends (multiple by off days)
1157 l_mod_days           NUMBER; --Modulo workdays for given weekend
1158 l_days_to_add        NUMBER; --Number of holiday days to add.
1159 l_shift_duration     NUMBER; --The shift duration in UOM of day
1160 L_API_NAME  CONSTANT VARCHAR2(30)  := 'Compute_Date';
1161 L_DEBUG_KEY CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
1162 --
1163 BEGIN
1164 
1165   IF (l_log_procedure >= l_log_current_level) THEN
1166      fnd_log.string(l_log_procedure,
1167                     L_DEBUG_KEY ||'.begin',
1168                     'At the start of PL SQL function. Start Date = ' || p_start_date ||
1169                     ', Department Id = ' || p_dept_id || ', Duration = ' || p_duration);
1170   END IF;
1171 
1172   --1. Re-init the department shift time data if not the same
1173   -- as the current cached department
1174   IF (G_CURRENT_DEPT_ID IS NULL or
1175       p_dept_id <> G_CURRENT_DEPT_ID) THEN
1176   Init_Shift_Data(p_dept_id);
1177   G_CURRENT_DEPT_ID := p_dept_id;
1178   END IF;
1179 
1180   --2. Adjust the start date to department shift
1181   l_start_date := p_start_date;
1182 
1183  --Reset the start time to shift start hour if shift starts after current time.
1184    IF (G_SHIFT_END < G_SHIFT_START) THEN
1185      IF (l_start_date < TRUNC(l_start_date) + G_SHIFT_START AND
1186          l_start_date  >= TRUNC(l_start_date) + G_SHIFT_END) THEN
1187          l_start_date := trunc(l_start_date)+ G_SHIFT_START;
1188      END IF;
1189    ELSE
1190       IF (l_start_date < TRUNC(l_start_date) + G_SHIFT_START) THEN
1191           l_start_date := trunc(l_start_date)+ G_SHIFT_START;
1192       ELSIF (l_start_date  >= TRUNC(l_start_date) + G_SHIFT_END) THEN
1193          --Add another day if shift starts tomorrow
1194          l_start_date := trunc(l_start_date)+ 1 + G_SHIFT_START;
1195      END IF;
1196    END IF;
1197 
1198    --If it's an overnight shift and time is before shift ends on the same day,
1199   --the shift started a day earlier
1200   l_shift_start_date :=  get_shift_start_date(l_start_date);
1201 
1202   l_curr_wday := MOD((TRUNC(l_shift_start_date) - G_CAL_START), (G_DAYS_ON + G_DAYS_OFF));
1203 
1204   -- Add to a day_on (basically, passed the weekend)
1205   IF(l_curr_wday +1 > G_DAYS_ON) THEN
1206     l_start_date := TRUNC(l_shift_start_date + (G_DAYS_ON+G_DAYS_OFF-l_curr_wday))+G_SHIFT_START;
1207   END IF;
1208 
1209   --If it's an overnight shift and time is before shift ends on the same day,
1210   --the shift started a day earlier
1211   l_shift_start_date :=  get_shift_start_date(l_start_date);
1212 
1213   -- Not Day Off: Check if holiday and adjust based on holiday
1214   WHILE (Is_Dept_Holiday(l_shift_start_date)) LOOP
1215        l_shift_start_date := l_shift_start_date+1;
1216 
1217        l_curr_wday := MOD((l_shift_start_date - G_CAL_START), (G_DAYS_ON + G_DAYS_OFF));
1218        -- Add to a day_on (basically, passed the weekend)
1219        IF(l_curr_wday +1 > G_DAYS_ON) THEN
1220           l_shift_start_date := l_shift_start_date + (G_DAYS_ON+G_DAYS_OFF-l_curr_wday);
1221        END IF;
1222 
1223        l_start_date := TRUNC(l_shift_start_date) + G_SHIFT_START;
1224   END LOOP;
1225 
1226   IF (p_duration = 0) THEN
1227     -- If duration is 0, RETURN the adjusted start date.
1228     IF (l_log_procedure >= l_log_current_level) THEN
1229        fnd_log.string(l_log_procedure,
1230                       L_DEBUG_KEY ||'.end',
1231                       'At the end of PL SQL function. Start Date = ' || l_start_date);
1232     END IF;
1233     RETURN l_start_date;
1234 
1235   ELSE
1236 
1237     --1. derive shift duration
1238     IF(G_SHIFT_END < G_SHIFT_START) THEN
1239      l_shift_duration := G_SHIFT_END + 1  - G_SHIFT_START;
1240     ELSE
1241      l_shift_duration := G_SHIFT_END - G_SHIFT_START;
1242     END IF;
1243 
1244     --2. Calculate the end date based on the start and duration. p_duration is in hours
1245     -- so must divide duration/24 to get fractions of a day
1249     -- l_start_date equals the shift start date. Then set end date to shift end time
1246     --Both the p_duration/24 and the l_shift_duration are stored as fraction of a day
1247 
1248     --If the border condition of p_duration/shift_duration is an exact number of days and
1250     -- and date to n-1 days from start date
1251     IF (MOD(p_duration/24, l_shift_duration) =0
1252       AND l_start_date-TRUNC(l_start_date)= G_SHIFT_START) THEN
1253       l_end_date := l_start_date + (TRUNC((p_duration/24)/l_shift_duration)-1)+l_shift_duration;
1254     ELSE
1255       l_end_date := l_start_date + TRUNC((p_duration/24)/l_shift_duration) + MOD(p_duration/24, l_shift_duration);
1256     END IF;
1257 
1258     --Get the end hour as fraction of a day
1259     l_end_hour := l_end_date - TRUNC(l_end_date);
1260 
1261     --3. If new end hours goes beyond shift end hour, adjust til next shift
1262     IF (l_end_hour > G_SHIFT_END) THEN
1263       --Adjust end hour into the next shift. So if end_hour is 9pm and shift end is 5pm.
1264       -- Then must add 4 hours to shift start time. (all in fraction of a day)
1265       --This value could be > 1 for overnight shifts
1266        l_end_hour := G_SHIFT_START + (l_end_hour-G_SHIFT_END);
1267 
1268        --Add a day to the end date if the shift ends after start time. (Regular shift)
1269        IF (G_SHIFT_START < G_SHIFT_END) THEN
1270         l_end_date := TRUNC(l_end_date)+1+l_end_hour;
1271        ELSE
1272         l_end_date := TRUNC(l_end_date)+l_end_hour;
1273        END IF;
1274     END IF;
1275 
1276     --Add in the days off
1277     --First calculate number of days off
1278     l_num_of_weekends := TRUNC((get_shift_start_date(l_end_date)-get_shift_start_date(l_start_date))/G_DAYS_ON);
1279 
1280     --This gets the number of extra days over week so that we can check if we get an extra weekend.
1281     l_mod_days :=MOD(get_shift_start_date(l_end_date)- get_shift_start_date(l_start_date), G_DAYS_ON);
1282 
1283     --This is the weekday of the start day.
1284     l_curr_wday := MOD(get_shift_start_date(l_start_date) - G_CAL_START, G_DAYS_ON + G_DAYS_OFF);
1285 
1286     --If the extra days pushes into an extra week, add 1 more weekend.
1287     IF(l_curr_wday+l_mod_days+1>G_DAYS_ON) THEN
1288       l_num_of_weekends := l_num_of_weekends +1;
1289     END IF;
1290     l_end_date := l_end_date + G_DAYS_OFF * l_num_of_weekends;
1291 
1292     --Add in the holidays if not already added
1293     l_days_to_add := 0;
1294     OPEN get_holiday_csr(p_dept_id, get_shift_start_date(l_start_date),
1295                                       get_shift_start_date(l_end_date));
1296     FETCH get_holiday_csr INTO l_days_to_add;
1297     CLOSE get_holiday_csr;
1298 
1299     WHILE (l_days_to_add > 0) LOOP
1300        --Increment and decrement the days
1301        l_end_date := l_end_date +1;
1302        l_days_to_add := l_days_to_add -1;
1303 
1304        --Skip the weekends and the additional holidays
1305        l_curr_wday := MOD(get_shift_start_date(l_end_date)- G_CAL_START, G_DAYS_ON + G_DAYS_OFF);
1306 
1307        IF (l_curr_wday+1 > G_DAYS_ON) THEN
1308           l_days_to_add := l_days_to_add + 1;
1309        ELSIF(Is_Dept_Holiday(get_shift_start_date(l_end_date))) THEN
1310             l_days_to_add := l_days_to_add + 1;
1311        END IF;
1312     END LOOP;
1313 
1314    --RETURN the derived end date.
1315     IF (l_log_procedure >= l_log_current_level) THEN
1316        fnd_log.string(l_log_procedure,
1317                       L_DEBUG_KEY ||'.end',
1318                       'At the end of PL SQL function. End Date = ' || l_end_date);
1319     END IF;
1320     RETURN l_end_date;
1321 
1322   END IF;
1323 
1324 END Compute_Date;
1325 
1326 ------------------------------------------------------------------------------
1327 -- Private function that initializes global variables for computing date/time
1328 ------------------------------------------------------------------------------
1329 PROCEDURE Init_Shift_Data(p_department_id number)
1330 IS
1331 -- Define local cursors
1332 --Find all shift information into the local variables
1333 CURSOR l_shift_info_csr(p_department_id IN NUMBER) IS
1334    SELECT TRUNC(cal.CALENDAR_START_DATE), TRUNC(cal.CALENDAR_END_DATE),
1335           times.FROM_TIME/G_SECS_IN_DAY, times.TO_TIME/G_SECS_IN_DAY,
1336           pattern.DAYS_ON, pattern.DAYS_OFF
1337     FROM bom_shift_times times, bom_workday_patterns pattern,
1338          bom_calendars cal, ahl_department_shifts dept
1339      WHERE dept.calendar_code = times.calendar_code
1340      AND dept.shift_num = times.shift_num
1341      AND pattern.calendar_code = dept.calendar_code
1342      AND pattern.shift_num = dept.shift_num
1343      AND cal.calendar_code = dept.calendar_code
1344      AND dept.department_id = p_department_id;
1345 --
1346 -- Fetch the holidays for the given department
1347   CURSOR l_exceptions_csr(p_department_id IN NUMBER) IS
1348     SELECT ex.EXCEPTION_DATE
1349     FROM bom_calendar_exceptions ex, ahl_department_shifts dept
1350     WHERE ex.CALENDAR_CODE = dept.calendar_code
1351     AND EXCEPTION_TYPE = G_HOLIDAY_TYPE
1352     AND dept.department_id = p_department_id
1353     ORDER BY EXCEPTION_DATE;
1354 --
1355 l_temp_index NUMBER;
1356 l_temp_date  DATE;
1357 L_API_NAME        CONSTANT VARCHAR2(30)  := 'Init_Shift_Data';
1358 L_DEBUG_KEY       CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || L_API_NAME;
1359 --
1360 BEGIN
1361 
1362   IF (l_log_procedure >= l_log_current_level) THEN
1363      fnd_log.string(l_log_procedure,
1364                     L_DEBUG_KEY ||'.begin',
1365                     'At the start of PL SQL procedure. Department Id = ' || p_department_id);
1366   END IF;
1367   -- Get the department informations
1368   OPEN l_shift_info_csr(p_department_id);
1369   FETCH l_shift_info_csr INTO G_CAL_START, G_CAL_END,
1370                              G_SHIFT_START, G_SHIFT_END,
1371                              G_DAYS_ON, G_DAYS_OFF;
1372   IF (l_shift_info_csr%NOTFOUND) THEN
1373     --Fnd_Message.Set_Name('AHL','AHL_LTP_NO_SHIFT_FOR_DEPT');
1374     --Fnd_Message.Set_Token('DEPT_ID', p_department_id);
1375     --Fnd_Msg_Pub.ADD;
1376     CLOSE l_shift_info_csr;
1377     RETURN; --RAISE  Fnd_Api.G_EXC_UNEXPECTED_ERROR;
1378   END IF;
1379   CLOSE l_shift_info_csr;
1380 
1381   -- Get the Exception (Holidays) days
1382   OPEN l_exceptions_csr(p_department_id);
1383   l_temp_index := 1;
1384   LOOP
1385     FETCH l_exceptions_csr INTO l_temp_date;
1386     EXIT WHEN l_exceptions_csr%NOTFOUND;
1387     G_EXCEPTION_DATES_TBL(l_temp_index) := TRUNC(l_temp_date);
1388     l_temp_index := l_temp_index + 1;
1389   END LOOP;
1390   CLOSE l_exceptions_csr;
1391 
1392   IF (l_log_procedure >= l_log_current_level) THEN
1393      fnd_log.string(l_log_procedure,
1394                     L_DEBUG_KEY ||'.end',
1395                     'At the end of PL SQL procedure.');
1396   END IF;
1397 
1398 END Init_shift_Data;
1399 
1400 ----------------------------------------
1401 -- Function to determine if a specific date is a holiday
1402 ----------------------------------------
1403 FUNCTION Is_Dept_Holiday(l_curr_date DATE) RETURN BOOLEAN
1404 IS
1405   l_temp_date DATE := TRUNC(l_curr_date);
1406 BEGIN
1407   IF (G_EXCEPTION_DATES_TBL.COUNT = 0) THEN
1408     RETURN FALSE;
1409   END IF;
1410   --Iterate through the exception dates to make sure it's not a holiday.
1411   FOR i IN G_EXCEPTION_DATES_TBL.FIRST .. G_EXCEPTION_DATES_TBL.LAST LOOP
1412     IF (l_temp_date = G_EXCEPTION_DATES_TBL(i)) THEN
1413       RETURN TRUE;
1414     --Assumes the exception table is sorted by date
1415     ELSIF (l_temp_date < G_EXCEPTION_DATES_TBL(i)) THEN
1416       RETURN FALSE;
1417     END IF;
1418   END LOOP;
1419 
1420   RETURN FALSE;
1421 
1422 END Is_Dept_Holiday;
1423 
1424 --------------------------------------------------------------------
1425 --  Function name    : Get_task_duration
1426 --  Type             : Public
1427 --  Purpose          : To return the total duration of the task
1428 --                     based on the resource requirements defined
1429 --                     at the route/operation level.
1430 --
1431 --  Parameters  :
1432 --       p_vst_task_qty   : Visit task quantity
1433 --       p_route_id       : Route id
1434 --
1435 --  27/Nov/2007       Initial Version Sowmya
1436 --------------------------------------------------------------------
1437 Function Get_task_duration(
1438      p_vst_task_qty   IN   NUMBER,
1439      p_route_id       IN   NUMBER
1440  )
1441 RETURN NUMBER IS
1442 
1443 CURSOR c_get_route_level_res_reqs (c_route_id IN NUMBER) IS
1444   SELECT COST_BASIS_ID, DURATION, RT_OPER_RESOURCE_ID
1445   FROM ahl_rt_oper_resources
1446   WHERE OBJECT_ID = c_route_id
1447   AND NVL(SCHEDULED_TYPE_ID,1) <> 2
1448   AND ASSOCIATION_TYPE_CODE = G_ASSOC_TYPE_ROUTE;
1449 
1450 get_route_level_res_reqs_rec  c_get_route_level_res_reqs%ROWTYPE;
1451 
1452 CURSOR c_get_op_level_res_reqs (c_oprn_id IN NUMBER) IS
1453   SELECT COST_BASIS_ID, DURATION, RT_OPER_RESOURCE_ID
1454   FROM ahl_rt_oper_resources
1455   WHERE OBJECT_ID = c_oprn_id
1456   AND NVL(SCHEDULED_TYPE_ID,1) <> 2
1457   AND ASSOCIATION_TYPE_CODE = G_ASSOC_TYPE_OPERATION;
1458 
1459 get_op_level_res_reqs_rec   c_get_op_level_res_reqs%ROWTYPE;
1460 
1461 CURSOR c_get_oprns (c_route_id IN NUMBER) IS
1462   SELECT RO.operation_id
1463   FROM ahl_operations_vl O, ahl_route_operations RO
1464   WHERE O.operation_id = RO.operation_id
1465   AND RO.route_id = c_route_id
1466   AND O.revision_status_code = 'COMPLETE'
1467   AND O.revision_number IN (SELECT max(revision_number)
1468                             FROM ahl_operations_b_kfv
1469                             WHERE concatenated_segments = O.concatenated_segments
1470                             AND trunc(sysdate) between trunc(start_date_active) and
1471                             trunc(NVL(end_date_active,SYSDATE+1))
1472                             );
1473 
1474 get_oprns_rec   c_get_oprns%ROWTYPE;
1475 
1479   WHERE ROUTE_ID = c_route_id;
1476 CURSOR c_get_route_time_span (c_route_id IN NUMBER) IS
1477   SELECT time_span
1478   FROM ahl_routes_b
1480 
1481 L_API_NAME  CONSTANT VARCHAR2(30)  := 'Get_task_duration';
1482 L_DEBUG_KEY CONSTANT VARCHAR2(100) := 'ahl.plsql.' || G_PKG_NAME || '.' || l_api_name;
1483 l_vst_task_qty       NUMBER := p_vst_task_qty;
1484 max_duration         NUMBER := 0;
1485 ro_duration          NUMBER := 0;
1486 total_opr_duration   NUMBER := 0;
1487 rt_final_duration    NUMBER := 0;
1488 rt_time_span         NUMBER := 0;
1489 
1490 BEGIN
1491   -- Log API entry point
1492   IF (l_log_procedure >= l_log_current_level) THEN
1493      fnd_log.string(l_log_procedure,
1494                     L_DEBUG_KEY ||'.begin',
1495                     'At the start of function. Route Id = ' || p_route_id || ' and Task Quantity = ' || p_vst_task_qty);
1496   END IF;
1497 
1498   IF (p_route_id IS NULL) THEN
1499      IF (l_log_statement >= l_log_current_level)THEN
1500         fnd_log.string(l_log_statement,
1501                        L_DEBUG_KEY,
1502                        'Route Id is null.');
1503      END IF;
1504      RETURN 0;
1505   END IF;
1506 
1507   OPEN c_get_route_time_span (p_route_id);
1508   FETCH c_get_route_time_span INTO rt_time_span;
1509   CLOSE c_get_route_time_span;
1510 
1511   IF (l_log_statement >= l_log_current_level)THEN
1512      fnd_log.string(l_log_statement,
1513                     L_DEBUG_KEY,
1514                     'Route time span = ' || rt_time_span || ', Visit task Quantity = ' || l_vst_task_qty);
1515   END IF;
1516 
1517   IF (nvl(l_vst_task_qty,1) = 1) THEN --serialized items
1518      IF (l_log_statement >= l_log_current_level)THEN
1519         fnd_log.string(l_log_statement,
1520                        L_DEBUG_KEY,
1521                        'serialized item. rt_time_span = ' || rt_time_span);
1522      END IF;
1523      RETURN rt_time_span;
1524   ELSIF (l_vst_task_qty > 1) THEN --non-serialized items
1525     OPEN c_get_route_level_res_reqs (p_route_id);
1526     FETCH c_get_route_level_res_reqs INTO get_route_level_res_reqs_rec;
1527     IF (c_get_route_level_res_reqs%FOUND) THEN --requirements exist at route level
1528       LOOP
1529         EXIT WHEN c_get_route_level_res_reqs%NOTFOUND;
1530         IF (nvl(get_route_level_res_reqs_rec.cost_basis_id,2) = 1) THEN --item based resource
1531             ro_duration := get_route_level_res_reqs_rec.duration * l_vst_task_qty;
1532         ELSE --lot based resource
1533             ro_duration := get_route_level_res_reqs_rec.duration ;
1534         END IF;
1535 
1536         IF (ro_duration > max_duration) THEN
1537             max_duration := ro_duration;
1538         END IF;
1539 
1540         FETCH c_get_route_level_res_reqs INTO get_route_level_res_reqs_rec;
1541       END LOOP;
1542       CLOSE c_get_route_level_res_reqs;
1543       rt_final_duration := max_duration;
1544     ELSE --requirements exist at operation level
1545       CLOSE c_get_route_level_res_reqs;
1546       OPEN c_get_oprns (p_route_id);
1547       LOOP
1548         FETCH c_get_oprns INTO get_oprns_rec;
1549         EXIT WHEN c_get_oprns%NOTFOUND;
1550 
1551         max_duration := 0;
1552 
1553         OPEN c_get_op_level_res_reqs (get_oprns_rec.operation_id);
1554         LOOP
1555           FETCH c_get_op_level_res_reqs INTO get_op_level_res_reqs_Rec;
1556           EXIT WHEN c_get_op_level_res_reqs%NOTFOUND;
1557           IF (nvl(get_op_level_res_reqs_Rec.cost_basis_id,2) = 1) THEN --item based resource
1558               ro_duration := get_op_level_res_reqs_Rec.duration * l_vst_task_qty;
1559           ELSE --lot based resource
1560               ro_duration := get_op_level_res_reqs_Rec.duration ;
1561           END IF;
1562 
1563           IF (ro_duration > max_duration) THEN
1564               max_duration := ro_duration;
1565           END IF;
1566         END LOOP;
1567         CLOSE c_get_op_level_res_reqs;
1568         /*max durations of all operations are summed up since they are assumed to be performed sequentially.*/
1569         total_opr_duration := total_opr_duration + max_duration;
1570       END LOOP;
1571       CLOSE c_get_oprns;
1572 
1573       rt_final_duration := total_opr_duration;
1574     END IF; --requirements exist at route level
1575 
1576     IF (l_log_statement >= l_log_current_level)THEN
1577        fnd_log.string(l_log_statement,
1578           L_DEBUG_KEY,
1579           'Route Duration - ' ||rt_final_duration);
1580     END IF;
1581 
1582     IF (rt_time_span >= rt_final_duration) THEN
1583        IF (l_log_procedure >= l_log_current_level) THEN
1584           fnd_log.string(l_log_procedure,
1585                          L_DEBUG_KEY ||'.end',
1586                          'At the end of PL SQL function. non-serialized item. rt_time_span = ' || rt_time_span);
1587        END IF;
1588        RETURN rt_time_span;
1589     ELSE
1590        IF (l_log_procedure >= l_log_current_level) THEN
1591           fnd_log.string(l_log_procedure,
1592                          L_DEBUG_KEY ||'.end',
1593                          'At the end of PL SQL function. non-serialized item. rt_final_duration = ' || rt_final_duration);
1594        END IF;
1595        RETURN rt_final_duration;
1596     END IF;
1597   END IF; --non-serialized items
1598 
1599 END Get_task_duration;
1600 
1601 END AHL_VWP_TIMES_PVT;