1 package body JTF_AGENDA_CALCULATIONS as
2 /*$Header: JTFAGCAB.pls 120.2 2005/09/01 22:09:44 pseo ship $*/
3
4 -- get attributes of the task assignment prior to the current
5 -- task assignment, dependant on the type of the current task, that is
6 -- for an arrival virtual task all tasks in the shift, for a departure
7 -- nothing (because this is the first 'task' in the shift), and for a
8 -- real task all tasks before the current task including the departure
9 procedure get_prior_task_assignment
10 ( p_res_id in number
11 , p_res_type in varchar2
12 , p_shift_start in date
13 , p_shift_end in date
14 , p_sched_start in date
15 , p_ta_id in number
16 , p_task_type_id in number
17 , x_prior_ta_id out NOCOPY number
18 , x_prior_sched_end out NOCOPY date
19 , x_prior_found out NOCOPY boolean
20 )
21 is
22 -- get tasks for this resource in this shift which are before current
23 -- task or is the departure virtual task
24 cursor c_prior
25 ( p_res_id number
26 , p_res_type varchar2
27 , p_shift_start date
28 , p_shift_end date
29 , p_sched_start date
30 , p_ta_id number
31 )
32 is
33 select task_assignment_id
34 , scheduled_end_date
35 from jtf_agenda_ta_v
36 where resource_id = p_res_id
37 and resource_type_code = p_res_type
38 and shift_start = p_shift_start
39 and shift_end = p_shift_end
40 and ( task_type_id = 20 -- departure task
41 or ( task_type_id not in (20,21) -- real tasks
42 and ( scheduled_start_date < p_sched_start
43 or ( scheduled_start_date = p_sched_start
44 and task_assignment_id < p_ta_id ) ) ) )
45 order by decode(task_type_id,20,1,0) -- departure task last
46 , scheduled_start_date desc
47 , task_assignment_id desc;
48
49 -- get all tasks for this resource in this shift but without arrival
50 cursor c_prior_all
51 ( p_res_id number
52 , p_res_type varchar2
53 , p_shift_start date
54 , p_shift_end date
55 )
56 is
57 select task_assignment_id
58 , scheduled_end_date
59 from jtf_agenda_ta_v
60 where resource_id = p_res_id
61 and resource_type_code = p_res_type
62 and shift_start = p_shift_start
63 and shift_end = p_shift_end
64 and task_type_id <> 21 -- not arrival task
65 order by decode(task_type_id,20,1,0) -- departure task last
66 , scheduled_start_date desc
67 , task_assignment_id desc;
68
69 begin
70 x_prior_ta_id := null;
71 x_prior_sched_end := null;
72 x_prior_found := false;
73
74 -- real task
75 if p_task_type_id not in (20,21)
76 then
77 open c_prior
78 ( p_res_id
79 , p_res_type
80 , p_shift_start
81 , p_shift_end
82 , p_sched_start
83 , p_ta_id
84 );
85 fetch c_prior
86 into x_prior_ta_id
87 , x_prior_sched_end;
88
89 if c_prior%found
90 then
91 x_prior_found := true;
92 end if;
93 close c_prior;
94
95 -- virtual arrival task
96 elsif p_task_type_id = 21
97 then
98 open c_prior_all
99 ( p_res_id
100 , p_res_type
101 , p_shift_start
102 , p_shift_end
103 );
104 fetch c_prior_all
105 into x_prior_ta_id
106 , x_prior_sched_end;
107
108 if c_prior_all%found
109 then
110 x_prior_found := true;
111 end if;
112 close c_prior_all;
113 end if;
114 end get_prior_task_assignment;
115
116 function predict_time_difference
117 (
118 p_task_assignment_id number
119 )
120 return number
121 is
122 l_diff number := 0;
123 l_sched_start date := null;
124 l_sched_end date := null;
125 l_actua_start date := null;
126 l_actua_end date := null;
127 l_sched_travel number := 0;
128 l_res_id number := null;
129 l_res_type varchar2(30) := null;
130 l_shift_start date := null;
131 l_shift_end date := null;
132 l_prior_ta_id number := null;
133 l_prior_sched_end date := null;
134 l_min_start date := null;
135 l_free number := 0;
136 l_bmode varchar2(30) := null;
137 l_plan_start date := null;
138 l_plan_end date := null;
139 l_task_type_id number := null;
140 l_prior_found boolean := false;
141
142 cursor c_this ( p_ta_id number )
143 is
144 select scheduled_start_date
145 , scheduled_end_date
146 , actual_start_date
147 , actual_end_date
148 , sched_travel_duration
149 , resource_id
150 , resource_type_code
151 , shift_start
152 , shift_end
153 , bound_mode_code
154 , planned_start_date
155 , planned_end_date
156 , task_type_id
157 from jtf_agenda_ta_v
158 where task_assignment_id = p_ta_id;
159
160 begin
161 open c_this ( p_task_assignment_id );
162 fetch c_this
163 into l_sched_start
164 , l_sched_end
165 , l_actua_start
166 , l_actua_end
167 , l_sched_travel
168 , l_res_id
169 , l_res_type
170 , l_shift_start
171 , l_shift_end
172 , l_bmode
173 , l_plan_start
174 , l_plan_end
175 , l_task_type_id;
176
177 if c_this%found
178 then
179 -- validate shift
180 if l_shift_start is null
181 or l_shift_end is null
182 or l_shift_end < l_shift_start
183 then
184 -- exit
185 return 0;
186 end if;
187
188 -- compute difference
189 if l_actua_end is not null
190 then
191 l_diff := l_actua_end - l_sched_end;
192
193 elsif l_actua_start is not null
194 then
195 l_diff := l_actua_start - l_sched_start;
196 if sysdate > l_sched_end + l_diff
197 then
198 l_diff := sysdate - l_sched_end;
199 end if;
200
201 -- no actual dates are found, get the previous task in this trip to find
202 -- an actual date
203 else
204 get_prior_task_assignment ( l_res_id
205 , l_res_type
206 , l_shift_start
207 , l_shift_end
208 , l_sched_start
209 , p_task_assignment_id
210 , l_task_type_id
211 , l_prior_ta_id
212 , l_prior_sched_end
213 , l_prior_found );
214
215 if l_prior_found
216 then
217 -- this is a recursive function!
218 l_diff := predict_time_difference ( l_prior_ta_id );
219
220 -- no previous task found, this is the first task of the trip, take
221 -- system date into account
222 else
223 if sysdate > l_sched_start
224 then
225 l_diff := sysdate - l_sched_start;
226 end if;
227 end if;
228
229 -- validate travel time attributes
230 if l_sched_travel is null
231 or l_sched_travel < 0
232 then
233 l_sched_travel := 0;
234 end if;
235
236 -- compute minimal time resource has to leave in order to arrive
237 -- in time to start task (unit of measurement is minute)
238 l_min_start := l_sched_start - ( l_sched_travel / 1440 );
239
240 -- correct difference by amount of not scheduled, free time
241 l_free := l_min_start - nvl( l_prior_sched_end, l_shift_start );
242 l_diff := l_diff - l_free;
243
244 -- correct for time bounds
245 if l_bmode = 'BTS'
246 and l_plan_end >= l_plan_start
247 -- makes no sense for virtual tasks departure and arrival
248 and l_task_type_id not in (20,21)
249 then
250 if ( l_sched_start + l_diff ) < l_plan_start
251 then
252 l_diff := l_plan_start - l_sched_start;
253 end if;
254 end if;
255 end if;
256 end if;
257 close c_this;
258
259 return l_diff;
260 end predict_time_difference;
261
262 function set_sequence_flag
263 (
264 p_task_assignment_id number
265 )
266 return varchar2
267 is
268 l_flag varchar2(1) := 'N';
269 l_res_id number := null;
270 l_res_type varchar2(30) := null;
271 l_shift_start date := null;
272 l_shift_end date := null;
273 l_sched_start date := null;
274
275 cursor c_this ( p_ta_id number )
276 is
277 select scheduled_start_date
278 , resource_id
279 , resource_type_code
280 , shift_start
281 , shift_end
282 from jtf_agenda_ta_v
283 where task_assignment_id = p_ta_id
284 and actual_start_date is null
285 and actual_end_date is null;
286
287 cursor c_next
288 ( p_res_id number
289 , p_res_type varchar2
290 , p_shift_start date
291 , p_shift_end date
292 , p_sched_start date
293 , p_ta_id number
294 )
295 is
296 select 'Y'
297 from jtf_agenda_ta_v
298 where resource_id = p_res_id
299 and resource_type_code = p_res_type
300 and shift_start = p_shift_start
301 and shift_end = p_shift_end
302 and ( scheduled_start_date > p_sched_start
303 or ( scheduled_start_date = p_sched_start
304 and task_assignment_id > p_ta_id ) )
305 and nvl(actual_start_date,actual_end_date) is not null;
306
307 begin
308 open c_this ( p_task_assignment_id );
309 fetch c_this
310 into l_sched_start
311 , l_res_id
312 , l_res_type
313 , l_shift_start
314 , l_shift_end;
315
316 if c_this%found
317 then
318 open c_next
319 ( l_res_id
320 , l_res_type
321 , l_shift_start
322 , l_shift_end
323 , l_sched_start
324 , p_task_assignment_id
325 );
326 fetch c_next
327 into l_flag;
328
329 close c_next;
330 end if;
331 close c_this;
332
333 return l_flag;
334 end set_sequence_flag;
335
336 function get_progress_status
337 ( p_resource_id number
338 , p_resource_type_code varchar2
339 , p_date date
340 )
341 return number
342 is
343 -- get all escalated tasks in current trip
344 cursor c_esc
345 ( p_res_id number
346 , p_res_type varchar2
347 , p_date date
348 )
349 is
350 select ''
351 from jtf_agenda_v
352 where resource_id = p_res_id
353 and resource_type_code = p_res_type
354 and p_date between shift_start and shift_end
355 and escalation_flag = 'Y';
356
357 cursor c_max
358 (
359 p_res_id number
360 , p_res_type varchar2
361 , p_date date
362 )
363 is
364 select max(predicted_end_date)
365 , max(shift_end)
366 from jtf_agenda_v
367 where resource_id = p_res_id
368 and resource_type_code = p_res_type
369 and p_date between shift_start and shift_end
370 and task_type_id not in (20,21);
371
372 l_chk varchar2(1);
373 l_max_pred_end date := null;
374 l_shift_end date := null;
375 l_dif number := null;
376 l_uom constant number := 1440; /* unit of measurement is minutes */
377 l_margin number;
378
379 begin
380 /* see if any task in current trip is escalated */
381 open c_esc ( p_resource_id
382 , p_resource_type_code
383 , p_date );
384 fetch c_esc into l_chk;
385 if c_esc%found
386 then
387 close c_esc;
388 return 4; /* escalated */
389 end if;
390 close c_esc;
391
392 /* get highest predicted end date within trip */
393 open c_max
394 ( p_resource_id
395 , p_resource_type_code
396 , p_date
397 );
398 fetch c_max
399 into l_max_pred_end
400 , l_shift_end;
401
402 /* calculate difference with shift end */
403 l_dif := ( l_shift_end - l_max_pred_end ) * l_uom;
404
405 if c_max%found
406 and l_dif is not null
407 then
408 /* get margin profile option */
409 l_margin := to_number( fnd_profile.value(
410 'CSF_RESOURCE_PROGRESS_STATUS') );
411 if l_margin is null
412 or sqlcode <> 0
413 then
414 l_margin := 60; /* default value (60 minutes) */
415 end if;
416
417 close c_max;
418
419 if l_dif < ( l_margin * -1 )
420 then
421 return 3; /* behind schedule */
422 elsif l_dif > l_margin
423 then
424 return 1; /* ahead of schedule */
425 end if;
426 return 2; /* on schedule */
427 end if;
428 close c_max;
429
430 return 0; /* unknown */
431 end get_progress_status;
432
433 function get_assignment_status
434 (
435 p_resource_id number
436 , p_resource_type_code varchar2
437 )
438 return number
439 is
440 cursor c_currsta
441 is
442 select assignment_status_id
443 from jtf_agenda_ta_v
444 where resource_id = p_resource_id
445 and resource_type_code = p_resource_type_code
446 and task_type_id not in (20,21)
447 and ( actual_start_date =
448 ( select max( actual_start_date )
449 from jtf_agenda_ta_v
450 where resource_id = p_resource_id
451 and resource_type_code = p_resource_type_code
452 and task_type_id not in (20,21) )
453 or actual_start_date is null )
454 order by scheduled_start_date
455 , task_assignment_id;
456
457 l_status_id number;
458 begin
459 open c_currsta;
460 fetch c_currsta into l_status_id;
461 if c_currsta%notfound
462 then
463 l_status_id := null;
464 end if;
465 close c_currsta;
466
467 return l_status_id;
468 end get_assignment_status;
469
470 function get_status_name
471 (
472 p_status_id number
473 )
474 return varchar2
475 is
476 cursor c_name
477 is
478 select name
479 from jtf_task_statuses_vl
480 where task_status_id = p_status_id;
481 l_name varchar2(30);
482 begin
483 open c_name;
484 fetch c_name into l_name;
485 if c_name%notfound
486 then
487 l_name := null;
488 end if;
489 close c_name;
490
491 return l_name;
492 end get_status_name;
493
494 function get_current_task
495 (
496 p_resource_id number
497 , p_resource_type_code varchar2
498 )
499 return number
500 is
501 cursor c_currtask
502 is
503 select task_id
504 from jtf_agenda_ta_v
505 where resource_id = p_resource_id
506 and resource_type_code = p_resource_type_code
507 and task_type_id not in (20,21)
508 and ( actual_start_date =
509 ( select max( actual_start_date )
510 from jtf_agenda_ta_v
511 where resource_id = p_resource_id
512 and resource_type_code = p_resource_type_code
513 and task_type_id not in (20,21) )
514 or actual_start_date is null )
515 order by scheduled_start_date
516 , task_assignment_id;
517
518 l_task_id number;
519 begin
520 open c_currtask;
521 fetch c_currtask into l_task_id;
522 if c_currtask%notfound
523 then
524 l_task_id := null;
525 end if;
526 close c_currtask;
527
528 return l_task_id;
529 end get_current_task;
530
531 FUNCTION get_shift_start
532 ( p_shift_construct_id NUMBER DEFAULT NULL
533 , p_resource_id NUMBER DEFAULT NULL
534 , p_resource_type_code VARCHAR2 DEFAULT NULL
535 , p_date DATE DEFAULT NULL
536 )
537 RETURN DATE
538 IS
539 l_start DATE;
540 l_time NUMBER;
541 l_return_status VARCHAR2(1);
542 l_msg_count NUMBER;
543 l_msg_data VARCHAR2(2000);
544 l_shift JTF_CALENDAR_PUB.SHIFT_TBL_TYPE;
545
546 CURSOR c_shift_construct IS
547 SELECT begin_time
548 FROM jtf_cal_shift_constructs
549 WHERE shift_construct_id = p_shift_construct_id;
550
551 r_shift_construct c_shift_construct%ROWTYPE;
552
553 BEGIN
554 OPEN c_shift_construct;
555 FETCH c_shift_construct INTO r_shift_construct;
556 IF c_shift_construct%FOUND THEN
557 l_time := r_shift_construct.begin_time -
558 TRUNC(r_shift_construct.begin_time);
559 l_start := TRUNC(p_date) + l_time;
560 END IF;
561 CLOSE c_shift_construct;
562
563 -- No shift start was found using shift_construct_id
564 IF l_start IS NULL THEN
565 JTF_CALENDAR_PUB.Get_Resource_Shifts
566 ( p_api_version => 1.0 ,
567 p_resource_id => p_resource_id ,
568 p_resource_type => p_resource_type_code ,
569 p_start_date => p_date ,
570 p_end_date => p_date ,
571 x_return_status => l_return_status ,
572 x_msg_count => l_msg_count ,
573 x_msg_data => l_msg_data ,
574 x_shift => l_shift
575 );
576
577 IF l_return_status = FND_API.G_RET_STS_SUCCESS THEN
578 l_start := TO_DATE(l_shift(1).start_time, 'hh24:mi');
579 l_time := l_start - TRUNC(l_start);
580 l_start := TRUNC(p_date) + l_time;
581 END IF;
582 END IF;
583
584 -- Temporary if Calendar DB objects are invalid
585 -- l_start := TRUNC(p_date) + ( 8 / 24 );
586 -- IF l_start > p_date THEN
587 -- l_start := l_start - 1;
588 -- END IF;
589
590 RETURN l_start;
591 END get_shift_start;
592
593 FUNCTION get_shift_end
594 ( p_shift_construct_id NUMBER DEFAULT NULL
595 , p_resource_id NUMBER DEFAULT NULL
596 , p_resource_type_code VARCHAR2 DEFAULT NULL
597 , p_date DATE DEFAULT NULL
598 )
599 RETURN DATE
600 IS
601 l_end DATE;
602 l_time NUMBER;
603 l_return_status VARCHAR2(1);
604 l_msg_count NUMBER;
605 l_msg_data VARCHAR2(2000);
606
607 l_shift JTF_CALENDAR_PUB.SHIFT_TBL_TYPE;
608
609 CURSOR c_shift_construct IS
610 SELECT end_time
611 FROM jtf_cal_shift_constructs
612 WHERE shift_construct_id = p_shift_construct_id;
613
614 r_shift_construct c_shift_construct%ROWTYPE;
615
616 BEGIN
617 OPEN c_shift_construct;
618 FETCH c_shift_construct INTO r_shift_construct;
619 IF c_shift_construct%FOUND THEN
620 l_time := r_shift_construct.end_time - TRUNC(r_shift_construct.end_time);
621 l_end := TRUNC(p_date) + l_time;
622 END IF;
623 CLOSE c_shift_construct;
624
625 -- No shift end was found using shift_construct_id
626 IF l_end IS NULL THEN
627 JTF_CALENDAR_PUB.Get_Resource_Shifts
628 ( p_api_version => 1.0 ,
629 p_resource_id => p_resource_id ,
630 p_resource_type => p_resource_type_code ,
631 p_start_date => p_date ,
632 p_end_date => p_date ,
633 x_return_status => l_return_status ,
634 x_msg_count => l_msg_count ,
635 x_msg_data => l_msg_data ,
636 x_shift => l_shift
637 );
638
639 IF l_return_status = FND_API.G_RET_STS_SUCCESS THEN
640 l_end := TO_DATE(l_shift(1).end_time, 'hh24:mi');
641 l_time := l_end - TRUNC(l_end);
642 l_end := TRUNC(p_date) + l_time;
643 END IF;
644 END IF;
645
646 -- Temporary if Calendar DB objects are invalid
647 -- l_end := ( get_shift_start( p_shift_construct_id,
648 -- p_resource_id,
649 -- p_resource_type_code,
650 -- p_date
651 -- ) + ( 9 / 24 ) );
652
653 RETURN l_end;
654 END get_shift_end;
655
656 FUNCTION set_escalation_flag
657 (
658 p_task_id NUMBER
659 )
660 RETURN VARCHAR2
661 IS
662 l_return_value VARCHAR2(1) := 'N';
663 l_object_type_code VARCHAR2(30) := 'TASK';
664 l_object_id NUMBER := p_task_id;
665
666 CURSOR c_esc IS
667 SELECT NULL
668 FROM jtf_tasks_b t,
669 jtf_task_references_vl r,
670 jtf_ec_statuses_vl s
671 WHERE t.task_id = r.task_id
672 AND t.task_type_id = 22
673 AND t.task_status_id = s.task_status_id
674 AND (s.closed_flag = 'N'
675 OR s.closed_flag is null)
676 AND (s.completed_flag = 'N'
677 OR s.completed_flag is null)
678 AND (s.cancelled_flag = 'N'
679 OR s.cancelled_flag is null)
680 AND r.reference_code = 'ESC'
681 AND r.object_type_code = l_object_type_code
682 AND r.object_id = l_object_id;
683
684 CURSOR c_tsk IS
685 SELECT t.source_object_type_code,
686 t.source_object_id
687 FROM jtf_tasks_b t,
688 jtf_task_statuses_vl s
689 WHERE t.task_id = p_task_id
690 AND t.task_status_id = s.task_status_id
691 AND (s.closed_flag = 'N'
692 OR s.closed_flag is null)
693 AND (s.completed_flag = 'N'
694 OR s.completed_flag is null)
695 AND (s.cancelled_flag = 'N'
696 OR s.cancelled_flag is null);
697 r_esc c_esc%ROWTYPE;
698 r_tsk c_tsk%ROWTYPE;
699 BEGIN
700 -- Check if Task is escalated. Ignore completed/cancelled status
701 -- of Task.
702 OPEN c_esc;
703 FETCH c_esc INTO r_esc;
704 IF c_esc%FOUND THEN
705 l_return_value := 'Y';
706 END IF;
707
708 CLOSE c_esc;
709
710 -- If Task is not escalated then check if Service Request is
711 -- escalated. Only Tasks which are not completed/cancelled can be
712 -- escalated if the Service Request is escalated
713 IF l_return_value = 'N' THEN
714 OPEN c_tsk;
715 FETCH c_tsk INTO r_tsk;
716 IF c_tsk%FOUND THEN
717 l_object_type_code := r_tsk.source_object_type_code;
718 l_object_id := r_tsk.source_object_id;
719
720 OPEN c_esc;
721 FETCH c_esc INTO r_esc;
722 IF c_esc%FOUND THEN
723 l_return_value := 'Y';
724 END IF;
725 CLOSE c_esc;
726 END IF;
727 CLOSE c_tsk;
728 END IF;
729
730 RETURN l_return_value;
731 END set_escalation_flag;
732
733 end JTF_AGENDA_CALCULATIONS;