DBA Data[Home] [Help]

PACKAGE BODY: APPS.WIP_INFRESSCHED_GRP

Source


1 package body wip_infResSched_grp as
2 /* $Header: wipinrsb.pls 120.13.12020000.6 2013/03/20 12:17:26 kswarna ship $ */
3 
4   --package constants
5   g_dateCursorLen CONSTANT NUMBER := 10;--must be greater than or equal to 1
6   g_precision CONSTANT NUMBER := 6;
7   g_forward CONSTANT NUMBER := 0;
8   g_backward CONSTANT NUMBER := 1;
9   g_logDateFmt CONSTANT VARCHAR2(30) := 'HH24:MI:SS MM/DD/YYYY';
10   -- Bug #13388579 @start
11   g_reset_date NUMBER :=0;
12   is_backWardSch boolean :=false;
13   -- Bug #13388579 @End
14   --private types
15   type op_rec_t is record(startDate date,
16                           endDate date,
17                           priorsExist boolean,
18                           nextsExist boolean,
19                           resStartIdx number,
20                           resEndIdx number);
21 
22   type op_tbl_t is table of op_rec_t index by binary_integer;
23 
24   /* fix bug 7027946 */
25   type shift_recTbl_t is record(shiftNum num_tbl_t,
26                                 startDate date_tbl_t,
27                                 endDate date_tbl_t);
28   /* end of fix bug 7027946 */
29 
30   procedure buildOpStructure(p_resTbls in op_res_rectbl_t,
31                              p_anchorDate in DATE,
32                              x_opTbl out nocopy op_tbl_t);
33 
34   procedure findMdPntRes(p_resTbls IN OP_RES_RECTBL_T,
35                          p_opSeqNum NUMBER,
36                          p_resSeqNum NUMBER,
37                          p_isMdPntFwd boolean,
38                          x_midPntFwdIdx OUT NOCOPY NUMBER,
39                          x_midPntBkwdIdx OUT NOCOPY NUMBER);
40 
41   --schedules prior resources when forward scheduling, or resource is on or after the midpoint op when midpoint scheduling
42   procedure schedulePriorResources(p_orgID IN NUMBER,
43                                    p_repLineID NUMBER,
44                                    p_opTbl in op_tbl_t,
45                                    x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
46                                    x_returnStatus OUT NOCOPY VARCHAR2);
47 
48   --schedules next resources when backward scheduling, or resource is on or before the midpoint op when midpoint scheduling
49   procedure scheduleNextResources(p_orgID IN NUMBER,
50                                   p_repLineID NUMBER,
51                                   p_opTbl in op_tbl_t,
52                                   x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
53                                   x_returnStatus OUT NOCOPY VARCHAR2);
54 
55 
56 
57   --schedules 'no' resources
58   procedure scheduleNoResources(p_anchorDate IN DATE,
59                                 x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
60                                 x_returnStatus OUT NOCOPY VARCHAR2);
61 
62   --when forward scheduling, this function will reschedule the entire job
63   --if one or more prior resources are initially scheduled to start before the start date passed in.
64   procedure resolvePriorExceptions(p_orgID IN NUMBER,
65                                    p_repLineID  IN NUMBER,
66                                    p_startDate IN DATE,
67                                    x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
68                                    x_returnStatus OUT NOCOPY VARCHAR2);
69 
70   /* fix bug 7027946 */
71   procedure capacityExceptions(p_resID     IN NUMBER,
72                                p_deptID    IN NUMBER,
73                                p_orgID     IN NUMBER,
74                                x_shifts IN OUT NOCOPY shift_recTbl_t,
75           x_returnStatus OUT NOCOPY VARCHAR2);
76   /* end of fix bug 7027946 */
77 
78   --when backward scheduling, this function will reschedule the entire job
79   --if one or more next resources are initially scheduled to end after the end date passed in.
80   procedure resolveNextExceptions(p_orgID IN NUMBER,
81                                   p_repLineID  IN NUMBER,
82                                   p_endDate IN DATE,
83                                   x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
84                                   x_returnStatus OUT NOCOPY VARCHAR2);
85 
86   procedure forwardSchedule(p_orgID        in number,
87                             p_repLineID    in NUMBER := null,
88                             p_startDate    in DATE,
89                             p_range        in num_tbl_t,
90                             p_schedFlag    in number,
91                             x_resTbls      in out NOCOPY OP_RES_RECTBL_T,
92                             x_returnStatus OUT NOCOPY VARCHAR2);
93 
94   procedure backwardSchedule(p_orgID        in number,
95                              p_repLineID    in NUMBER := null,
96                              p_endDate      in DATE,
97                              p_range        in num_tbl_t,
98                              p_schedFlag    in number,
99                              x_resTbls      in out NOCOPY OP_RES_RECTBL_T,
100                              x_returnStatus OUT NOCOPY VARCHAR2);
101 
102 
103   --removes priors from simultaneous batch returns last index of batch
104   function cleanBatch(p_startIdx NUMBER,
105                       x_resTbls IN OUT NOCOPY op_res_rectbl_t) return number is
106   begin
107     for i in p_startIdx..x_resTbls.resID.count loop
108       if(x_resTbls.opSeqNum(i) = x_resTbls.opSeqNum(p_startIdx) and
109          x_resTbls.schedSeqNum(i) = x_resTbls.schedSeqNum(p_startIdx)) then
110         if(x_resTbls.schedFlag(i) = wip_constants.sched_prior) then
111           x_resTbls.schedFlag(i) := wip_constants.sched_yes;
112         end if;
113       else
114         return i;
115       end if;
116     end loop;
117     return x_resTbls.resID.count;
118   end cleanBatch;
119 
120   --checks if priors co-exist with other schedule methods in simultaneous batch if so, it changes the priors to scheduled yes.
121   procedure removePriorsFromBatch(x_resTbls IN OUT NOCOPY op_res_rectbl_t) is
122     i number := 2;
123     l_curOp NUMBER := x_resTbls.opSeqNum(1);
124     l_curSch NUMBER := x_resTbls.schedSeqNum(1);
125     l_priorExists boolean := x_resTbls.schedFlag(1) = wip_constants.sched_prior;
126     l_otherExists boolean := x_resTbls.schedFlag(1) in (wip_constants.sched_yes, wip_constants.sched_next);
127     l_startIdx NUMBER := 1;
128     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
129     l_retStatus VARCHAR2(1);
130     l_params wip_logger.param_tbl_t;
131   begin
132     if(l_logLevel <= wip_constants.trace_logging) then
133       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.removePriorsFromBatch',
134                             p_params => l_params,
135                             x_returnStatus => l_retStatus);
136     end if;
137     while(i <= x_resTbls.resID.count) loop
138       --in same batch as the previous res
139       if(x_resTbls.schedSeqNum(i) = l_curSch and
140          x_resTbls.opSeqNum(i) = l_curOp) then
141         l_priorExists := l_priorExists or x_resTbls.schedFlag(i) = wip_constants.sched_prior;
142         l_otherExists := l_otherExists or x_resTbls.schedFlag(i) in (wip_constants.sched_yes, wip_constants.sched_next);
143         if(l_priorExists and l_otherExists) then
144           i := cleanBatch(p_startIdx => l_startIdx, x_resTbls => x_resTbls);
145         end if;
146 
147       --new batch
148       else
149         l_curOp := x_resTbls.opSeqNum(i);
150         l_curSch := x_resTbls.schedSeqNum(i);
151         l_startIdx := i;
152         l_priorExists := x_resTbls.schedFlag(i) = wip_constants.sched_prior;
153         l_otherExists := x_resTbls.schedFlag(i) in (wip_constants.sched_yes, wip_constants.sched_next);
154       end if;
155       i := i + 1;
156     end loop;
157     if (l_logLevel <= wip_constants.trace_logging) then
158       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.removePriorsFromBatch',
159                            p_procReturnStatus => null,
160                            p_msg              => 'success',
161                            x_returnStatus     => l_retStatus);
162     end if;
163   end removePriorsFromBatch;
164 
165   procedure removePriors(x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T) is
166     l_curOp NUMBER:= x_resTbls.opSeqNum(1);
167     l_nonPriorExists boolean := false;
168     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
169     l_retStatus VARCHAR2(1);
170     l_params wip_logger.param_tbl_t;
171   begin
172     if(l_logLevel <= wip_constants.trace_logging) then
173       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.removePriors',
174                             p_params => l_params,
175                             x_returnStatus => l_retStatus);
176     end if;
177     for i in 1..x_resTbls.resID.count loop
178       if(l_curOp = x_resTbls.opSeqNum(i)) then
179         if(l_nonPriorExists and x_resTbls.schedFlag(i) = wip_constants.sched_prior) then
180           x_resTbls.schedFlag(i) := wip_constants.sched_yes;
181         end if;
182         l_nonPriorExists := l_nonPriorExists or (x_resTbls.schedFlag(i) not in (wip_constants.sched_prior, wip_constants.sched_no));
183       else
184         l_curOp := x_resTbls.opSeqNum(i);
185         l_nonPriorExists := x_resTbls.schedFlag(i) not in (wip_constants.sched_prior, wip_constants.sched_no);
186       end if;
187     end loop;
188     if (l_logLevel <= wip_constants.trace_logging) then
189       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.removePriors',
190                            p_procReturnStatus => null,
191                            p_msg              => 'success',
192                            x_returnStatus     => l_retStatus);
193     end if;
194   end removePriors;
195 
196   procedure removeNexts(x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T) is
197     l_curOp NUMBER:= x_resTbls.opSeqNum(x_resTbls.resID.count);
198     l_nonNextExists boolean := false;
199     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
200     l_retStatus VARCHAR2(1);
201     l_params wip_logger.param_tbl_t;
202   begin
203     if(l_logLevel <= wip_constants.trace_logging) then
204       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.removeNexts',
205                             p_params => l_params,
206                             x_returnStatus => l_retStatus);
207     end if;
208     for i in reverse 1..x_resTbls.resID.count loop
209       if(l_curOp = x_resTbls.opSeqNum(i)) then
210         if(l_nonNextExists and x_resTbls.schedFlag(i) = wip_constants.sched_next) then
211           x_resTbls.schedFlag(i) := wip_constants.sched_yes;
212         end if;
213         l_nonNextExists := l_nonNextExists or
214                            (x_resTbls.schedFlag(i) not in (wip_constants.sched_next, wip_constants.sched_no));
215       else
216         l_curOp := x_resTbls.opSeqNum(i);
217         l_nonNextExists := x_resTbls.schedFlag(i) not in (wip_constants.sched_no, wip_constants.sched_next);
218       end if;
219     end loop;
220     if (l_logLevel <= wip_constants.trace_logging) then
221       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.removeNexts',
222                            p_procReturnStatus => null,
223                            p_msg              => 'success',
224                            x_returnStatus     => l_retStatus);
225     end if;
226   end removeNexts;
227 
228   procedure verifyResources(x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T) is
229 
230     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
231     l_retStatus VARCHAR2(1);
232     l_params wip_logger.param_tbl_t;
233   begin
234     if(l_logLevel <= wip_constants.trace_logging) then
235       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.verifyResources',
236                             p_params => l_params,
237                             x_returnStatus => l_retStatus);
238     end if;
239 
240     --changes schedule method of prior resources to yes if
241     -- + they are in the first op <= can't do this b/c of midpoint scheduling
242     -- + other resources with a different schedule type precede them in the operation
243     removePriors(x_resTbls => x_resTbls);
244 
245     --changes schedule method of next resources to yes if
246     -- + other resources with a different schedule type are after them in the operation
247     removeNexts(x_resTbls => x_resTbls);
248 
249     --if a prior resource is in a simultaneous batch that contains other resources
250     --with different scheduling methods simply treat them as
251     --scheduled ("yes") resources as the next/prior goals cannot be met, i.e. no
252     --overlap with the next/previous operation can be achieved.
253     --this shouldn't be done for next resources as they can still complete after
254     --the next operation starts (batched resources must start at the same time but
255     --can complete at different times).
256 
257     --changes schedule method of prior resources to yes if
258     -- + they are in a simultaneous batch with yes or next resources.
259     removePriorsFromBatch(x_resTbls => x_resTbls);
260     if (l_logLevel <= wip_constants.trace_logging) then
261       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.verifyResources',
262                            p_procReturnStatus => null,
263                            p_msg              => 'success',
264                            x_returnStatus     => l_retStatus);
265     end if;
266   end verifyResources;
267 
268   procedure dumpOps(p_opTbl in op_tbl_t) is
269     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
270     l_retStatus VARCHAR2(1);
271     l_params wip_logger.param_tbl_t;
272   begin
273     if(l_logLevel <= wip_constants.trace_logging) then
274       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.dumpOps',
275                             p_params => l_params,
276                             x_returnStatus => l_retStatus);
277     end if;
278     if(l_logLevel <= wip_constants.full_logging) then
279       for i in 1..p_opTbl.count loop
280         wip_logger.log('op:' || i, l_retStatus);
281         wip_logger.log('startDate:' || to_char(p_opTbl(i).startDate, g_logDateFmt), l_retStatus);
282         wip_logger.log('endDate:' || to_char(p_opTbl(i).endDate, g_logDateFmt), l_retStatus);
283         if(p_opTbl(i).priorsExist) then
284           wip_logger.log('priorsExist:true', l_retStatus);
285         else
286           wip_logger.log('priorsExist:false', l_retStatus);
287         end if;
288         if(p_opTbl(i).nextsExist) then
289           wip_logger.log('nextsExist:true', l_retStatus);
290         else
291           wip_logger.log('nextsExist:false', l_retStatus);
292         end if;
293         wip_logger.log('resRange:' || p_opTbl(i).resStartIdx || '-' || p_opTbl(i).resEndIdx, l_retStatus);
294       end loop;
295     end if;
296     if (l_logLevel <= wip_constants.trace_logging) then
297       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.dumpOps',
298                            p_procReturnStatus => null,
299                            p_msg              => 'success',
300                            x_returnStatus     => l_retStatus);
301     end if;
302   end dumpOps;
303 
304   procedure buildOpStructure(p_resTbls in op_res_rectbl_t,
305                              p_anchorDate in Date,
306                              x_opTbl out nocopy op_tbl_t) is
307     l_opSeqNum NUMBER := p_resTbls.opSeqNum(1);
308     l_startRange NUMBER := 1;
309     l_endRange NUMBER := 1;
310     j number := 1;
311     l_firstYesOpIdx NUMBER;
312     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
313     l_retStatus VARCHAR2(1);
314     l_params wip_logger.param_tbl_t;
315   begin
316     if(l_logLevel <= wip_constants.trace_logging) then
317       l_params(1).paramName := 'p_anchorDate';
318       l_params(1).paramValue := to_char(p_anchorDate, g_logDateFmt);
319       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.buildOpStructure',
320                             p_params => l_params,
321                             x_returnStatus => l_retStatus);
322     end if;
323 
324     --initialize op structure
325     x_opTbl(1).resStartIdx := 1;
326     x_opTbl(1).resEndIdx := null;
327 
328     for i in 1..p_resTbls.resID.count loop
329       if(l_opSeqNum <> p_resTbls.opSeqNum(i)) then
330 
331         if(l_logLevel <= wip_constants.full_logging) then
332           wip_logger.log('new op at resource ' || i, l_retStatus);
333         end if;
334 
335         x_opTbl(j).resEndIdx := i - 1;
336         j := j + 1;
337 --        if(j > 1) then
338 --          x_opTbl(j).startDate := x_opTbl(j-1).startDate;
339 --          x_opTbl(j).endDate := x_opTbl(j-1).endDate;
340 --        end if;
341         x_opTbl(j).resStartIdx := i;
342         x_opTbl(j).resEndIdx := null;
343 
344         l_opSeqNum := p_resTbls.opSeqNum(i);
345       end if;
346       x_opTbl(j).priorsExist := x_opTbl(j).priorsExist or p_resTbls.schedFlag(i) = wip_constants.sched_prior;
347       x_opTbl(j).nextsExist := x_opTbl(j).nextsExist or p_resTbls.schedFlag(i) = wip_constants.sched_next;
348       if(p_resTbls.schedFlag(i) = wip_constants.sched_yes) then
349         if(l_firstYesOpIdx is null) then
350           l_firstYesOpIdx := j;
351         end if;
352         x_opTbl(j).startDate := least(p_resTbls.startDate(i), nvl(x_opTbl(j).startDate, p_resTbls.startDate(i)));
353         x_opTbl(j).endDate := greatest(p_resTbls.endDate(i), nvl(x_opTbl(j).endDate, p_resTbls.endDate(i)));
354         if(l_logLevel <= wip_constants.full_logging) then
355           wip_logger.log('op ' || j || '''s start date:' || to_char(x_opTbl(j).startDate, g_logDateFmt), l_retStatus);
356           wip_logger.log('op ' || j || '''s end date:' || to_char(x_opTbl(j).endDate, g_logDateFmt), l_retStatus);
357         end if;
358 
359       end if;
360     end loop;
361     --for the last op, set the end resource to the last one in the structure
362     x_opTbl(x_opTbl.count).resEndIdx := p_resTbls.resID.count;
363 
364     for i in 1..x_opTbl.count loop
365       if(x_opTbl(i).startDate is null) then
366         if(i = 1) then
367           if(l_firstYesOpIdx is null) then
368             x_opTbl(i).startDate := p_anchorDate;
369             x_opTbl(i).endDate := p_anchorDate;
370   -- Added below condition for bug #13388579
371   -- This p_anchorDate  is greater than x_opTbl(l_firstYesOpIdx).startDate in backward scheduling because this is end date in backward scheduling .
372   -- This p_anchorDate  is equal to  x_opTbl(l_firstYesOpIdx).startDate in forward  scheduling because this is start date in forward scheduling .
373         -- If there is two type of resource both 24 and shift resource in operations then for few cases then p_anchorDate is less than  x_opTbl(l_firstYesOpIdx).startDate, in below code we considered that case.
374     elsif( x_opTbl(i).nextsExist and  (p_anchorDate < x_opTbl(l_firstYesOpIdx).startDate) ) then
375             x_opTbl(i).startDate := p_anchorDate;
376             x_opTbl(i).endDate := p_anchorDate;
377           else
378             x_opTbl(i).startDate := x_opTbl(l_firstYesOpIdx).startDate;
379             x_opTbl(i).endDate := x_opTbl(l_firstYesOpIdx).startDate;
380           end if;
381         else
382           x_opTbl(i).startDate := x_opTbl(i-1).endDate;
383           x_opTbl(i).endDate := x_opTbl(i-1).endDate;
384         end if;
385       end if;
386     end loop;
387 
388     if (l_logLevel <= wip_constants.full_logging) then
389       dumpOps(x_opTbl);
390     end if;
391 
392     if (l_logLevel <= wip_constants.trace_logging) then
393       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.buildOpStructure',
394                            p_procReturnStatus => null,
395                            p_msg              => 'success',
396                            x_returnStatus     => l_retStatus);
397     end if;
398   end buildOpStructure;
399 
400   procedure findMdPntRes(p_resTbls IN OP_RES_RECTBL_T,
401                          p_opSeqNum NUMBER,
402                          p_resSeqNum NUMBER,
403                          p_isMdPntFwd boolean,
404                          x_midPntFwdIdx OUT NOCOPY NUMBER,
405                          x_midPntBkwdIdx OUT NOCOPY NUMBER) is
406     l_retStatus VARCHAR2(1);
407     l_params wip_logger.param_tbl_t;
408     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
409     l_foundMidPntOp boolean := false;
410   begin
411     if(l_logLevel <= wip_constants.trace_logging) then
412       l_params(1).paramName := 'p_opSeqNum';
413       l_params(1).paramValue := p_opSeqNum;
414       l_params(2).paramName := 'p_resSeqNum';
415       l_params(2).paramValue := p_resSeqNum;
416       l_params(3).paramName := 'p_isMdPntFwd';
417       if(p_isMdPntFwd) then l_params(3).paramValue := 'true';
418       else l_params(3).paramValue := 'false'; end if;
419 
420       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.findMdPntRes',
421                             p_params => l_params,
422                             x_returnStatus => l_retStatus);
423     end if;
424 
425     --find the midpoint resource
426     for i in 1..p_resTbls.resID.count loop
427       if(p_opSeqNum = p_resTbls.opSeqNum(i)) then --op matches
428         l_foundMidPntOp := true;
429         if(l_logLevel <= wip_constants.full_logging) then
430           wip_logger.log('op seq matches res ' || i, l_retStatus);
431         end if;
432 
433         if(p_resSeqNum is not null) then
434           if(p_resSeqNum = p_resTbls.resSeqNum(i)) then --res seq matches
435 
436             if(l_logLevel <= wip_constants.full_logging) then
437               wip_logger.log('res seq matches res ' || i, l_retStatus);
438             end if;
439 
440             if(p_isMdPntFwd) then
441               -- bug 3423612: If there are simultaneous resources, we have to
442               -- set the index to the first res in the group (last res for
443               -- backwards scheduling).
444               for j in reverse 1..i loop
445                 if (p_resTbls.opSeqNum(j) = p_resTbls.opSeqNum(i) and
446                     nvl(p_resTbls.schedSeqNum(j), p_resTbls.resSeqNum(j)) = nvl(p_resTbls.schedSeqNum(i), p_resTbls.resSeqNum(i))) then
447                   x_midPntFwdIdx := j;
448                   if(j <> 1) then
449                     x_midPntBkwdIdx := j - 1;
450                   else
451                     x_midPntBkwdIdx := null;
452                   end if;
453                 else
454                   exit;
455                 end if;
456               end loop;
457             else
458               for j in i..p_resTbls.resID.count loop
459                 if (p_resTbls.opSeqNum(j) = p_resTbls.opSeqNum(i) and
460                     nvl(p_resTbls.schedSeqNum(j), p_resTbls.resSeqNum(j)) = nvl(p_resTbls.schedSeqNum(i), p_resTbls.resSeqNum(i))) then
461                   x_midPntBkwdIdx := j;
462                   if(j <> p_resTbls.resID.count) then
463                     x_midPntFwdIdx := j + 1;
464                   else
465                     x_midPntFwdIdx := null;
466                   end if;
467                 else
468                   exit;
469                 end if;
470               end loop;
471             end if; --start date...
472             exit; --res seq matched, exit loop
473           end if;
474         else --resource seq was not populated. use op start or end res
475 
476           if(l_logLevel <= wip_constants.full_logging) then
477             wip_logger.log('res seq is null', l_retStatus);
478           end if;
479 
480           if(p_isMdPntFwd) then --forward scheduling midpoint op
481             x_midPntFwdIdx := i;
482             if(i <> 1) then
483               x_midPntBkwdIdx := i - 1;
484             end if;
485             exit;
486           end if;
487         end if;
488       end if;
489 
490       --if backward scheduling the midpoint op and the first op of the next op was found...
491       if(l_foundMidPntOp and
492          not(p_isMdPntFwd) and
493          p_resTbls.opSeqNum(i) <> p_opSeqNum) then
494         if(l_logLevel <= wip_constants.full_logging) then
495           wip_logger.log('first res past midpoint at idx:' || i, l_retStatus);
496         end if;
497         x_midPntBkwdIdx := i - 1;
498         x_midPntFwdIdx := i;
499         exit;
500       end if;
501 
502       if(p_resTbls.resID.count = i) then
503         if(l_logLevel <= wip_constants.full_logging) then
504           wip_logger.log('backward scheduling everything', l_retStatus);
505         end if;
506 
507         x_midPntBkwdIdx := i;
508         exit;
509       end if;
510     end loop;
511     if(l_logLevel <= wip_constants.trace_logging) then
512       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.findMdPntRes',
513                            p_procReturnStatus => null,
514                            p_msg              => 'fwdIdx:' || x_midPntFwdIdx || '; bkwdIdx:' || x_midPntBkwdIdx,
515                            x_returnStatus     => l_retStatus);
516     end if;
517   end findMdPntRes;
518 
519   procedure schedule(p_orgID IN NUMBER,
520                      p_repLineID NUMBER := null,
521                      p_startDate DATE := null,
522                      p_endDate DATE := null,
523                      p_opSeqNum NUMBER := null,
524                      p_resSeqNum NUMBER := null,
525                      p_endDebug IN VARCHAR2 := null,
526                      x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
527                      x_returnStatus OUT NOCOPY VARCHAR2) is
528     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
529     l_params wip_logger.param_tbl_t;
530     l_retStatus VARCHAR2(1);
531 
532     l_fwdStIdx NUMBER;--resource to start forward scheduling from
533     l_bkwdEndIdx NUMBER;--resource to backward schedule to
534     l_startDate DATE;
535     l_endDate DATE;
536     l_range num_tbl_t := num_tbl_t(null,null);
537     l_opTbl op_tbl_t;
538     l_errMsg VARCHAR2(2000);
539   begin
540     if(l_logLevel <= wip_constants.trace_logging) then
541       l_params(1).paramName := 'p_orgID';
542       l_params(1).paramValue := p_orgID;
543       l_params(2).paramName := 'p_repLineID';
544       l_params(2).paramValue := p_repLineID;
545       l_params(3).paramName := 'p_startDate';
546       l_params(3).paramValue := to_char(p_startDate, g_logDateFmt);
547       l_params(4).paramName := 'p_endDate';
548       l_params(4).paramValue := to_char(p_endDate, g_logDateFmt);
549       l_params(5).paramName := 'p_opSeqNum';
550       l_params(5).paramValue := p_opSeqNum;
551       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.schedule',
552                             p_params => l_params,
553                             x_returnStatus => x_returnStatus);
554       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
555         raise fnd_api.g_exc_unexpected_error;
556       end if;
557     end if;
558     x_returnStatus := fnd_api.g_ret_sts_success;
559 
560     if(x_resTbls.resID is null or x_resTbls.resID.count < 1) then
561       if (l_logLevel <= wip_constants.trace_logging) then
562         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedule',
563                              p_procReturnStatus => x_returnStatus,
564                              p_msg              => 'no resources to schedule!',
565                              x_returnStatus     => l_retStatus);
566       end if;
567       return;
568     end if;
569 
570     --initialize the date tables
571     x_resTbls.startDate := date_tbl_t();
572     x_resTbls.endDate := date_tbl_t();
573 
574     x_resTbls.usgStartIdx := num_tbl_t();
575     x_resTbls.usgEndIdx := num_tbl_t();
576 
577     x_resTbls.usgStartDate := date_tbl_t();
578     x_resTbls.usgEndDate := date_tbl_t();
579 
580     x_resTbls.usgCumMinProcTime := num_tbl_t();
581 
582     x_resTbls.usgStartIdx.extend(x_resTbls.resID.count);
583     x_resTbls.usgEndIdx.extend(x_resTbls.resID.count);
584 
585     x_resTbls.startDate.extend(x_resTbls.resID.count);
586     x_resTbls.endDate.extend(x_resTbls.resID.count);
587     if(l_logLevel <= wip_constants.trace_logging) then
588       dumpResources(x_resTbls);
589     end if;
590 
591     verifyResources(x_resTbls => x_resTbls);
592 
593     if(l_logLevel <= wip_constants.trace_logging) then
594       dumpResources(x_resTbls);
595     end if;
596 
597     --caller wants to either forward or backward schedule.
598     if(p_opSeqNum is null) then
599       --forward
600       if(p_startDate is not null) then
601         l_fwdStIdx := 1;
602         l_bkwdEndIdx := null;--this line isn''t necessary, but is included for clarity
603         l_startDate := p_startDate;
604         l_endDate := null;--this line isn''t necessary, but is included for clarity
605 
606         if (l_logLevel <= wip_constants.trace_logging) then
607           wip_logger.log(p_msg          => 'forward scheduling',
608                          x_returnStatus => x_returnStatus);
609         end if;
610 
611       --backward
612       else
613         l_fwdStIdx := null;--this line isn''t necessary, but is included for clarity
614         l_bkwdEndIdx := x_resTbls.resID.count;
615         l_startDate := null;--this line isn''t necessary, but is included for clarity
616         l_endDate := p_endDate;
617 
618         if (l_logLevel <= wip_constants.trace_logging) then
619           wip_logger.log(p_msg          => 'backward scheduling',
620                          x_returnStatus => x_returnStatus);
621         end if;
622       end if;
623     else --midpoint scheduling
624       findMdPntRes(p_resTbls => x_resTbls,
625                    p_opSeqNum => p_opSeqNum,
626                    p_resSeqNum => p_resSeqNum,
627                    p_isMdPntFwd => p_startDate is not null,
628                    x_midPntFwdIdx => l_fwdStIdx,
629                    x_midPntBkwdIdx => l_bkwdEndIdx);
630 
631       if (l_logLevel <= wip_constants.trace_logging) then
632         wip_logger.log(p_msg          => 'midpoint scheduling',
633                        x_returnStatus => x_returnStatus);
634       end if;
635 
636       if(p_startDate is not null) then
637         --forward schedule operation provided and those greater.
638         --backward schedule previous operations
639         l_startDate := p_startDate;
640         l_endDate := p_startDate;
641       else
642         --forward schedule operations greater than the one provided
643         --backward schedule op provided and the previous ones
644         l_startDate := p_endDate;
645         l_endDate := p_endDate;
646       end if;
647     end if;
648 
649     if(l_fwdStIdx is not null) then
650       l_range(1) := l_fwdStIdx;
651       l_range(2) := x_resTbls.resID.count;
652 
653       --forward schedule resources in range.
654       forwardSchedule(p_orgID        => p_orgID,
655                       p_repLineID    => p_repLineID,
656                       p_startDate    => l_startDate,
657                       p_range        => l_range,
658                       p_schedFlag    => wip_constants.sched_yes,
659                       x_resTbls      => x_resTbls,
660                       x_returnStatus => x_returnStatus);
661 
662       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
663         if(l_logLevel <= wip_constants.full_logging) then
664           wip_logger.log('fwdSch failed', l_retStatus);
665         end if;
666         raise fnd_api.g_exc_unexpected_error;
667       end if;
668 
669       if(l_logLevel <= wip_constants.full_logging) then
670         dumpResources(x_resTbls);
671       end if;
672     end if;
673 
674     if(l_bkwdEndIdx is not null) then
675       l_range(1) := 1;
676       l_range(2) := l_bkwdEndIdx;
677 
678       --backward schedule resources in range.
679       backwardSchedule(p_orgID        => p_orgID,
680                        p_repLineID    => p_repLineID,
681                        p_endDate      => l_endDate,
682                        p_range        => l_range,
683                        p_schedFlag    => wip_constants.sched_yes,
684                        x_resTbls      => x_resTbls,
685                        x_returnStatus => x_returnStatus);
686       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
687         if(l_logLevel <= wip_constants.full_logging) then
688           wip_logger.log('bkwdSch failed', l_retStatus);
689         end if;
690         raise fnd_api.g_exc_unexpected_error;
691       end if;
692     end if;
693 
694     --build the operation structure
695     buildOpStructure(p_resTbls    => x_resTbls,
696                      p_anchorDate => nvl(p_startDate, p_endDate),
697                      x_opTbl      => l_opTbl);
698 
699     --now schedule prior and next resources
700     schedulePriorResources(p_orgID => p_orgID,
701                            p_repLineID => p_repLineID,
702                            p_opTbl => l_opTbl,
703                            x_resTbls => x_resTbls,
704                            x_returnStatus => x_returnStatus);
705 
706     if(x_returnStatus <> fnd_api.g_ret_sts_success) then
707       if(l_logLevel <= wip_constants.full_logging) then
708         wip_logger.log('schPriorRes failed', l_retStatus);
709       end if;
710       raise fnd_api.g_exc_unexpected_error;
711     end if;
712  -- Bug # 13388579 logic to identify back ward scheduling .
713  if(p_opSeqNum is null and p_endDate is not null) then
714   is_backWardSch := true;
715   end if;
716 
717     scheduleNextResources(p_orgID => p_orgID,
718                           p_repLineID => p_repLineID,
719                           p_opTbl => l_opTbl,
720                           x_resTbls => x_resTbls,
721                           x_returnStatus => x_returnStatus);
722 
723 
724     if(x_returnStatus <> fnd_api.g_ret_sts_success) then
725       if(l_logLevel <= wip_constants.full_logging) then
726         wip_logger.log('schNextRes failed', l_retStatus);
727       end if;
728       raise fnd_api.g_exc_unexpected_error;
729     end if;
730 
731     if(l_logLevel <= wip_constants.full_logging) then
732       dumpResources(x_resTbls);
733     end if;
734 
735     --if forward scheduling...
736     if(p_opSeqNum is null and p_startDate is not null) then
737       resolvePriorExceptions(p_orgID        => p_orgID,
738                              p_repLineID    => p_repLineID,
739                              p_startDate    => p_startDate,
740                              x_resTbls      => x_resTbls,
741                              x_returnStatus => x_returnStatus);
742       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
743         if(l_logLevel <= wip_constants.full_logging) then
744           wip_logger.log('resolvePriorRes failed', l_retStatus);
745         end if;
746         raise fnd_api.g_exc_unexpected_error;
747       end if;
748     --if backward scheduling
749     elsif(p_opSeqNum is null and p_endDate is not null) then
750       resolveNextExceptions(p_orgID        => p_orgID,
751                             p_repLineID    => p_repLineID,
752                             p_endDate      => p_endDate,
753                             x_resTbls      => x_resTbls,
754                             x_returnStatus => x_returnStatus);
755    -- Bug # 13388579 resetting the flag.
756   is_backWardSch := false;
757       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
758         if(l_logLevel <= wip_constants.full_logging) then
759           wip_logger.log('resolveNextRes failed', l_retStatus);
760         end if;
761         raise fnd_api.g_exc_unexpected_error;
762       end if;
763     end if;
764 
765 
766     --assign dates to scheduled no resources
767     scheduleNoResources(p_anchorDate => nvl(p_startDate, p_endDate),
768                         x_resTbls => x_resTbls,
769                         x_returnStatus => x_returnStatus);
770 
771 
772 
773     if(l_logLevel <= wip_constants.trace_logging) then
774       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedule',
775                            p_procReturnStatus => x_returnStatus,
776                            p_msg              => 'success',
777                            x_returnStatus     => l_retStatus);
778       if(fnd_api.to_boolean(nvl(p_endDebug, fnd_api.g_true))) then
779         wip_logger.cleanup(l_retStatus);
780       end if;
781     end if;
782   exception
783      when fnd_api.g_exc_unexpected_error then
784        x_returnStatus := fnd_api.g_ret_sts_unexp_error;
785        if(l_logLevel <= wip_constants.trace_logging) then
786          wip_utilities.get_message_stack(p_msg => l_errMsg,
787                                          p_delete_stack => fnd_api.g_false);
788 
789          wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedule',
790                               p_procReturnStatus => x_returnStatus,
791                               p_msg              => 'failure: ' || l_errMsg,
792                               x_returnStatus     => l_retStatus);
793          if(fnd_api.to_boolean(nvl(p_endDebug, fnd_api.g_true))) then
794            wip_logger.cleanup(l_retStatus);
795          end if;
796        end if;
797      when others then
798        x_returnStatus := fnd_api.g_ret_sts_unexp_error;
799        fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
800                                p_procedure_name => 'schedule',
801                                p_error_text => SQLERRM);
802        if(l_logLevel <= wip_constants.trace_logging) then
803          wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedule',
804                               p_procReturnStatus => x_returnStatus,
805                               p_msg              => 'unexpected error: ' || SQLERRM,
806                               x_returnStatus     => l_retStatus);
807          if(fnd_api.to_boolean(nvl(p_endDebug, fnd_api.g_true))) then
808            wip_logger.cleanup(l_retStatus);
809          end if;
810        end if;
811   end schedule;
812 
813   function getNextResIdx(p_range        in num_tbl_t,
814                          p_schedFlag    in number,
815                          p_schedMethod  in number,
816                          p_resTbls      in OP_RES_RECTBL_T,
817                          x_idx in out nocopy number) return boolean is
818     l_retStatus VARCHAR2(1);
819   begin
820     if(p_schedMethod = g_forward) then
821       for j in nvl(x_idx+1, p_range(1))..p_range(2) loop
822         if(p_resTbls.schedFlag(j) = p_schedFlag) then
823           x_idx := j;
824           return true;
825         end if;
826       end loop;
827     end if;
828 
829     if(p_schedMethod = g_backward) then
830       for j in reverse p_range(1)..nvl(x_idx-1,p_range(2)) loop
831         if(p_resTbls.schedFlag(j) = p_schedFlag) then
832           x_idx := j;
833           return true;
834         end if;
835       end loop;
836     end if;
837 
838     return false;
839   end getNextResIdx;
840 
841   --p_prevStartDate: The date from which the previous resource was scheduled from (not necessarily
842   -- the start date of the previous resource...no shift could have been defined on the exact time
843   -- the resource could have been scheduled from)
844   function getStartDate(p_range in num_tbl_t,
845                         p_schedFlag in number,
846                         p_resTbls in op_res_rectbl_t,
847                         p_curIdx in number,
848                         p_doneSchedBatch in boolean,
849                         p_prevIdx in number) return date is
850     l_retStatus VARCHAR2(1);
851     l_params wip_logger.param_tbl_t;
852     i number;
853     l_maxEndDate date;
854     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
855     l_bool boolean;
856   begin
857     if (l_logLevel <= wip_constants.trace_logging) then
858       l_params(1).paramName := 'p_range(1)';
859       l_params(1).paramValue := p_range(1);
860       l_params(2).paramName := 'p_range(2)';
861       l_params(2).paramValue := p_range(2);
862       l_params(3).paramName := 'p_schedFlag';
863       l_params(3).paramValue := p_schedFlag;
864       l_params(4).paramName := 'p_curIdx';
865       l_params(4).paramValue := p_curIdx;
866       l_params(5).paramName := 'p_doneSchedBatch';
867       if(p_doneSchedBatch) then l_params(5).paramValue := 'true';
868       else l_params(5).paramValue := 'false';
869       end if;
870       l_params(6).paramName := 'p_prevIdx';
871       l_params(6).paramValue := p_prevIdx;
872 
873       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.getStartDate',
874                             p_params       => l_params,
875                             x_returnStatus => l_retStatus);
876     end if;
877 
878     --in case we just got done scheduling a batch of simultaneous resources, get the
879     --latest end date to use as the next resource's start date
880     i := p_curIdx;
881 
882     if(p_doneSchedBatch) then
883       if(l_logLevel <= wip_constants.full_logging) then
884         wip_logger.log('done scheduling batch', l_retStatus);
885       end if;
886       while(getNextResIdx(p_range, p_schedFlag, g_backward, p_resTbls, i)) loop
887         if(l_logLevel <= wip_constants.full_logging) then
888           wip_logger.log('in loop', l_retStatus);
889           wip_logger.log('resID' || p_resTbls.resID(i), l_retStatus);
890           wip_logger.log('opSeq' || p_resTbls.opSeqNum(i), l_retStatus);
891           wip_logger.log('schSeq' || p_resTbls.schedSeqNum(i), l_retStatus);
892           wip_logger.log('idx' || i, l_retStatus);
893         end if;
894         if(p_resTbls.schedSeqNum(i) = p_resTbls.schedSeqNum(p_prevIdx) and
895            p_resTbls.opSeqNum(i) = p_resTbls.opSeqNum(p_prevIdx)) then
896           l_maxEndDate := greatest(nvl(l_maxEndDate, p_resTbls.endDate(i)), p_resTbls.endDate(i));
897           if(l_logLevel <= wip_constants.full_logging) then
898             wip_logger.log('resource in batch. endDate:' || to_char(p_resTbls.endDate(i), g_logDateFmt), l_retStatus);
899           end if;
900         else
901           if(l_logLevel <= wip_constants.full_logging) then
902             wip_logger.log('resource not in batch.', l_retStatus);
903           end if;
904           exit;
905         end if;
906       end loop;
907     else
908       l_bool := (getNextResIdx(p_range, p_schedFlag, g_backward, p_resTbls, i));
909       l_maxEndDate := p_resTbls.endDate(i);
910     end if;
911 
912     if (l_logLevel <= wip_constants.trace_logging) then
913       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.getStartDate',
914                            p_procReturnStatus => to_char(l_maxEndDate),
915                            p_msg              => 'finished scheduling',
916                            x_returnStatus     => l_retStatus);
917     end if;
918     return l_maxEndDate;
919   end getStartDate;
920 
921  /*Bug 13069474: Added this function to process overlapping shifts*/
922     procedure process_shift(p_fwd_or_bk_flag in number,
923        i in number,
924        x_shifts in out nocopy shift_recTbl_t,
925        x_overlap_exists in out nocopy boolean) is
926  l_retStatus VARCHAR2(1);
927  l_params wip_logger.param_tbl_t;
928  l_logLevel NUMBER := fnd_log.g_current_runtime_level;
929   begin
930    if (l_logLevel <= wip_constants.trace_logging) then
931       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.process_shift',
932                             p_params       => l_params,
933                             x_returnStatus => l_retStatus);
934     end if;
935  if(p_fwd_or_bk_flag = 1) then /*backward schedule*/
936   /*For backward scheduling, the shifts are ordered in descreasing order of
937   startDate. Thats how the cursors populating into x_shifts are written.*/
938   if(x_shifts.endDate(i+1) < x_shifts.startDate(i)) then
939     if(l_logLevel <= wip_constants.full_logging) then
940       wip_logger.log('no overlap for shift', l_retStatus);
941     end if;
942   else
943    x_overlap_exists := true;
944    if(x_shifts.endDate(i+1) <= x_shifts.endDate(i)) then
945      if(l_logLevel <= wip_constants.full_logging) then
946        wip_logger.log('partial overlap for shift', l_retStatus);
947      end if;
948      x_shifts.endDate(i+1) := x_shifts.endDate(i);
949    else
950      if(l_logLevel <= wip_constants.full_logging) then
951        wip_logger.log('complete overlap for shift', l_retStatus);
952      end if;
953    end if;
954    /*instead of deleting the shift here setting it to -1.
955    Will delete the -1 shifts together later, otherwise with everyloop
956    there will be sorting of the records required, which will have
957    performance impact.*/
958    x_shifts.shiftNum(i) := -1;
959   end if;
960  else /*forward schedule*/
961   /*For forward scheduling, the shifts are ordered in ascending order of
962   startDate. Thats how the cursors populating into x_shifts are written.*/
963   if(x_shifts.startDate(i+1) > x_shifts.endDate(i)) then
964     if(l_logLevel <= wip_constants.full_logging) then
965       wip_logger.log('no overlap for shift', l_retStatus);
966     end if;
967   else
968    x_overlap_exists := true;
969    if(x_shifts.startDate(i+1) > x_shifts.startDate(i)) then
970     if(l_logLevel <= wip_constants.full_logging) then
971       wip_logger.log('partial overlap for shift: adjusted startDate', l_retStatus);
972     end if;
973     x_shifts.startDate(i+1) := x_shifts.startDate(i);
974    end if;
975    if(x_shifts.endDate(i+1) < x_shifts.endDate(i)) then
976     if(l_logLevel <= wip_constants.full_logging) then
977       wip_logger.log('partial overlap for shift: adjusted endDate', l_retStatus);
978     end if;
979     x_shifts.endDate(i+1) := x_shifts.endDate(i);
980    end if;
981    /*instead of deleting the shift here setting it to -1.
982    Will delete the -1 shifts together later, otherwise with everyloop
983    there will be sorting of the records required, which will have
984    performance impact.*/
985    x_shifts.shiftNum(i) := -1;
986   end if;
987  end if;
988  if(l_logLevel <= wip_constants.trace_logging) then
989         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.process_shift',
990                              p_procReturnStatus => l_retStatus,
991                              p_msg              => 'successful complete',
992                              x_returnStatus     => l_retStatus);
993     end if;
994   end;
995 
996   /*Bug 13069474: Added this function to process overlapping shifts*/
997   procedure process_overlap_shifts(p_fwd_or_bk_flag in number, x_shifts in out nocopy shift_recTbl_t) is
998  l_retStatus VARCHAR2(1);
999  l_overlap_exists boolean := true;
1000  l_count number;
1001  l_count2 number;
1002  l_params wip_logger.param_tbl_t;
1003  l_logLevel NUMBER := fnd_log.g_current_runtime_level;
1004  l_shifts shift_recTbl_t;
1005   begin
1006     if (l_logLevel <= wip_constants.trace_logging) then
1007       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.process_overlap_shifts',
1008                             p_params       => l_params,
1009                             x_returnStatus => l_retStatus);
1010 
1011       wip_logger.log('shifts BEFORE overlap processing', l_retStatus);
1012       wip_logger.log('*********************************', l_retStatus);
1013     end if;
1014 
1015  for i in 1..(x_shifts.shiftNum.count) loop
1016   if (l_logLevel <= wip_constants.trace_logging) then
1017     wip_logger.log('shiftNum: ' || x_shifts.shiftNum(i)
1018       || ' startDate: ' || to_char(x_shifts.startDate(i), g_logDateFmt)
1019       || ' endDate:' || to_char(x_shifts.endDate(i), g_logDateFmt), l_retStatus);
1020   end if;
1021  end loop;
1022  /*Overnight shifts*/
1023  for i in 1..(x_shifts.shiftNum.count) loop
1024   if(x_shifts.endDate(i) < x_shifts.startDate(i)) then --overnight shift
1025           x_shifts.endDate(i) := x_shifts.endDate(i) + 1;
1026     if (l_logLevel <= wip_constants.trace_logging) then
1027     wip_logger.log('increased endDate by 1 day for count: ' || i, l_retStatus);
1028     end if;
1029         end if;
1030  end loop;
1031  /*Looping in x_shifts to delete overlapping shifts and to create one most inclusive shifts.
1032  Since shifts are getting merged thus Shift Numbers may be incorrect after this processing.
1033  But in later part of the code, Shift Numbers are not needed and only start and end times
1034  are used.*/
1035  while(l_overlap_exists) loop
1036   if (l_logLevel <= wip_constants.trace_logging) then
1037   wip_logger.log('while loop begins', l_retStatus);
1038   end if;
1039   --at the start of the loop, setting overlap to false. if it exists it will set to true
1040   l_overlap_exists := false;
1041   for i in 1..(x_shifts.shiftNum.count-1) loop --i shift is compared to i+1
1042   -- Bug 14782605
1043     -- if (x_shifts.shiftNum(i) = -1) then continue; end if;
1044   if(x_shifts.shiftNum(i) <> -1) then
1045    process_shift(p_fwd_or_bk_flag, i, x_shifts, l_overlap_exists);
1046   end if;
1047   end loop;--for loop
1048   /*Deleting shifts with shiftNum = -1*/
1049   l_count := x_shifts.shiftNum.count;
1050   if (l_logLevel <= wip_constants.trace_logging) then
1051   wip_logger.log('num of shifts: ' || l_count, l_retStatus);
1052   end if;
1053   for i in 1..(x_shifts.shiftNum.count) loop
1054    if (l_logLevel <= wip_constants.trace_logging) then
1055    wip_logger.log('counter: ' || i, l_retStatus);
1056    end if;
1057    if(x_shifts.shiftNum(i) = -1) then
1058     l_count2 := i;
1059     for j in (i)..(x_shifts.shiftNum.count) loop
1060      if (x_shifts.shiftNum(j) > -1) then
1061       l_count2 := j; exit;
1062      end if;
1063     end loop;
1064     if (l_logLevel <= wip_constants.trace_logging) then
1065     wip_logger.log('moving shift at position: ' || l_count2 || 'to position: ' || i, l_retStatus);
1066     end if;
1067     if(l_count2 > i) then
1068      x_shifts.shiftNum(i) := x_shifts.shiftNum(l_count2);
1069      x_shifts.startDate(i) := x_shifts.startDate(l_count2);
1070      x_shifts.endDate(i) := x_shifts.endDate(l_count2);
1071      x_shifts.shiftNum(l_count2) := -1;
1072     end if;
1073     if (l_logLevel <= wip_constants.trace_logging) then
1074     wip_logger.log('deleted counter: ' || i, l_retStatus);
1075     end if;
1076    end if;
1077   end loop;
1078   /*Identifying how many shifts left after deletion*/
1079   l_count2 := 0;
1080   for i in 1..(x_shifts.shiftNum.count) loop
1081    if(x_shifts.shiftNum(i) > -1) then l_count2 := l_count2 + 1;
1082    end if;
1083   end loop;
1084   if (l_logLevel <= wip_constants.trace_logging) then
1085   wip_logger.log('num of shifts (after deletion): ' || l_count2, l_retStatus);
1086   end if;
1087   /*Trim the remaining shifts. These shifts are deleted above and have shiftNum as -1*/
1088   x_shifts.shiftNum.trim(l_count-l_count2);
1089   x_shifts.startDate.trim(l_count-l_count2);
1090   x_shifts.endDate.trim(l_count-l_count2);
1091  end loop;
1092  if (l_logLevel <= wip_constants.trace_logging) then
1093  wip_logger.log('shifts AFTER overlap processing', l_retStatus);
1094  wip_logger.log('*********************************', l_retStatus);
1095  end if;
1096  for i in 1..(x_shifts.shiftNum.count) loop
1097  if (l_logLevel <= wip_constants.trace_logging) then
1098   wip_logger.log('shiftNum: ' || x_shifts.shiftNum(i)
1099       || ' startDate: ' || to_char(x_shifts.startDate(i), g_logDateFmt)
1100       || ' endDate:' || to_char(x_shifts.endDate(i), g_logDateFmt), l_retStatus);
1101  end if;
1102  end loop;
1103  if(l_logLevel <= wip_constants.trace_logging) then
1104         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.process_overlap_shifts',
1105                              p_procReturnStatus => l_retStatus,
1106                              p_msg              => 'successful complete',
1107                              x_returnStatus     => l_retStatus);
1108     end if;
1109   end process_overlap_shifts;
1110 
1111   procedure forwardSchResource(p_orgID in number,
1112                                p_startDate in date,
1113                                p_maxDate in date,
1114                                p_idx in number,
1115                                p_repLineID in number := null,
1116                                x_resTbls in out nocopy op_res_rectbl_t,
1117                                x_returnStatus out nocopy varchar2) is
1118 
1119     cursor c_shiftTimes(v_resID NUMBER,
1120                         v_deptID NUMBER,
1121                         v_orgID NUMBER,
1122                         v_startDate DATE,
1123                         v_endDate DATE) is
1124       select brs.shift_num,
1125              bsd.shift_date + bst.from_time/86400,
1126 	     --added the below case statement for bug 16481026.
1127 	     -- This fix is to consider the resource scheduled from 00:00:00 to 00:00:00 properly
1128 	     -- to ensure that the start time and end time for such resource are not same.
1129 	     CASE WHEN (bst.to_time = bst.from_time or bst.to_time < bst.from_time)
1130               THEN bsd.shift_date + bst.to_time/86400 + 1
1131              ELSE
1132               bsd.shift_date + bst.to_time/86400
1133              END
1134              --bsd.shift_date + bst.to_time/86400
1135         from bom_resource_shifts brs,
1136              mtl_parameters mp,
1137              bom_shift_dates bsd,
1138              bom_shift_times bst,
1139              bom_department_resources bdr
1140        where bdr.department_id = v_deptID
1141          and bdr.resource_id = v_resID
1142          and brs.resource_id = bdr.resource_id
1143          and brs.department_id = nvl(bdr.share_from_dept_id,bdr.department_id)
1144          and mp.organization_id = v_orgID
1145          and mp.calendar_code = bsd.calendar_code
1146          and mp.calendar_exception_set_id = bsd.exception_set_id
1147          and brs.shift_num = bsd.shift_num
1148          and bsd.shift_date between v_startDate and v_endDate --don't incorporate time into this check as it slows the query
1149          and bsd.seq_num is not null
1150          and bst.shift_num = bsd.shift_num
1151          and bst.calendar_code = bsd.calendar_code
1152        order by bsd.shift_date, bst.from_time;
1153 
1154       --for repetitive, ignore shifts and use the line's start and stop times. However, do
1155       --respect the working days definition
1156       cursor c_repTimes(v_repLineID NUMBER,
1157                         v_orgID NUMBER,
1158                         v_startDate DATE,
1159                         v_endDate DATE) is
1160       select -1 shiftNum,
1161              bcd.calendar_date + wl.start_time/86400,
1162              bcd.calendar_date + wl.stop_time/86400
1163         from mtl_parameters mp,
1164              bom_calendar_dates bcd,
1165              wip_lines wl
1166        where mp.organization_id = v_orgID
1167          and mp.calendar_code = bcd.calendar_code
1168          and mp.calendar_exception_set_id = bcd.exception_set_id
1169          and wl.line_id = v_repLineID
1170          and bcd.seq_num is not null --working day
1171          and bcd.calendar_date between v_startDate and v_endDate
1172        order by bcd.calendar_date;
1173 
1174     cursor c_24HrTimes(v_orgID NUMBER,
1175                        v_startDate DATE,
1176                        v_endDate DATE) is
1177       select -1,
1178              bcd.calendar_date,
1179              bcd.calendar_date + 1
1180         from mtl_parameters mp,
1181              bom_calendar_dates bcd
1182        where mp.organization_id = v_orgID
1183          and mp.calendar_code = bcd.calendar_code
1184          and mp.calendar_exception_set_id = bcd.exception_set_id
1185          and bcd.calendar_date between v_startDate and v_endDate
1186          and bcd.seq_num is not null
1187        order by bcd.calendar_date;
1188 
1189      --used to collect cursor records...
1190     /* fix bug 7027946 */
1191     /* type shift_recTbl_t is record(shiftNum num_tbl_t,
1192                                      startDate date_tbl_t,
1193                                      endDate date_tbl_t);
1194      end of fix bug 7027946 */
1195 
1196     l_shifts shift_recTbl_t;
1197     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
1198     l_params wip_logger.param_tbl_t;
1199     l_retStatus VARCHAR2(1);
1200     l_resourceScheduled boolean := false;
1201     l_cursorStartDate date := trunc(p_startDate) - 1;--subtract 1 to make sure to get wraparound shifts (start on prev day)
1202     l_fromDate date;
1203     l_shiftLen NUMBER;
1204     l_remUsage NUMBER := x_resTbls.totalDaysUsg(p_idx);
1205     l_usgIdx NUMBER;
1206     l_startDate DATE;
1207     l_prevProcTime NUMBER;
1208     l_isFirstUsg boolean := true;
1209     l_dummy NUMBER; /* Bug 5660475 */
1210   begin
1211     if (l_logLevel <= wip_constants.trace_logging) then
1212       l_params(1).paramName := 'p_orgID';
1213       l_params(1).paramValue := p_orgID;
1214       l_params(2).paramName := 'p_startDate';
1215       l_params(2).paramValue := to_char(p_startDate, g_logDateFmt);
1216       l_params(3).paramName := 'p_maxDate';
1217       l_params(3).paramValue := to_char(p_maxDate, g_logDateFmt);
1218       l_params(4).paramName := 'p_idx';
1219       l_params(4).paramValue := p_idx;
1220       l_params(5).paramName := 'p_repLineID';
1221       l_params(5).paramValue := p_repLineID;
1222       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.forwardSchResource',
1223                             p_params       => l_params,
1224                             x_returnStatus => l_retStatus);
1225     end if;
1226     x_returnStatus := fnd_api.g_ret_sts_success;
1227 
1228     /* Fix for bug 5660475: If dealing with shift resource, first check if shifts are setup fine. */
1229     -- Bug 16322124 . Modified for Performance. Validation is simplified since all shifts are assumed to have valid time setups .
1230     if( p_repLineID is null
1231         and x_resTbls.avail24Flag(p_idx) = wip_constants.no
1232    and x_resTbls.schedFlag(p_idx) <> wip_constants.sched_no) then
1233    if (l_logLevel <= wip_constants.trace_logging) then
1234   wip_logger.log('This is a shift resource. Need to validate shift setup', l_retStatus);
1235   end if;
1236   begin
1237     -- Bug 16322124 . Modified for Performance.
1238     select 1
1239     into l_dummy
1240     from dual
1241     where exists (select 1
1242                     from bom_resource_shifts brs,
1243                          bom_department_resources bdr
1244                    where bdr.department_id = x_resTbls.deptID(p_idx)
1245                      and bdr.resource_id = x_resTbls.resID(p_idx)
1246                      and brs.resource_id = bdr.resource_id
1247                      and brs.department_id = nvl(bdr.share_from_dept_id,bdr.department_id)
1248                      and brs.shift_num is not null
1249                      and rownum = 1);
1250   exception
1251      when NO_DATA_FOUND then
1252         if (l_logLevel <= wip_constants.trace_logging) then
1253         wip_logger.log('Error: Missing shifts or shift times!', l_retStatus);
1254         end if;
1255         fnd_message.set_name('WIP', 'WIP_SHIFT_RESOURCE');
1256         fnd_message.set_token('ENTITY1', x_resTbls.resSeqNum(p_idx));
1257         fnd_message.set_token('ENTITY2', x_resTbls.opSeqNum(p_idx));
1258         fnd_msg_pub.add;
1259         raise fnd_api.g_exc_unexpected_error;
1260   end;
1261     end if;
1262 
1263     x_resTbls.usgStartIdx(p_idx) := null;
1264     x_resTbls.usgEndIdx(p_idx) := null;
1265     loop
1266       exit when l_resourceScheduled;
1267       if (l_logLevel <= wip_constants.full_logging) then
1268         wip_logger.log('cursor start date is' || to_char(l_cursorStartDate, g_logDateFmt), l_retStatus);
1269         wip_logger.log('cursor end date is' || to_char((l_cursorStartDate  + g_dateCursorLen - 1/86400), g_logDateFmt), l_retStatus);
1270       end if;
1271 
1272       --for v_endDate, subtract a second to avoid overlap between cursors.
1273       if(p_repLineID is not null) then
1274         if(l_logLevel <= wip_constants.full_logging) then
1275           wip_logger.log('scheduling repetitive', l_retStatus);
1276         end if;
1277         open c_repTimes(v_repLineID => p_repLineID,
1278                         v_orgID     => p_orgID,
1279                         v_startDate => l_cursorStartDate,
1280                         v_endDate   => l_cursorStartDate + g_dateCursorLen - 1/86400);
1281         fetch c_repTimes
1282           bulk collect into l_shifts.shiftNum,
1283                             l_shifts.startDate,
1284                             l_shifts.endDate;
1285         close c_repTimes;
1286       elsif(x_resTbls.avail24Flag(p_idx) = wip_constants.yes) then
1287         if(l_logLevel <= wip_constants.full_logging) then
1288           wip_logger.log('scheduling 24HR resource', l_retStatus);
1289         end if;
1290         open c_24HrTimes(v_orgID     => p_orgID,
1291                          v_startDate => l_cursorStartDate,
1292                          v_endDate   => l_cursorStartDate + g_dateCursorLen - 1/86400);
1293         fetch c_24HrTimes
1294           bulk collect into l_shifts.shiftNum,
1295                             l_shifts.startDate,
1296                             l_shifts.endDate;
1297         close c_24HrTimes;
1298       else
1299         if(l_logLevel <= wip_constants.full_logging) then
1300           wip_logger.log('scheduling shift resource', l_retStatus);
1301         end if;
1302         open c_shiftTimes(v_resID     => x_resTbls.resID(p_idx),
1303                           v_deptID    => x_resTbls.deptID(p_idx),
1304                           v_orgID     => p_orgID,
1305                           v_startDate => l_cursorStartDate,
1306                           v_endDate   => l_cursorStartDate + g_dateCursorLen - 1/86400);
1307         fetch c_shiftTimes
1308           bulk collect into l_shifts.shiftNum,
1309                             l_shifts.startDate,
1310                             l_shifts.endDate;
1311 
1312         if (l_shifts.shiftNum.count = 0 ) then
1313         /* Fix for bug 5660475: If shifts are not available in the date range,
1314  we should continue to search in the next date range, instead of erroring out. */
1315    if (l_logLevel <= wip_constants.trace_logging) then
1316    wip_logger.log('No shifts found in this period.', l_retStatus);
1317    end if;
1318           l_resourceScheduled := false;
1319         end if;
1320 
1321         close c_shiftTimes;
1322 
1323        /* fix bug 7027946 */
1324        capacityExceptions(p_resID        => x_resTbls.resID(p_idx),     -- adjust the capacity exception.
1325                           p_deptID       => x_resTbls.deptID(p_idx),
1326                           p_orgID        => p_orgID,
1327                           x_shifts       => l_shifts,
1328                           x_returnStatus => x_returnStatus);
1329        /* end of fix bug 7027946 */
1330 
1331      if (l_logLevel <= wip_constants.full_logging) then
1332           if (l_logLevel <= wip_constants.trace_logging) then
1333           wip_logger.log('*** Shift records after incorporating capacity exceptions ***', l_retStatus);
1334           end if;
1335           for i in 1..l_shifts.shiftNum.count loop
1336             if (l_logLevel <= wip_constants.trace_logging) then
1337             wip_logger.log(l_shifts.shiftNum(i)||' - '||to_char(l_shifts.startDate(i),'DD.MM.YYYY HH24:MI:SS')||' - '||to_char(l_shifts.endDate(i),'DD.MM.YYYY HH24:MI:SS'), l_retStatus);
1338             end if;
1339           end loop;
1340         end if;
1341 
1342      /*Bug 13069474: calling this function to process overlapping shifts*/
1343      process_overlap_shifts(2, x_shifts => l_shifts);
1344       end if;
1345 
1346       for i in 1..l_shifts.shiftNum.count loop
1347         if(l_shifts.endDate(i) < l_shifts.startDate(i)) then --overnight shift
1348            l_shifts.endDate(i) := l_shifts.endDate(i) + 1;
1349         end if;
1350 
1351         if (l_logLevel <= wip_constants.full_logging) then
1352           wip_logger.log('**********shiftNum:' || l_shifts.shiftNum(i), l_retStatus);
1353           wip_logger.log('**shift start date:' || to_char(l_shifts.startDate(i), g_logDateFmt), l_retStatus);
1354           wip_logger.log('****shift end date:' || to_char(l_shifts.endDate(i), g_logDateFmt), l_retStatus);
1355         end if;
1356 
1357         --if shift ends before the requested start date, skip it since none of the shift
1358         --can be used. don't do this in the sql query as it degrades performance
1359         if(l_shifts.endDate(i) <= p_startDate) then
1360           if (l_logLevel <= wip_constants.full_logging) then
1361             wip_logger.log('skipping shift (ends before start date)', l_retStatus);
1362           end if;
1363           goto NO_FULFILL_USAGE;--end of loop
1364         end if;
1365 
1366         --if the shift starts before the start time, adjust the shift length
1367         l_fromDate := greatest(l_shifts.startDate(i), p_startDate);
1368         if (l_logLevel <= wip_constants.full_logging) then
1369           wip_logger.log('calculated start date: ' || to_char(l_fromDate, g_logDateFmt), l_retStatus);
1370         end if;
1371 
1372         l_shiftLen := l_shifts.endDate(i) - l_fromDate;
1373            /*Bug 7015594: If shift start time is same as end time then consider it as 24 hours resource.
1374            This should be only done when 24 hours check is unchecked and resource is not used on repetitive line*/
1375            /*Bug 9355406: fixed regression caused by 7015594, if resource start day is the end of the shift, it wont be treated as 24 hrs resource*/
1376            if(x_resTbls.avail24Flag(p_idx) <> wip_constants.yes AND p_repLineID is null AND l_shifts.startDate(i)=l_shifts.endDate(i)) then
1377                    l_shiftLen := 86400;
1378            end if;
1379 
1380         if (l_logLevel <= wip_constants.full_logging) then
1381           wip_logger.log('shiftLen(HRS) is ' || round(l_shiftLen*24, g_precision), l_retStatus);
1382         end if;
1383 
1384         if(round(l_shiftLen, g_precision) = 0) then
1385           if (l_logLevel <= wip_constants.full_logging) then
1386             wip_logger.log('skipping shift (no usage)', l_retStatus);
1387           end if;
1388           goto NO_FULFILL_USAGE;--end of loop
1389         end if;
1390 
1391 
1392         if(l_startDate is null) then
1393           l_startDate := l_fromDate;
1394           if (l_logLevel <= wip_constants.full_logging) then
1395             wip_logger.log('calculated resource start date:' || to_char(l_startDate, g_logDateFmt), l_retStatus);
1396           end if;
1397         end if;
1398          /*Bug 9355406: fixed regression caused by 7136375. if remaining usage is one day:
1399           for regular resource, consider shift fullfilled resource usage and exit the loop
1400           for 24 hours resource, condiser shift cannot fullfilled resource usage and loop to next working day
1401           */
1402     -- Commented below condition for bug #13388579
1403       --    if(round(l_remUsage, g_precision) < round(l_shiftLen, g_precision) or /* Fix for bug 7136375.If time remaining is one day then we need to loop to next working day*/
1404       --     (round(l_remUsage, g_precision) = round(l_shiftLen, g_precision) and x_resTbls.avail24Flag(p_idx) <> wip_constants.yes)) then
1405           --shift fullfilled resource usage (round to approximately seconds)
1406        /* Bug 13388579 : If there exist a resource of type "next" in backward scheduling then no need to move end date to next working day if its end on non working day
1407              because in backward scheduling we wont move end date to next working day if it end on non working day.
1408           */
1409          if ((g_reset_date=0 and ( (round(l_remUsage, g_precision) < round(l_shiftLen, g_precision)) or
1410            (round(l_remUsage, g_precision) = round(l_shiftLen, g_precision) and x_resTbls.avail24Flag(p_idx) <> wip_constants.yes))) or (g_reset_date=1 and  (round(l_remUsage, g_precision) <= round(l_shiftLen, g_precision)) ) ) then
1411 
1412           if (l_logLevel <= wip_constants.full_logging) then
1413             wip_logger.log('calculated resource start date:' || to_char(l_startDate, g_logDateFmt), l_retStatus);
1414           end if;
1415           x_resTbls.startDate(p_idx) := l_startDate;
1416           x_resTbls.endDate(p_idx) := l_fromDate + l_remUsage;
1417           --record shift usage
1418           x_resTbls.usgStartDate.extend(1);
1419           x_resTbls.usgEndDate.extend(1);
1420           x_resTbls.usgCumMinProcTime.extend(1);
1421 
1422           l_usgIdx := x_resTbls.usgStartDate.count;
1423           if (l_logLevel <= wip_constants.full_logging) then
1424             wip_logger.log('idx is ' || l_usgIdx, l_retStatus);
1425             wip_logger.log('count is ' || x_resTbls.usgStartIdx.count, l_retStatus);
1426             wip_logger.log('val is ' || x_resTbls.usgStartIdx(p_idx), l_retStatus);
1427           end if;
1428 
1429           x_resTbls.usgStartIdx(p_idx) := nvl(x_resTbls.usgStartIdx(p_idx), l_usgIdx);
1430           x_resTbls.usgEndIdx(p_idx) := l_usgIdx;
1431 
1432           x_resTbls.usgStartDate(l_usgIdx) := l_fromDate;
1433 
1434           --shift fulfilled resource => usage end time is resource end time
1435           x_resTbls.usgEndDate(l_usgIdx) := x_resTbls.endDate(p_idx);
1436           if(l_isFirstUsg) then
1437             if (l_logLevel <= wip_constants.full_logging) then
1438               wip_logger.log('first usage', l_retStatus);
1439             end if;
1440             l_isFirstUsg := false;
1441             l_prevProcTime := 0;
1442           else
1443             if (l_logLevel <= wip_constants.full_logging) then
1444               wip_logger.log('not first usage', l_retStatus);
1445             end if;
1446             l_prevProcTime := x_resTbls.usgCumMinProcTime(l_usgIdx - 1);
1447           end if;
1448 
1449           x_resTbls.usgCumMinProcTime(l_usgIdx) := l_prevProcTime +
1450                                                    (24*60)*(x_resTbls.usgEndDate(l_usgIdx) -
1451                                                             x_resTbls.usgStartDate(l_usgIdx));
1452 
1453           if (l_logLevel <= wip_constants.full_logging) then
1454             wip_logger.log('start date is ' || to_char(x_resTbls.startDate(p_idx), g_logDateFmt), l_retStatus);
1455             wip_logger.log('end date is ' || to_char(x_resTbls.endDate(p_idx), g_logDateFmt), l_retStatus);
1456             wip_logger.log('usage:' || to_char(x_resTbls.usgStartDate(l_usgIdx), g_logDateFmt) || ' - ' ||
1457                            to_char(x_resTbls.usgEndDate(l_usgIdx), g_logDateFmt), l_retStatus);
1458             wip_logger.log('cum usage time:' || x_resTbls.usgCumMinProcTime(l_usgIdx), l_retStatus);
1459           end if;
1460 
1461           l_resourceScheduled := true; --exit outer loop
1462           exit; --exit inner loop
1463 
1464         else --shift did not fulfill resource usage
1465           l_remUsage := l_remUsage - l_shiftLen; --decrement remaining time
1466 
1467           --record shift usage
1468           x_resTbls.usgStartDate.extend(1);
1469           x_resTbls.usgEndDate.extend(1);
1470           x_resTbls.usgCumMinProcTime.extend(1);
1471 
1472           l_usgIdx := x_resTbls.usgStartDate.count;
1473           x_resTbls.usgStartIdx(p_idx) := nvl(x_resTbls.usgStartIdx(p_idx), l_usgIdx);
1474           x_resTbls.usgEndIdx(p_idx) := l_usgIdx;
1475 
1476           x_resTbls.usgStartDate(l_usgIdx) := l_fromDate;
1477           --resource consumed until end of the shift
1478           x_resTbls.usgEndDate(l_usgIdx) := l_shifts.endDate(i);
1479 
1480           if(l_isFirstUsg) then
1481             l_prevProcTime := 0;
1482             l_isFirstUsg := false;
1483           else
1484             l_prevProcTime := x_resTbls.usgCumMinProcTime(l_usgIdx - 1);
1485           end if;
1486           x_resTbls.usgCumMinProcTime(l_usgIdx) := l_prevProcTime +
1487                                                    (24*60)*(x_resTbls.usgEndDate(l_usgIdx) -
1488                                                             x_resTbls.usgStartDate(l_usgIdx));
1489           if (l_logLevel <= wip_constants.full_logging) then
1490             wip_logger.log('exhausted shift. remaining usage(HRS) is ' || round(l_remUsage*24, g_precision), l_retStatus);
1491             wip_logger.log('usage:' || to_char(x_resTbls.usgStartDate(l_usgIdx), g_logDateFmt) || ' - ' ||
1492                            to_char(x_resTbls.usgEndDate(l_usgIdx), g_logDateFmt), l_retStatus);
1493             wip_logger.log('cum usage time:' || x_resTbls.usgCumMinProcTime(l_usgIdx), l_retStatus);
1494           end if;
1495         end if;
1496         <<NO_FULFILL_USAGE>>
1497         null;
1498       end loop;
1499 
1500       --if the resource wasn't scheduled, increment the date and keep going.
1501       if(not l_resourceScheduled) then
1502         l_cursorStartDate := l_cursorStartDate + g_dateCursorLen;
1503 
1504         --if the next start date is after the end of the calendar, then we can't schedule anything
1505         if(l_cursorStartDate > p_maxDate) then
1506           if (l_logLevel <= wip_constants.full_logging) then
1507             wip_logger.log('exhausted calendar. remaining usage(HRS) is ' || round(l_remUsage*24, g_precision), l_retStatus);
1508           end if;
1509           fnd_message.set_name('WIP', 'WIP_NO_CALENDAR');
1510           fnd_msg_pub.add;
1511           raise fnd_api.g_exc_unexpected_error;
1512         end if;
1513       end if;
1514     end loop;
1515     if(l_logLevel <= wip_constants.trace_logging) then
1516       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardSchResource',
1517                            p_procReturnStatus => x_returnStatus,
1518                            p_msg              => 'success',
1519                            x_returnStatus     => l_retStatus);
1520     end if;
1521   exception
1522     when fnd_api.g_exc_unexpected_error then
1523       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
1524       if(l_logLevel <= wip_constants.trace_logging) then
1525         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardSchResource',
1526                              p_procReturnStatus => x_returnStatus,
1527                              p_msg              => 'error',
1528                              x_returnStatus     => l_retStatus);
1529       end if;
1530     when others then
1531       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
1532       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
1533                               p_procedure_name => 'forwardSchResource',
1534                               p_error_text => SQLERRM);
1535       if(l_logLevel <= wip_constants.trace_logging) then
1536         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardSchResource',
1537                              p_procReturnStatus => x_returnStatus,
1538                              p_msg              => 'unexp error: ' || SQLERRM,
1539                              x_returnStatus     => l_retStatus);
1540       end if;
1541 
1542   end forwardSchResource;
1543 
1544    /* fix bug 7027946: Added procedure wip_infResSched_grp.capacityExceptions to handle resource capacity exceptions.
1545                        It will change the resource shifts (add day, delete day, modify shift times) as per capacity
1546          exceptions.
1547    */
1548    procedure capacityExceptions(p_resID     IN NUMBER,
1549                                 p_deptID    IN NUMBER,
1550                                 p_orgID     IN NUMBER,
1551                                 x_shifts    IN OUT NOCOPY shift_recTbl_t,
1552            x_returnStatus OUT NOCOPY VARCHAR2) is
1553 
1554     /*bug 10251978 (FP 10086620): Modified the cursor to include capacity_units value from bom_resource_shifts table*/
1555      cursor c_capacityDtls(v_resID  NUMBER,
1556                            v_deptID NUMBER,
1557       v_orgID  NUMBER) is
1558       select  brc.shift_num,
1559               brc.from_date,
1560        brc.to_date,
1561        brc.from_time,
1562        brc.to_time,
1563        brc.capacity_change,
1564        brc.action_type,
1565        brs.capacity_units
1566          from bom_resource_changes brc,
1567        crp_simulation_sets crp,
1568        BOM_RESOURCE_SHIFTS brs
1569         where brc.department_id = v_deptID
1570    and brc.resource_id = v_resID
1571    and crp.organization_id = v_orgID
1572    and crp.simulation_set  =  brc.simulation_set
1573    and crp.use_in_wip_flag = 1
1574    and brs.department_id = v_deptID
1575     and brs.resource_id = v_resID
1576    and brs.shift_num = brc.shift_num;
1577 
1578       --used to collect cursor records...
1579       type  capacity_rec_t  is  record(shiftNum       number,
1580                                        fromDate       date,
1581                                        toDate         date ,
1582            fromTime       number,
1583            toTime         number,
1584            capacityChange number,
1585            actionType     number,
1586         capacityUnits  number);
1587 
1588      type capacity_recTbl_t is table of capacity_rec_t index by binary_integer;
1589 
1590      l_capacity  capacity_recTbl_t ;
1591      l_capacity_2  capacity_recTbl_t ;
1592      l_logLevel NUMBER := fnd_log.g_current_runtime_level;
1593      l_params wip_logger.param_tbl_t;
1594      l_retStatus VARCHAR2(1);
1595 
1596      l_firstRow NUMBER;
1597      l_currRow NUMBER;
1598      l_lastRow NUMBER;
1599      l_prevRow NUMBER;
1600      j NUMBER;
1601      k NUMBER;
1602      flag BOOLEAN;
1603      l_shiftDate DATE;
1604 
1605      l_counter NUMBER;
1606      m Number;
1607      l_previous_row NUMBER;
1608 
1609   l_capFmDate DATE;
1610   l_capToDate DATE;
1611   l_capRecCount Number;
1612   n Number;
1613 
1614    BEGIN
1615 
1616      if (l_logLevel <= wip_constants.trace_logging) then
1617          l_params(1).paramName := 'p_resID';
1618          l_params(1).paramValue := p_resID;
1619          l_params(2).paramName := 'p_deptID';
1620          l_params(2).paramValue := p_deptID;
1621          l_params(3).paramName := 'p_orgID';
1622          l_params(3).paramValue := p_orgID;
1623 
1624         wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.capacityExceptions',
1625                               p_params       => l_params,
1626                               x_returnStatus => x_returnStatus);
1627      end if;
1628 
1629       open c_capacityDtls(v_resID  => p_resID,
1630                           v_deptID => p_deptID,
1631             v_orgID  => p_orgID);
1632       fetch c_capacityDtls
1633         bulk collect into l_capacity ;
1634       close c_capacityDtls;
1635 
1636       if(l_logLevel <= wip_constants.trace_logging) then
1637  wip_logger.log('l_capacity.count = ' || l_capacity.count, l_retStatus);
1638       end if;
1639 
1640 /*Bug 16322124: if there is no capacity exception being found, return and do nothing.
1641                 This will avoid shift being deleted if customer define shift start time and endtime the same as 00:00:00*/
1642       if(l_capacity.count = 0) then
1643          if(l_logLevel <= wip_constants.trace_logging) then
1644             wip_logger.log('No Capacity Exception found. exiting capacity exception', l_retStatus);
1645          end if;
1646          return;
1647       end if;
1648  --------------------
1649  /* This loop is to split the date range (if mentioned in capacity exception record) into multiple records with each single date */
1650      for i in 1..l_capacity.count loop
1651             if ( l_capacity(i).fromDate <> l_capacity(i).toDate ) then
1652                 l_capFmDate := l_capacity(i).fromDate;
1653                 l_capToDate := l_capacity(i).toDate;
1654                 l_capRecCount := l_capToDate - l_capFmDate+1;       -- l_capRecCount records need to be created.
1655 
1656                 l_capToDate := l_capacity(i).fromDate;
1657 
1658                 For j in 1..l_capRecCount loop
1659                     l_capacity_2(NVL(l_capacity_2.last,0)+1) := l_capacity(i);
1660                     l_capacity_2(l_capacity_2.last).fromDate := l_capToDate;
1661                     l_capacity_2(l_capacity_2.last).toDate := l_capToDate;
1662                     l_capToDate := l_capToDate + 1;
1663                 end loop;
1664             ELSE
1665                 l_capacity_2(NVL(l_capacity_2.last,0)+1) := l_capacity(i);
1666             END if;
1667         end loop;
1668 
1669         l_capacity.DELETE;
1670         l_capacity := l_capacity_2;
1671 
1672         l_capacity_2.DELETE;
1673         if (l_logLevel <= wip_constants.trace_logging) then
1674         wip_logger.log('l capacity count is :'||l_capacity.Count, l_retStatus);
1675         end if;
1676   -------------------
1677     for i in 1..l_capacity.count loop
1678     if (l_logLevel <= wip_constants.trace_logging) then
1679      wip_logger.log('****************************modified capacity exception records**************************************', l_retStatus);
1680     wip_logger.log('shiftNum       = ' || l_capacity(i).shiftNum        , l_retStatus);
1681     wip_logger.log('fromDate       = ' || l_capacity(i).fromDate        , l_retStatus);
1682     wip_logger.log('toDate         = ' || l_capacity(i).toDate          , l_retStatus);
1683     wip_logger.log('fromTime       = ' || l_capacity(i).fromTime        , l_retStatus);
1684     wip_logger.log('toTime         = ' || l_capacity(i).toTime          , l_retStatus);
1685     wip_logger.log('capacityChange = ' || l_capacity(i).capacityChange  , l_retStatus);
1686     wip_logger.log('actionType     = ' || l_capacity(i).actionType      , l_retStatus);
1687     wip_logger.log('capacityUnits  = ' || l_capacity(i).capacityUnits   , l_retStatus);
1688     end if;
1689     end loop;
1690     -------------------
1691       for i in 1..l_capacity.count loop   -- outer most loop to loop through all the capacity exception records
1692 
1693           l_firstRow := x_shifts.shiftNum.FIRST;
1694           l_lastRow :=  x_shifts.shiftNum.LAST;
1695           j := l_firstRow;
1696           flag := FALSE;
1697           if(l_logLevel <= wip_constants.trace_logging) then
1698             wip_logger.log('inside for. i = ' || i || ' n count = ' || l_capacity.count, l_retStatus);
1699             wip_logger.log('l_firstRow = ' || l_firstRow, l_retStatus);
1700      wip_logger.log('l_lastRow = ' || l_lastRow, l_retStatus);
1701           end if;
1702           if (l_capacity(i).actionType = wip_constants.DELETE_WKDY) THEN     -- delete a working day
1703     /* If more than one shift exists for a day (in case of shift with breakups) then it will
1704        delete all those shifts for that day. */
1705             if(l_logLevel <= wip_constants.trace_logging) then
1706         wip_logger.log('inside delete a working day', l_retStatus);
1707             end if;
1708             WHILE (j <= l_lastRow) LOOP
1709            /* Changed IF condition to WHILE loop  to delete all the shifts for the given day */
1710            WHILE ( j <= l_lastRow AND Trunc(l_capacity(i).fromDate) = Trunc(x_shifts.startDate(j)) )  LOOP
1711       l_currRow := j;                               -- row that needs to be deleted
1712       k := x_shifts.shiftNum.NEXT(l_currRow);
1713                     WHILE (k <= l_lastRow) LOOP                      -- shift all the rows one-up
1714            x_shifts.shiftNum(l_currRow)  :=  x_shifts.shiftNum(k);
1715            x_shifts.startDate(l_currRow) :=  x_shifts.startDate(k);
1716            x_shifts.endDate(l_currRow)   :=  x_shifts.endDate(k);
1717                          l_currRow := k;
1718                          k := x_shifts.shiftNum.NEXT(k);
1719       END LOOP;
1720 
1721       x_shifts.shiftNum.trim();                   -- trim the last row
1722       x_shifts.startDate.trim();
1723       x_shifts.endDate.trim();
1724                     l_lastRow :=  x_shifts.shiftNum.LAST;        -- updated last row
1725            END LOOP;
1726                   j :=  x_shifts.shiftNum.NEXT(j);
1727      END LOOP;
1728 
1729           ELSIF (l_capacity(i).actionType = wip_constants.ADD_WKDY) THEN         -- add a non-working day
1730             if(l_logLevel <= wip_constants.trace_logging) then
1731        wip_logger.log('inside adding a non-working day', l_retStatus);
1732      end if;
1733 
1734        /* Bug 12627423:  Added extra if statement to check that the fromDate of the capacity exception is bigger
1735        than the first day of xshifts.  */
1736 
1737 
1738           IF ( Trunc(l_capacity(i).fromDate) >= Trunc(x_shifts.startDate(l_firstRow)) ) THEN
1739             WHILE (j <= l_lastRow) LOOP
1740               IF ( Trunc(l_capacity(i).fromDate) < Trunc(x_shifts.startDate(j)) ) THEN     -- add the day just before the shift date
1741                   flag := TRUE;                                                            -- that is greater than the capacity date
1742                   x_shifts.shiftNum.extend;   -- extend the xshifts table by one row and insert the day and then shift remaning days
1743                   x_shifts.startDate.extend;
1744                   x_shifts.endDate.extend;
1745                   l_lastRow :=  x_shifts.shiftNum.LAST;
1746 
1747                   k := l_lastRow;
1748                   l_prevRow := x_shifts.shiftNum.PRIOR(k);         -- now shift all the rows one-down
1749                   WHILE (k <> j) LOOP
1750                       x_shifts.shiftNum(k) := x_shifts.shiftNum(l_prevRow);
1751                       x_shifts.startDate(k) := x_shifts.startDate(l_prevRow);
1752                       x_shifts.endDate(k) := x_shifts.endDate(l_prevRow);
1753                       k := l_prevRow;
1754                       l_prevRow := x_shifts.shiftNum.PRIOR(k);
1755                   END LOOP;
1756 
1757                   x_shifts.shiftNum(j) := l_capacity(i).shiftNum;
1758                   x_shifts.startDate(j) := l_capacity(i).fromDate + l_capacity(i).fromTime/86400;
1759                   x_shifts.endDate(j) := l_capacity(i).fromDate + l_capacity(i).toTime/86400;
1760 
1761                   EXIT WHEN flag = TRUE;
1762               END IF;
1763               j :=  x_shifts.shiftNum.NEXT(j);
1764             END LOOP;
1765           END IF;
1766 
1767         ELSIF l_capacity(i).actionType = wip_constants.MODIFY_WKDY THEN          -- modify capacity - modify or reduce capacity
1768           if(l_logLevel <= wip_constants.trace_logging) then
1769             wip_logger.log('inside modifying capacity', l_retStatus);
1770           end if;
1771           WHILE (j <= l_lastRow) LOOP
1772             l_shiftDate := x_shifts.startDate(j);
1773             if(l_logLevel <= wip_constants.trace_logging) then
1774     wip_logger.log('1: j = ' || j || ' l_lastRow = ' || l_lastRow, l_retStatus);
1775     wip_logger.log('inside while: j = ' || j || ' startDate = ' || to_char(x_shifts.startDate(j),g_logDateFmt), l_retStatus);
1776     wip_logger.log('inside while: j = ' || j || ' fromDate = ' || to_char(l_capacity(i).fromDate,g_logDateFmt), l_retStatus);
1777     wip_logger.log('inside while: j = ' || j || ' toDate = ' || to_char(l_capacity(i).toDate,g_logDateFmt), l_retStatus);
1778             end if;
1779    flag := FALSE;
1780    IF ( Trunc(x_shifts.startDate(j)) >= Trunc(l_capacity(i).fromDate)
1781     AND  Trunc(x_shifts.startDate(j)) <= Trunc(l_capacity(i).toDate) ) THEN
1782 
1783                     k := j;     -- 'k' holds the shift that needs to be modified as per capacity exception
1784         WHILE ( j <= l_lastRow AND Trunc(l_shiftDate) = Trunc(x_shifts.startDate(j)) ) LOOP
1785       IF ( (l_capacity(i).fromDate + l_capacity(i).fromTime/86400) > x_shifts.startDate(j) ) THEN
1786            k := j;
1787       END IF;
1788       j :=  x_shifts.shiftNum.NEXT(j);
1789         END LOOP;
1790      flag := TRUE;  -- to know whether j points to next record or not.
1791 
1792      if j is null then
1793       j := l_lastRow;
1794         end if;
1795         if (l_logLevel <= wip_constants.trace_logging) then
1796      wip_logger.log('After j is null code', l_retStatus);
1797 end if;
1798      IF ( l_capacity(i).capacityChange > 0 ) THEN      -- add capacity
1799      /*Idea here is that if a new capacity is added and one of it's dates matches with shift dates then we adjust shift start
1800      or end time. In all other cases we will add a new time in shift table for the exception to add the new capacity. */
1801       if(l_logLevel <= wip_constants.trace_logging) then
1802        wip_logger.log('ADD capacity', l_retStatus);
1803       end if;
1804       if  (x_shifts.endDate(k) = (l_capacity(i).fromDate + l_capacity(i).fromTime/86400)) then
1805        if(l_logLevel <= wip_constants.trace_logging) then
1806         wip_logger.log('inside IF.1: endDate = ' || to_char(x_shifts.endDate(k), g_logDateFmt), l_retStatus);
1807        end if;
1808        x_shifts.endDate(k) := x_shifts.endDate(k) + ((l_capacity(i).toTime - l_capacity(i).fromTime)/86400 );
1809        if(l_logLevel <= wip_constants.trace_logging) then
1810          wip_logger.log('inside IF.1 endDate = ' || to_char(x_shifts.endDate(k),g_logDateFmt), l_retStatus);
1811          wip_logger.log('inside elseIF.1: startDate = ' || to_char(x_shifts.startDate(k),g_logDateFmt), l_retStatus);
1812        end if;
1813       elsif (x_shifts.startDate(k) = (l_capacity(i).toDate + l_capacity(i).toTime/86400)) then
1814        if(l_logLevel <= wip_constants.trace_logging) then
1815          wip_logger.log('inside elseIF.1: startDate = ' || to_char(x_shifts.startDate(k),g_logDateFmt), l_retStatus);
1816        end if;
1817        x_shifts.startDate(k) := x_shifts.startDate(k) - ((l_capacity(i).toTime - l_capacity(i).fromTime)/86400) ;
1818        if(l_logLevel <= wip_constants.trace_logging) then
1819         wip_logger.log('inside elseIF.1 startDate = ' || to_char(x_shifts.startDate(k),g_logDateFmt), l_retStatus);
1820        end if;
1821       elsif (x_shifts.endDate(k) = x_shifts.startDate(k)) THEN
1822        -- this should only come when user reduce the entire shift capacity
1823        -- after reducing the entire shift capacity, shift start and end date will be same
1824         x_shifts.startDate(k) := (l_capacity(i).fromDate + l_capacity(i).fromTime/86400);
1825         x_shifts.endDate(k)   := (l_capacity(i).toDate + l_capacity(i).toTime/86400);
1826       else
1827              --Fix bug 10632963, only add the shift if the capacity start and end date is not the same
1828               --as shift start date and end date
1829               if((x_shifts.startDate(k) <> (l_capacity(i).fromDate + l_capacity(i).fromTime/86400)) and
1830                  (x_shifts.endDate(k) <> (l_capacity(i).toDate + l_capacity(i).toTime/86400))) then
1831        if(l_logLevel <= wip_constants.trace_logging) then
1832         wip_logger.log('inside else.1:', l_retStatus);
1833        end if;
1834        if (x_shifts.startDate(k) > (l_capacity(i).fromDate + l_capacity(i).fromTime/86400)) then
1835         /* capacity shd be added before the current shift */
1836         l_counter := x_shifts.shiftNum.PRIOR(j);
1837 
1838         if (l_counter IS NULL) then
1839          l_counter := j;
1840         end if;
1841         if(l_logLevel <= wip_constants.trace_logging) then
1842          wip_logger.log('inside else.1: j-1: l_counter = ' || l_counter, l_retStatus);
1843         end if;
1844        else
1845            /* capcacity should be added after the current shift */
1846            l_counter := j;
1847         if(l_logLevel <= wip_constants.trace_logging) then
1848          wip_logger.log('inside else.1: j: l_counter = ' || l_counter, l_retStatus);
1849         end if;
1850        end if;
1851        x_shifts.shiftNum.extend;   -- extend the xshifts table by one row and insert the day and then shift remaning days
1852        x_shifts.startDate.extend;
1853        x_shifts.endDate.extend;
1854        l_lastRow :=  x_shifts.shiftNum.LAST;
1855        m := l_lastRow;
1856        l_previous_row := x_shifts.shiftNum.PRIOR(m);         -- now shift all the rows one-down
1857        WHILE (m <> l_counter) LOOP
1858          x_shifts.shiftNum(m) := x_shifts.shiftNum(l_previous_row);
1859          x_shifts.startDate(m) := x_shifts.startDate(l_previous_row);
1860          x_shifts.endDate(m) := x_shifts.endDate(l_previous_row);
1861          m := l_previous_row;
1862          l_previous_row := x_shifts.shiftNum.PRIOR(m);
1863        END LOOP;
1864        x_shifts.shiftNum(l_counter) := l_capacity(i).shiftNum;
1865        x_shifts.startDate(l_counter) := l_capacity(i).fromDate + l_capacity(i).fromTime/86400;
1866        x_shifts.endDate(l_counter) := l_capacity(i).fromDate + l_capacity(i).toTime/86400;
1867        j :=  x_shifts.shiftNum.NEXT(j); -- need to move shift pointer as current shift is added and j should point to next shift.
1868       end if;
1869            end if;
1870      ELSE                                              -- reduce capacity
1871       if(l_logLevel <= wip_constants.trace_logging) then
1872          wip_logger.log('inside else.2', l_retStatus);
1873          wip_logger.log('capacity units is ' || l_capacity(i).capacityUnits, l_retStatus);
1874       end if;
1875 
1876       /*  Bug 14293561: The below if statement used to compare l_capacity(i).capacityUnits with the abs of l_capacity(i).capacityChange.
1877           capacityUnits seems to be a deprecated column as it was always returning null so flow would always avoid this if-statement
1878        I replaced the if statement with one that will always return true when capacityUnit is null.
1879       */
1880 
1881       if(nvl(l_capacity(i).capacityUnits, 0) <= (abs(l_capacity(i).capacityChange))) THEN
1882        if(l_logLevel <= wip_constants.trace_logging) then
1883         wip_logger.log('inside else.2 capacityChange = ' || l_capacity(i).capacityChange, l_retStatus);
1884         /*Idea here is that if a capacity is reduced and one of it's dates matches with shift dates then we adjust
1885         shift start or end time. In all other cases we will reduce time in shift table for the exception to reduce the new capacity.*/
1886         wip_logger.log('before IF.2: endDate = ' || to_char(x_shifts.endDate(k),g_logDateFmt), l_retStatus);
1887         wip_logger.log('before IF.2: l_cap.toDateTime = ' || to_char(l_capacity(i).toDate + l_capacity(i).toTime/86400,g_logDateFmt), l_retStatus);
1888         wip_logger.log('before IF.2: l_cap.fromDateTime = ' || to_char(l_capacity(i).fromDate + l_capacity(i).fromTime/86400,g_logDateFmt), l_retStatus);
1889        end if;
1890        if x_shifts.endDate(k) = (l_capacity(i).toDate + l_capacity(i).toTime/86400) then
1891         if(l_logLevel <= wip_constants.trace_logging) then
1892            wip_logger.log('inside IF.2: endDate = ' || to_char(x_shifts.endDate(k),g_logDateFmt), l_retStatus);
1893         end if;
1894         x_shifts.endDate(k) := x_shifts.endDate(k) - (l_capacity(i).toTime - l_capacity(i).fromTime)/86400;
1895 
1896         -- after reducing the shift if end time and start time become same then we need to delete this k th shift
1897         /*if (x_shifts.endDate(k) = x_shifts.startDate(k)) THEN
1898          WHILE (k < l_lastRow) LOOP                      -- shift all the rows one-up
1899              m := x_shifts.shiftNum.NEXT(k);
1900           x_shifts.shiftNum(k)  :=  x_shifts.shiftNum(m);
1901           x_shifts.startDate(k) :=  x_shifts.startDate(m);
1902           x_shifts.endDate(k)   :=  x_shifts.endDate(m);
1903           k := m;
1904          END LOOP;
1905          if (l_logLevel <= wip_constants.trace_logging) then
1906          wip_logger.log('inside IF.2-: after while loop', l_retStatus);
1907          end if;
1908          x_shifts.shiftNum.trim();                   -- trim the last row
1909          x_shifts.startDate.trim();
1910          x_shifts.endDate.trim();
1911          if (l_logLevel <= wip_constants.trace_logging) then
1912          wip_logger.log('inside IF.2-: after trim', l_retStatus);
1913          end if;
1914          l_lastRow :=  x_shifts.shiftNum.LAST;        -- updated last row
1915          if (l_logLevel <= wip_constants.trace_logging) then
1916          wip_logger.log('inside IF.2-: after l_lastRow = '||l_lastRow, l_retStatus);
1917          end if;
1918          j :=  x_shifts.shiftNum.PRIOR(j);            -- update j as one shift record is deleted
1919          if (l_logLevel <= wip_constants.trace_logging) then
1920          wip_logger.log('inside IF.2-: after updating j = '||j, l_retStatus);
1921          end if;
1922         end if;*/
1923         --
1924 
1925         if(l_logLevel <= wip_constants.trace_logging) then
1926          wip_logger.log('inside IF.2--: endDate = .... = ', l_retStatus);
1927 
1928         end if;
1929        elsif x_shifts.startDate(k) = (l_capacity(i).fromDate + l_capacity(i).fromTime/86400) then
1930         if(l_logLevel <= wip_constants.trace_logging) then
1931            wip_logger.log('inside ELSEIF.2: endDate = ' || to_char(x_shifts.startDate(k),g_logDateFmt), l_retStatus);
1932         end if;
1933         x_shifts.startDate(k) := x_shifts.startDate(k) + (l_capacity(i).toTime - l_capacity(i).fromTime)/86400 ;
1934         if(l_logLevel <= wip_constants.trace_logging) then
1935          wip_logger.log('inside ELSEIF.2--: endDate = ' || to_char(x_shifts.startDate(k),g_logDateFmt), l_retStatus);
1936         end if;
1937        else
1938         if(l_logLevel <= wip_constants.trace_logging) then
1939            wip_logger.log('inside else.2--: endDate = ' || to_char(x_shifts.endDate(k),g_logDateFmt), l_retStatus);
1940         end if;
1941         -- Split the shift time into two here to reduce capacity.
1942         -- Add  a new record in x_shifts table after Kth record.
1943         -- for new record start date is (l_capacity(i).toDate + l_capacity(i).toTime/86400)
1944         -- end date is x_shifts.endDate(k)
1945         x_shifts.shiftNum.extend;   -- extend the xshifts table by one row and insert the day and then shift remaning days
1946         x_shifts.startDate.extend;
1947         x_shifts.endDate.extend;
1948         l_lastRow :=  x_shifts.shiftNum.LAST;
1949         m := l_lastRow;
1950         l_previous_row := x_shifts.shiftNum.PRIOR(m);         -- now shift all the rows one-down
1951         WHILE (m <> j) LOOP
1952             x_shifts.shiftNum(m) := x_shifts.shiftNum(l_previous_row);
1953          x_shifts.startDate(m) := x_shifts.startDate(l_previous_row);
1954          x_shifts.endDate(m) := x_shifts.endDate(l_previous_row);
1955          m := l_previous_row;
1956          l_previous_row := x_shifts.shiftNum.PRIOR(m);
1957         END LOOP;
1958         x_shifts.shiftNum(j) := l_capacity(i).shiftNum;
1959         x_shifts.startDate(j) := (l_capacity(i).toDate + l_capacity(i).toTime/86400);
1960         x_shifts.endDate(j) := x_shifts.endDate(k);
1961         x_shifts.endDate(k) := (l_capacity(i).fromDate + l_capacity(i).fromTime/86400);
1962         j :=  x_shifts.shiftNum.NEXT(j); -- need to move shift pointer as current shift is added and j should point to next shift
1963        end if;
1964       end if;
1965     END IF;
1966                 --j :=  x_shifts.shiftNum.PRIOR(j);
1967       END IF;
1968    if (flag = FALSE) then
1969     j :=  x_shifts.shiftNum.NEXT(j);
1970    end if;
1971    if ( (j = l_lastRow AND flag = TRUE) OR j IS NULL ) then
1972        exit;
1973    end if;
1974    END LOOP;
1975         END IF;
1976   END LOOP;     -- end outer loop
1977 
1978    -- loop through all the capacity exception records and delete the one with zero shift time
1979     l_firstRow := x_shifts.shiftNum.FIRST;
1980     l_lastRow :=  x_shifts.shiftNum.LAST;
1981  j := 1;
1982  WHILE (j <= l_lastRow) LOOP
1983   k := j;
1984   -- after reducing the shift if end time and start time become same then we need to delete this k th shift
1985   if (x_shifts.endDate(k) = x_shifts.startDate(k)) THEN
1986    WHILE (k < l_lastRow) LOOP                      -- shift all the rows one-up
1987        m := x_shifts.shiftNum.NEXT(k);
1988     x_shifts.shiftNum(k)  :=  x_shifts.shiftNum(m);
1989     x_shifts.startDate(k) :=  x_shifts.startDate(m);
1990     x_shifts.endDate(k)   :=  x_shifts.endDate(m);
1991     k := m;
1992    END LOOP;
1993    x_shifts.shiftNum.trim();                   -- trim the last row
1994    x_shifts.startDate.trim();
1995    x_shifts.endDate.trim();
1996    l_lastRow :=  x_shifts.shiftNum.LAST;        -- updated last row
1997     -- Fix bug 10632963, after we delete the kth shift, we must not move the j position because
1998     -- we need to re-check whether the new shift end date and start date at i position is the same
1999     -- and whether requires deletion or not
2000     else
2001       -- only move the the j position if the shift start date and end date is not the same.
2002     j := j+1;
2003     end if;
2004  end loop;
2005 
2006      IF(l_logLevel <= wip_constants.trace_logging) then
2007       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.capacityExceptions',
2008                            p_procReturnStatus => x_returnStatus,
2009                            p_msg              => 'success',
2010                            x_returnStatus     => l_retStatus);
2011      END IF;
2012    EXCEPTION
2013       WHEN fnd_api.g_exc_unexpected_error THEN
2014          x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2015          if(l_logLevel <= wip_constants.trace_logging) then
2016          wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.capacityExceptions',
2017                               p_procReturnStatus => x_returnStatus,
2018                               p_msg              => 'error',
2019                               x_returnStatus     => l_retStatus);
2020       end if;
2021       WHEN others  THEN
2022          x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2023   fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
2024                   p_procedure_name => 'capacityExceptions',
2025             p_error_text => SQLERRM);
2026          if(l_logLevel <= wip_constants.trace_logging) then
2027     wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.capacityExceptions',
2028                     p_procReturnStatus => x_returnStatus,
2029            p_msg              => 'unexp error: ' || SQLERRM,
2030            x_returnStatus     => l_retStatus);
2031   end if;
2032    END capacityExceptions;
2033    /* end of fix bug 7027946 */
2034 
2035   procedure forwardSchedule(p_orgID        IN number,
2036                             p_repLineID    in NUMBER := null,
2037                             p_startDate    in DATE,
2038                             p_range        in num_tbl_t,
2039                             p_schedFlag    in number,
2040                             x_resTbls      in out NOCOPY OP_RES_RECTBL_T,
2041                             x_returnStatus OUT NOCOPY VARCHAR2) is
2042     l_resStartDate DATE;  -- := p_startDate;
2043     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
2044     l_params wip_logger.param_tbl_t;
2045     l_retStatus VARCHAR2(1);
2046     l_fromTime NUMBER;
2047     l_maxDate DATE;
2048     l_shiftStartDate DATE;
2049     l_currSchedSeqNum NUMBER;
2050     l_prevResIdx NUMBER;
2051     i number;
2052     l_schedulingBatch boolean := false;
2053     l_doneSchedBatch boolean;
2054   begin
2055     if (l_logLevel <= wip_constants.trace_logging) then
2056       l_params(1).paramName := 'p_repLineID';
2057       l_params(1).paramValue := p_repLineID;
2058       l_params(2).paramName := 'p_startDate';
2059       l_params(2).paramValue := to_char(p_startDate, g_logDateFmt);
2060       l_params(3).paramName := 'p_range(1)';
2061       l_params(3).paramValue := p_range(1);
2062       l_params(4).paramName := 'p_range(2)';
2063       l_params(4).paramValue := p_range(2);
2064       l_params(5).paramName := 'p_schedFlag';
2065       l_params(5).paramValue := p_schedFlag;
2066 
2067       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.forwardSchedule',
2068                             p_params       => l_params,
2069                             x_returnStatus => x_returnStatus);
2070     end if;
2071     --get the maximum date
2072     select bc.calendar_end_date
2073       into l_maxDate
2074       from bom_calendars bc, mtl_parameters mp
2075      where mp.organization_id = p_orgID
2076        and mp.calendar_code = bc.calendar_code;
2077 
2078     while(getNextResIdx(p_range, p_schedFlag, g_forward, x_resTbls, i)) loop
2079       if (l_logLevel <= wip_constants.full_logging) then
2080         wip_logger.log('begin scheduling resource:' || x_resTbls.resID(i), l_retStatus);
2081         wip_logger.log('                operation:' || x_resTbls.opSeqNum(i), l_retStatus);
2082         wip_logger.log('              res seq num:' || x_resTbls.resSeqNum(i), l_retStatus);
2083         wip_logger.log('         schedule seq num:' || x_resTbls.schedSeqNum(i), l_retStatus);
2084         wip_logger.log('               sched flag:' || x_resTbls.schedFlag(i), l_retStatus);
2085         wip_logger.log('        total usage (HRS):' || round(x_resTbls.totalDaysUsg(i)*24, g_precision), l_retStatus);
2086 
2087         if(l_prevResIdx is not null) then
2088           wip_logger.log('prev sched seq num is:' || x_resTbls.schedSeqNum(l_prevResIdx), l_retStatus);
2089           wip_logger.log('prev op seq num is:' || x_resTbls.opSeqNum(l_prevResIdx), l_retStatus);
2090         end if;
2091       end if;
2092 
2093       l_doneSchedBatch := false;
2094       --scheduling simultaneous
2095       if(l_prevResIdx is not null and
2096          x_resTbls.schedSeqNum(i) = x_resTbls.schedSeqNum(l_prevResIdx) and
2097          x_resTbls.opSeqNum(i) = x_resTbls.opSeqNum(l_prevResIdx)) then
2098         l_schedulingBatch := true;
2099         if (l_logLevel <= wip_constants.full_logging) then
2100           wip_logger.log('setting sched batch to true', l_retStatus);
2101         end if;
2102       --just finished scheduling batch
2103       elsif(l_schedulingBatch) then
2104         l_schedulingBatch := false;
2105         l_doneSchedBatch := true;
2106         if (l_logLevel <= wip_constants.full_logging) then
2107           wip_logger.log('setting done sched batch to true', l_retStatus);
2108         end if;
2109       end if;
2110 
2111 
2112       if(l_prevResIdx is null) then
2113         l_resStartDate := p_startDate;
2114 
2115       --if scheduling simultaneous, no need to get new start date, just use the previous start date
2116       elsif(not l_schedulingBatch) then
2117         l_resStartDate := getStartDate(p_range, p_schedFlag, x_resTbls, i, l_doneSchedBatch, l_prevResIdx);
2118       end if;
2119 
2120       forwardSchResource(p_orgID, l_resStartDate, l_maxDate, i, p_repLineID, x_resTbls, x_returnStatus);
2121       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
2122         raise fnd_api.g_exc_unexpected_error;
2123       end if;
2124 
2125       l_prevResIdx := i;
2126     end loop;
2127 
2128     if(l_logLevel <= wip_constants.trace_logging) then
2129       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardSchedule',
2130                            p_procReturnStatus => x_returnStatus,
2131                            p_msg              => 'success',
2132                            x_returnStatus     => l_retStatus);
2133     end if;
2134   exception
2135     when fnd_api.g_exc_unexpected_error then
2136       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2137       if(l_logLevel <= wip_constants.trace_logging) then
2138         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardSchedule',
2139                              p_procReturnStatus => x_returnStatus,
2140                              p_msg              => 'error',
2141                              x_returnStatus     => l_retStatus);
2142       end if;
2143     when others then
2144       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2145       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
2146                               p_procedure_name => 'forwardSchedule',
2147                               p_error_text => SQLERRM);
2148       if(l_logLevel <= wip_constants.trace_logging) then
2149         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardSchedule',
2150                              p_procReturnStatus => x_returnStatus,
2151                              p_msg              => 'unexp error: ' || SQLERRM,
2152                              x_returnStatus     => l_retStatus);
2153       end if;
2154   end forwardSchedule;
2155 
2156   -- the resource could have been scheduled from
2157   function getEndDate(p_range in num_tbl_t,
2158                       p_schedFlag in number,
2159                       p_resTbls in op_res_rectbl_t,
2160                       p_curIdx in number,
2161                       p_doneSchedBatch in boolean,
2162                       p_prevIdx in number) return date is
2163     l_retStatus VARCHAR2(1);
2164     l_params wip_logger.param_tbl_t;
2165     i number;
2166     l_minStartDate date;
2167     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
2168     l_bool boolean;
2169   begin
2170     if (l_logLevel <= wip_constants.trace_logging) then
2171       l_params(1).paramName := 'p_range(1)';
2172       l_params(1).paramValue := p_range(1);
2173       l_params(2).paramName := 'p_range(2)';
2174       l_params(2).paramValue := p_range(2);
2175       l_params(3).paramName := 'p_schedFlag';
2176       l_params(3).paramValue := p_schedFlag;
2177       l_params(4).paramName := 'p_curIdx';
2178       l_params(4).paramValue := p_curIdx;
2179       l_params(5).paramName := 'p_doneSchedBatch';
2180       if(p_doneSchedBatch) then l_params(5).paramValue := 'true';
2181       else l_params(5).paramValue := 'false';
2182       end if;
2183       l_params(6).paramName := 'p_prevIdx';
2184       l_params(6).paramValue := p_prevIdx;
2185 
2186       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.getEndDate',
2187                             p_params       => l_params,
2188                             x_returnStatus => l_retStatus);
2189     end if;
2190 
2191     --in case we just got done scheduling a batch of simultaneous resources, get the
2192     --latest end date to use as the next resource's start date
2193     i := p_curIdx;
2194 
2195     if(p_doneSchedBatch) then
2196       if(l_logLevel <= wip_constants.full_logging) then
2197         wip_logger.log('done scheduling batch', l_retStatus);
2198       end if;
2199       while(getNextResIdx(p_range, p_schedFlag, g_forward, p_resTbls, i)) loop
2200         if(l_logLevel <= wip_constants.full_logging) then
2201           wip_logger.log('in loop', l_retStatus);
2202           wip_logger.log('resID' || p_resTbls.resID(i), l_retStatus);
2203           wip_logger.log('opSeq' || p_resTbls.opSeqNum(i), l_retStatus);
2204           wip_logger.log('schSeq' || p_resTbls.schedSeqNum(i), l_retStatus);
2205           wip_logger.log('idx' || i, l_retStatus);
2206         end if;
2207         if(p_resTbls.schedSeqNum(i) = p_resTbls.schedSeqNum(p_prevIdx) and
2208            p_resTbls.opSeqNum(i) = p_resTbls.opSeqNum(p_prevIdx)) then
2209           l_minStartDate := least(nvl(l_minStartDate, p_resTbls.startDate(i)), p_resTbls.startDate(i));
2210           if(l_logLevel <= wip_constants.full_logging) then
2211             wip_logger.log('resource in batch. startDate:' || to_char(p_resTbls.startDate(i), g_logDateFmt), l_retStatus);
2212           end if;
2213         else
2214           if(l_logLevel <= wip_constants.full_logging) then
2215             wip_logger.log('resource not in batch.', l_retStatus);
2216           end if;
2217           exit;
2218         end if;
2219       end loop;
2220     else
2221       l_bool := (getNextResIdx(p_range, p_schedFlag, g_forward, p_resTbls, i));
2222       l_minStartDate := p_resTbls.startDate(i);
2223     end if;
2224 
2225     if (l_logLevel <= wip_constants.trace_logging) then
2226       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.getEndDate',
2227                            p_procReturnStatus => to_char(l_minStartDate),
2228                            p_msg              => 'finished scheduling',
2229                            x_returnStatus     => l_retStatus);
2230     end if;
2231     return l_minStartDate;
2232   end getEndDate;
2233 
2234   procedure backwardSchResource(p_orgID in number,
2235                                 p_endDate in date,
2236                                 p_minDate in date,
2237                                 p_idx in number,
2238                                 p_repLineID in number := null,
2239                                 x_resTbls in out nocopy op_res_rectbl_t,
2240                                 x_returnStatus out nocopy varchar2) is
2241 
2242     cursor c_shiftTimes(v_resID NUMBER,
2243                         v_deptID NUMBER,
2244                         v_orgID NUMBER,
2245                         v_startDate DATE,
2246                         v_endDate DATE) is
2247       select brs.shift_num shiftNum,
2248              bsd.shift_date + bst.from_time/86400,
2249 	     --added the below case statement for bug 16481026.
2250 	     -- This fix is to consider the resource scheduled from 00:00:00 to 00:00:00 properly
2251 	     -- to ensure that the start time and end time for such resource are not same.
2252 	     CASE WHEN (bst.to_time = bst.from_time or bst.to_time < bst.from_time)
2253               THEN bsd.shift_date + bst.to_time/86400 + 1
2254              ELSE
2255               bsd.shift_date + bst.to_time/86400
2256              END
2257              --bsd.shift_date + bst.to_time/86400
2258         from bom_resource_shifts brs,
2259              mtl_parameters mp,
2260              bom_shift_dates bsd,
2261              bom_shift_times bst,
2262              bom_department_resources bdr
2263        where bdr.department_id = v_deptID
2264          and bdr.resource_id = v_resID
2265          and brs.resource_id = bdr.resource_id
2266          and brs.department_id = nvl(bdr.share_from_dept_id,bdr.department_id)
2267          and mp.organization_id = v_orgID
2268          and mp.calendar_code = bsd.calendar_code
2269          and mp.calendar_exception_set_id = bsd.exception_set_id
2270          and brs.shift_num = bsd.shift_num
2271          and bsd.shift_date between v_startDate and v_endDate --don't incorporate time into this check as it slows the query
2272          and bsd.seq_num is not null
2273          and bst.shift_num = bsd.shift_num
2274          and bst.calendar_code = bsd.calendar_code
2275        order by bsd.shift_date desc, bst.from_time desc;
2276 
2277     cursor c_24HrTimes(v_orgID NUMBER,
2278                        v_startDate DATE,
2279                        v_endDate DATE) is
2280       select -1,
2281              bcd.calendar_date,
2282              bcd.calendar_date + 1
2283         from mtl_parameters mp,
2284              bom_calendar_dates bcd
2285        where mp.organization_id = v_orgID
2286          and mp.calendar_code = bcd.calendar_code
2287          and mp.calendar_exception_set_id = bcd.exception_set_id
2288          and bcd.calendar_date between v_startDate and v_endDate
2289          and bcd.seq_num is not null
2290        order by bcd.calendar_date desc;
2291 
2292 
2293       --for repetitive, ignore shifts and use the line's start and stop times. However, do
2294       --respect the working days definition
2295       cursor c_repTimes(v_repLineID NUMBER,
2296                         v_orgID NUMBER,
2297                         v_startDate DATE,
2298                         v_endDate DATE) is
2299       select -1 shiftNum,
2300              bcd.calendar_date + wl.start_time/86400,
2301              bcd.calendar_date + wl.stop_time/86400
2302         from mtl_parameters mp,
2303              bom_calendar_dates bcd,
2304              wip_lines wl
2305        where mp.organization_id = v_orgID
2306          and mp.calendar_code = bcd.calendar_code
2307          and mp.calendar_exception_set_id = bcd.exception_set_id
2308          and wl.line_id = v_repLineID
2309          and bcd.seq_num is not null --working day
2310          and bcd.calendar_date between v_startDate and v_endDate --use stop_time to comsume tail end of a shift
2311        order by bcd.calendar_date desc;
2312 
2313      --used to collect cursor records...
2314      /*type shift_recTbl_t is record(shiftNum num_tbl_t,
2315                                    startDate date_tbl_t,
2316                                    endDate date_tbl_t);*/
2317 
2318     l_shifts shift_recTbl_t;
2319     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
2320     l_params wip_logger.param_tbl_t;
2321     l_retStatus VARCHAR2(1);
2322     l_resourceScheduled boolean := false;
2323     l_cursorEndDate date := p_endDate;
2324     l_shiftEndDate date;
2325     l_toDate DATE;
2326     l_shiftLen NUMBER;
2327     l_remUsage NUMBER := x_resTbls.totalDaysUsg(p_idx);
2328     l_usgIdx NUMBER;
2329     i number;
2330     j number;
2331     l_tmpUsgStartDate date;
2332     l_tmpUsgEndDate date;
2333     l_endDate date;
2334     l_prevProcTime NUMBER := 0;
2335     l_dummy NUMBER; /* Bug 5660475 */
2336   begin
2337 
2338     if (l_logLevel <= wip_constants.trace_logging) then
2339       l_params(1).paramName := 'p_orgID';
2340       l_params(1).paramValue := p_orgID;
2341       l_params(2).paramName := 'p_endDate';
2342       l_params(2).paramValue := to_char(p_endDate, g_logDateFmt);
2343       l_params(3).paramName := 'p_minDate';
2344       l_params(3).paramValue := to_char(p_minDate, g_logDateFmt);
2345       l_params(4).paramName := 'p_idx';
2346       l_params(4).paramValue := p_idx;
2347       l_params(5).paramName := 'p_repLineID';
2348       l_params(5).paramValue := p_repLineID;
2349       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.backwardSchResource',
2350                             p_params       => l_params,
2351                             x_returnStatus => l_retStatus);
2352     end if;
2353      /* Fix for bug 5660475: If dealing with shift resource, first check if shifts are setup fine. */
2354     -- Bug 16322124 . Modified for Performance. Validation is simplified since all shifts are assumed to have valid time setups .
2355     if( p_repLineID is null
2356         and x_resTbls.avail24Flag(p_idx) = wip_constants.no
2357    and x_resTbls.schedFlag(p_idx) <> wip_constants.sched_no) then
2358    if (l_logLevel <= wip_constants.trace_logging) then
2359   wip_logger.log('This is a shift resource. Need to validate shift setup', l_retStatus);
2360   end if;
2361   begin
2362     -- Bug 16322124 . Modified for Performance.
2363     select 1
2364     into l_dummy
2365     from dual
2366     where exists (select 1
2367                     from bom_resource_shifts brs,
2368                          bom_department_resources bdr
2369                    where bdr.department_id = x_resTbls.deptID(p_idx)
2370                      and bdr.resource_id = x_resTbls.resID(p_idx)
2371                      and brs.resource_id = bdr.resource_id
2372                      and brs.department_id = nvl(bdr.share_from_dept_id,bdr.department_id)
2373                      and brs.shift_num is not null
2374                      and rownum = 1);
2375   exception
2376      when NO_DATA_FOUND then
2377         if (l_logLevel <= wip_constants.trace_logging) then
2378         wip_logger.log('Error: Missing shifts or shift times!', l_retStatus);
2379         end if;
2380         fnd_message.set_name('WIP', 'WIP_SHIFT_RESOURCE');
2381         fnd_message.set_token('ENTITY1', x_resTbls.resSeqNum(p_idx));
2382         fnd_message.set_token('ENTITY2', x_resTbls.opSeqNum(p_idx));
2383         fnd_msg_pub.add;
2384         raise fnd_api.g_exc_unexpected_error;
2385   end;
2386     end if;
2387 
2388     x_resTbls.usgStartIdx(p_idx) := null;
2389     x_resTbls.usgEndIdx(p_idx) := null;
2390 
2391     loop
2392       exit when l_resourceScheduled;
2393       if (l_logLevel <= wip_constants.full_logging) then
2394         wip_logger.log('cursor start date: ' || to_char((l_cursorEndDate - (g_dateCursorLen - 1/86400)), g_logDateFmt), l_retStatus);
2395         wip_logger.log('cursor end date: ' || to_char(l_cursorEndDate, g_logDateFmt), l_retStatus);
2396       end if;
2397 
2398       --for v_endDate, subtract a second to avoid overlap between cursors.
2399       if(p_repLineID is not null) then
2400       if (l_logLevel <= wip_constants.trace_logging) then
2401   wip_logger.log('Using c_repTimes', l_retStatus);
2402   end if;
2403         open c_repTimes(v_repLineID => p_repLineID,
2404                         v_orgID     => p_orgID,
2405                         v_startDate => l_cursorEndDate - (g_dateCursorLen - 1/86400),
2406                         v_endDate   => l_cursorEndDate);
2407         fetch c_repTimes
2408           bulk collect into l_shifts.shiftNum,
2409                             l_shifts.startDate,
2410                             l_shifts.endDate;
2411         close c_repTimes;
2412       elsif(x_resTbls.avail24Flag(p_idx) = wip_constants.yes) then
2413       if (l_logLevel <= wip_constants.trace_logging) then
2414     wip_logger.log('Using c_24HrTimes', l_retStatus);
2415     end if;
2416         open c_24HrTimes(v_orgID     => p_orgID,
2417                          v_startDate => l_cursorEndDate - (g_dateCursorLen - 1/86400),
2418                          v_endDate   => l_cursorEndDate);
2419         fetch c_24HrTimes
2420           bulk collect into l_shifts.shiftNum,
2421                             l_shifts.startDate,
2422                             l_shifts.endDate;
2423         close c_24HrTimes;
2424       else
2425       if (l_logLevel <= wip_constants.trace_logging) then
2426   wip_logger.log('Using c_shiftTimes', l_retStatus);
2427   end if;
2428         open c_shiftTimes(v_resID     => x_resTbls.resID(p_idx),
2429                           v_deptID    => x_resTbls.deptID(p_idx),
2430                           v_orgID     => p_orgID,
2431                           v_startDate => l_cursorEndDate - (g_dateCursorLen - 1/86400),
2432                           v_endDate   => l_cursorEndDate);
2433         fetch c_shiftTimes
2434           bulk collect into l_shifts.shiftNum,
2435                             l_shifts.startDate,
2436                             l_shifts.endDate;
2437 
2438         if (l_shifts.shiftNum.count = 0 ) then
2439           /* Fix for bug 5660475: If shifts are not available in the date range,
2440     we should continue to search in the next date range, instead of erroring out. */
2441     if (l_logLevel <= wip_constants.trace_logging) then
2442    wip_logger.log('No shifts found in this period.', l_retStatus);
2443    end if;
2444           l_resourceScheduled := false;
2445         end if;
2446 
2447         close c_shiftTimes;
2448   /*Bug 13069474: calling this function to process overlapping shifts*/
2449      process_overlap_shifts(1, x_shifts => l_shifts);
2450       end if;
2451 
2452 
2453       for i in 1..l_shifts.shiftNum.count loop
2454         if(l_shifts.endDate(i) < l_shifts.startDate(i)) then --overnight shift
2455           l_shifts.endDate(i) := l_shifts.endDate(i) + 1;
2456         end if;
2457         if (l_logLevel <= wip_constants.full_logging) then
2458 
2459           wip_logger.log('**********shiftNum:' || l_shifts.shiftNum(i), l_retStatus);
2460           wip_logger.log('**shift start date:' || to_char(l_shifts.startDate(i), g_logDateFmt), l_retStatus);
2461           wip_logger.log('****shift end date:' || to_char(l_shifts.endDate(i), g_logDateFmt), l_retStatus);
2462         end if;
2463 
2464         --if shift starts after the requested end date, skip it since none of the shift
2465         --can be used. don't do this in the sql query as it degrades performance
2466         if(l_shifts.startDate(i) > p_endDate) then
2467           if (l_logLevel <= wip_constants.full_logging) then
2468             wip_logger.log('skipping shift (starts after end date)', l_retStatus);
2469           end if;
2470           goto NO_FULFILL_USAGE;--end of loop
2471         end if;
2472 
2473         --if the shift ends before the end time, adjust the shift length
2474         l_toDate := least(l_shifts.endDate(i), p_endDate);
2475         if (l_logLevel <= wip_constants.full_logging) then
2476           wip_logger.log('calculated end date: ' || to_char(l_toDate, g_logDateFmt), l_retStatus);
2477         end if;
2478 
2479         l_shiftLen := l_toDate - l_shifts.startDate(i);
2480    /*Bug 7015594: If shift start time is same as end time then consider it as 24 hours resource.
2481            This should be only done when 24 hours check is unchecked and resource is not used on repetitive line*/
2482           /*Bug 9355406: fixed regression caused by 7015594, if resource completion date  is the beginning of the shift, it wont be treated as 24 hrs resource*/
2483           if(x_resTbls.avail24Flag(p_idx) <> wip_constants.yes AND p_repLineID is null AND l_shifts.startDate(i)=l_shifts.endDate(i)) then
2484                    l_shiftLen := 86400;
2485            end if;
2486 
2487 
2488         if (l_logLevel <= wip_constants.full_logging) then
2489           wip_logger.log('shiftLen(HRS) is ' || round(l_shiftLen*24, g_precision), l_retStatus);
2490         end if;
2491 
2492         if(round(l_shiftLen, g_precision) = 0) then
2493           if (l_logLevel <= wip_constants.full_logging) then
2494             wip_logger.log('skipping shift (no usage)', l_retStatus);
2495           end if;
2496           goto NO_FULFILL_USAGE;--end of loop
2497         end if;
2498 
2499 
2500         if(l_endDate is null) then
2501           l_endDate := l_toDate;
2502           if (l_logLevel <= wip_constants.full_logging) then
2503             wip_logger.log('calculated resource end date:' || to_char(l_endDate, g_logDateFmt), l_retStatus);
2504           end if;
2505         end if;
2506 
2507         if(round(l_remUsage, g_precision) <= round(l_shiftLen, g_precision)) then
2508           --shift fullfilled resource usage (round to approximately seconds)
2509 
2510           x_resTbls.startDate(p_idx) := l_toDate - l_remUsage;
2511           x_resTbls.endDate(p_idx) := l_endDate;
2512 
2513           --record shift usage
2514           x_resTbls.usgStartDate.extend(1);
2515           x_resTbls.usgEndDate.extend(1);
2516           x_resTbls.usgCumMinProcTime.extend(1);
2517 
2518           l_usgIdx := x_resTbls.usgStartDate.count;
2519           if (l_logLevel <= wip_constants.full_logging) then
2520             wip_logger.log('start idx is ' || x_resTbls.usgStartIdx(p_idx), l_retStatus);
2521             wip_logger.log('end idx is ' || x_resTbls.usgEndIdx(p_idx), l_retStatus);
2522             wip_logger.log('usg idx is ' || l_usgIdx, l_retStatus);
2523           end if;
2524           x_resTbls.usgStartIdx(p_idx) := nvl(x_resTbls.usgStartIdx(p_idx), l_usgIdx);
2525           x_resTbls.usgEndIdx(p_idx) := l_usgIdx;
2526 
2527 
2528           --shift fulfilled resource => usage start time is resource end time
2529           x_resTbls.usgStartDate(l_usgIdx) := x_resTbls.startDate(p_idx);
2530           x_resTbls.usgEndDate(l_usgIdx) := l_toDate;--l_shifts.endDate(i);
2531 
2532           if (l_logLevel <= wip_constants.full_logging) then
2533             wip_logger.log('start date is ' || to_char(x_resTbls.startDate(p_idx), g_logDateFmt), l_retStatus);
2534             wip_logger.log('end date is ' || to_char(x_resTbls.endDate(p_idx), g_logDateFmt), l_retStatus);
2535             wip_logger.log('usgIdx:' || l_usgIdx, l_retStatus);
2536             wip_logger.log('usage:' || to_char(x_resTbls.usgStartDate(l_usgIdx), g_logDateFmt) || ' - ' ||
2537                            to_char(x_resTbls.usgEndDate(l_usgIdx), g_logDateFmt), l_retStatus);
2538           end if;
2539 
2540           l_resourceScheduled := true; --exit outer loop
2541           exit; --exit inner loop
2542 
2543         else --shift did not fulfill resource usage
2544           l_remUsage := l_remUsage - l_shiftLen; --decrement remaining time
2545 
2546           --record shift usage
2547           x_resTbls.usgStartDate.extend(1);
2548           x_resTbls.usgEndDate.extend(1);
2549           x_resTbls.usgCumMinProcTime.extend(1);
2550           l_usgIdx := x_resTbls.usgStartDate.count;
2551 
2552           x_resTbls.usgStartIdx(p_idx) := nvl(x_resTbls.usgStartIdx(p_idx), l_usgIdx);
2553           x_resTbls.usgEndIdx(p_idx) := l_usgIdx;
2554 
2555           x_resTbls.usgStartDate(l_usgIdx) := l_shifts.startDate(i);
2556           --resource consumed until end of the shift
2557           x_resTbls.usgEndDate(l_usgIdx) := l_toDate;
2558 
2559           if (l_logLevel <= wip_constants.full_logging) then
2560             wip_logger.log('exhausted shift. remaining usage(HRS) is ' || round(l_remUsage*24, g_precision), l_retStatus);
2561             wip_logger.log('usage:' || to_char(x_resTbls.usgStartDate(l_usgIdx), g_logDateFmt) || ' - ' ||
2562                            to_char(x_resTbls.usgEndDate(l_usgIdx), g_logDateFmt), l_retStatus);
2563             wip_logger.log('usgIdx:' || l_usgIdx, l_retStatus);
2564           end if;
2565         end if;
2566         <<NO_FULFILL_USAGE>>
2567         null;
2568       end loop;
2569 
2570       --if the resource wasn't scheduled, increment the date and keep going.
2571       if(not l_resourceScheduled) then
2572         l_cursorEndDate := l_cursorEndDate - g_dateCursorLen;
2573 
2574         --if the next start date is after the end of the calendar, then we can't schedule anything
2575         if(l_cursorEndDate < p_minDate) then
2576           if (l_logLevel <= wip_constants.full_logging) then
2577             wip_logger.log('exhausted calendar. remaining usage(HRS) is ' || round(l_remUsage*24, g_precision), l_retStatus);
2578           end if;
2579           fnd_message.set_name('WIP', 'WIP_NO_CALENDAR');
2580           fnd_msg_pub.add;
2581           raise fnd_api.g_exc_unexpected_error;
2582         end if;
2583       end if;
2584     end loop;
2585 
2586     --resource usages are in reverse chronological order. Flip them so they go start to end.
2587     i := x_resTbls.usgStartIdx(p_idx);
2588     j := x_resTbls.usgEndIdx(p_idx);
2589     if (l_logLevel <= wip_constants.full_logging) then
2590       wip_logger.log('i: ' || i || '; j: ' || j, l_retStatus);
2591     end if;
2592 
2593     while(j > i) loop
2594       l_tmpUsgStartDate := x_resTbls.usgStartDate(j);
2595       l_tmpUsgEndDate := x_resTbls.usgEndDate(j);
2596       x_resTbls.usgStartDate(j) := x_resTbls.usgStartDate(i);
2597       x_resTbls.usgEndDate(j) := x_resTbls.usgEndDate(i);
2598       x_resTbls.usgStartDate(i) := l_tmpUsgStartDate;
2599       x_resTbls.usgEndDate(i) := l_tmpUsgEndDate;
2600       j := j-1;
2601       i := i+1;
2602     end loop;
2603     for i in x_resTbls.usgStartIdx(p_idx)..x_resTbls.usgEndIdx(p_idx) loop
2604       x_resTbls.usgCumMinProcTime(i) := l_prevProcTime + (24*60)*(x_resTbls.usgEndDate(i)-x_resTbls.usgStartDate(i));
2605       l_prevProcTime := x_resTbls.usgCumMinProcTime(i);
2606     end loop;
2607 
2608     if(l_logLevel <= wip_constants.trace_logging) then
2609       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.backwardSchResource',
2610                            p_procReturnStatus => null,
2611                            p_msg              => 'success',
2612                            x_returnStatus     => l_retStatus);
2613     end if;
2614   exception
2615     when fnd_api.g_exc_unexpected_error then
2616       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2617       if(l_logLevel <= wip_constants.trace_logging) then
2618         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.backwardSchResource',
2619                              p_procReturnStatus => x_returnStatus,
2620                              p_msg              => 'error',
2621                              x_returnStatus     => l_retStatus);
2622       end if;
2623     when others then
2624       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2625       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
2626                               p_procedure_name => 'backwardSchResource',
2627                               p_error_text => SQLERRM);
2628 
2629       if(l_logLevel <= wip_constants.trace_logging) then
2630         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.backwardSchResource',
2631                              p_procReturnStatus => x_returnStatus,
2632                              p_msg              => 'unexp error:' || SQLERRM,
2633                              x_returnStatus     => l_retStatus);
2634       end if;
2635   end backwardSchResource;
2636 
2637   procedure forwardScheduleBatch(p_orgID in number,
2638                                  p_repLineID in number,
2639                                  p_range in num_tbl_t,
2640                                  p_schedFlag in number,
2641                                  p_startIdx in number,
2642                                  x_resTbls in out nocopy op_res_rectbl_t,
2643                                  x_returnStatus out nocopy varchar2) is
2644     j number;
2645     l_minStartDate DATE;
2646     l_logLevel number := fnd_log.g_current_runtime_level;
2647     l_params wip_logger.param_tbl_t;
2648     l_retStatus VARCHAR2(1);
2649   begin
2650     if (l_logLevel <= wip_constants.trace_logging) then
2651       l_params(1).paramName := 'p_orgID';
2652       l_params(1).paramValue := p_orgID;
2653       l_params(2).paramName := 'p_repLineID';
2654       l_params(2).paramValue := p_repLineID;
2655       l_params(3).paramName := 'p_range(1)';
2656       l_params(3).paramValue := p_range(1);
2657       l_params(4).paramName := 'p_range(2)';
2658       l_params(4).paramValue := p_range(2);
2659       l_params(5).paramName := 'p_schedFlag';
2660       l_params(5).paramValue := p_schedFlag;
2661       l_params(6).paramName := 'p_startIdx';
2662       l_params(6).paramValue := p_startIdx;
2663 
2664       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.forwardScheduleBatch',
2665                             p_params       => l_params,
2666                             x_returnStatus => x_returnStatus);
2667     end if;
2668 
2669     j := p_startIdx;
2670     l_minStartDate := x_resTbls.startDate(p_startIdx);
2671     --now find the min start date in the simultaneous batch and forward schedule
2672     --all resources in the batch from that point.
2673     while(getNextResIdx(p_range, p_schedFlag, g_forward, x_resTbls, j)) loop
2674       if(x_resTbls.schedSeqNum(j) = x_resTbls.schedSeqNum(p_startIdx) and
2675          x_resTbls.opSeqNum(j) = x_resTbls.opSeqNum(p_startIdx)) then
2676         --calculate min start date
2677         l_minStartDate := least(l_minStartDate, x_resTbls.startDate(j));
2678         if(l_logLevel <= wip_constants.full_logging) then
2679           wip_logger.log('resID:' || x_resTbls.resID(j), l_retStatus);
2680           wip_logger.log('res start date:' || to_char(x_resTbls.startDate(j), g_logDateFmt), l_retStatus);
2681           wip_logger.log('min start date:' || to_char(l_minStartDate, g_logDateFmt), l_retStatus);
2682         end if;
2683         --clear backward scheduled times
2684         x_resTbls.usgStartIdx(j) := null;
2685         x_resTbls.usgEndIdx(j) := null;
2686       else
2687         j := j - 1;--decrement j to previous resource for forwardSchedule stmt below...
2688         exit;
2689       end if;
2690     end loop;
2691     forwardSchedule(p_orgID        => p_orgID,
2692                     p_repLineID    => p_repLineID,
2693                     p_startDate    => l_minStartDate,
2694                     p_range        => num_tbl_t(p_startIdx, j),
2695                     p_schedFlag    => p_schedFlag,
2696                     x_resTbls      => x_resTbls,
2697                     x_returnStatus => x_returnStatus);
2698 
2699     if(l_logLevel <= wip_constants.trace_logging) then
2700       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.forwardScheduleBatch',
2701                            p_procReturnStatus => x_returnStatus,
2702                            p_msg              => 'success?',
2703                            x_returnStatus     => l_retStatus);
2704     end if;
2705   end forwardScheduleBatch;
2706 
2707 
2708   procedure backwardSchedule(p_orgID        IN NUMBER,
2709                              p_repLineID    in NUMBER := null,
2710                              p_endDate      in DATE,
2711                              p_range        in num_tbl_t,
2712                              p_schedFlag    in number,
2713                              x_resTbls      in out NOCOPY OP_RES_RECTBL_T,
2714                              x_returnStatus OUT NOCOPY VARCHAR2) is
2715     l_resEndDate DATE;
2716     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
2717     l_params wip_logger.param_tbl_t;
2718     l_retStatus VARCHAR2(1);
2719     l_fromTime NUMBER;
2720     l_minDate DATE;
2721     l_shiftStartDate DATE;
2722     l_currSchedSeqNum NUMBER;
2723     l_prevResIdx NUMBER;
2724     i number;
2725     j number;
2726     l_schedulingBatch boolean := false;
2727     l_doneSchedBatch boolean := false;
2728     l_forSchedRange num_tbl_t := num_tbl_t(null, null);
2729   begin
2730     if (l_logLevel <= wip_constants.trace_logging) then
2731       l_params(1).paramName := 'p_orgID';
2732       l_params(1).paramValue := p_orgID;
2733       l_params(2).paramName := 'p_repLineID';
2734       l_params(2).paramValue := p_repLineID;
2735       l_params(3).paramName := 'p_endDate';
2736       l_params(3).paramValue := to_char(p_endDate, g_logDateFmt);
2737       l_params(4).paramName := 'p_range(1)';
2738       l_params(4).paramValue := p_range(1);
2739       l_params(5).paramName := 'p_range(2)';
2740       l_params(5).paramValue := p_range(2);
2741       l_params(6).paramName := 'p_schedFlag';
2742       l_params(6).paramValue := p_schedFlag;
2743 
2744       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.backwardSchedule',
2745                             p_params       => l_params,
2746                             x_returnStatus => x_returnStatus);
2747     end if;
2748         --get the maximum date
2749 
2750     select bc.calendar_start_date
2751       into l_minDate
2752       from bom_calendars bc, mtl_parameters mp
2753      where mp.organization_id = p_orgID
2754        and mp.calendar_code = bc.calendar_code;
2755 
2756     while(getNextResIdx(p_range, p_schedFlag, g_backward, x_resTbls, i)) loop
2757       if (l_logLevel <= wip_constants.full_logging) then
2758         wip_logger.log('begin scheduling resource:' || x_resTbls.resID(i), l_retStatus);
2759         wip_logger.log('                operation:' || x_resTbls.opSeqNum(i), l_retStatus);
2760         wip_logger.log('         schedule seq num:' || x_resTbls.schedSeqNum(i), l_retStatus);
2761         wip_logger.log('               sched flag:' || x_resTbls.schedFlag(i), l_retStatus);
2762         wip_logger.log('        total usage (HRS):' || round(x_resTbls.totalDaysUsg(i)*24, g_precision), l_retStatus);
2763 
2764         if(l_prevResIdx is not null) then
2765           wip_logger.log('prev sched seq num is:' || x_resTbls.schedSeqNum(l_prevResIdx), l_retStatus);
2766           wip_logger.log('prev op seq num is:' || x_resTbls.opSeqNum(l_prevResIdx), l_retStatus);
2767         end if;
2768       end if;
2769 
2770       l_doneSchedBatch := false;
2771       --scheduling simultaneous
2772       if(l_prevResIdx is not null and
2773          x_resTbls.schedSeqNum(i) = x_resTbls.schedSeqNum(l_prevResIdx) and
2774          x_resTbls.opSeqNum(i) = x_resTbls.opSeqNum(l_prevResIdx)) then
2775         l_schedulingBatch := true;
2776         if(l_logLevel <= wip_constants.full_logging) then
2777           wip_logger.log('starting batch', l_retStatus);
2778         end if;
2779 
2780       --just finished scheduling batch
2781       elsif(l_schedulingBatch) then
2782         if(l_logLevel <= wip_constants.full_logging) then
2783           wip_logger.log('done bkwd scheduling batch, now fwd sched', l_retStatus);
2784         end if;
2785 
2786         l_schedulingBatch := false;
2787         l_doneSchedBatch := true;
2788 
2789         forwardScheduleBatch(p_orgID        => p_orgID,
2790                              p_repLineID    => p_repLineID,
2791                              p_range        => p_range,
2792                              p_schedFlag    => p_schedFlag,
2793                              p_startIdx     => l_prevResIdx,
2794                              x_resTbls      => x_resTbls,
2795                              x_returnStatus => x_returnStatus);
2796         if(x_returnStatus <> fnd_api.g_ret_sts_success) then
2797           if(l_logLevel <= wip_constants.full_logging) then
2798             wip_logger.log('simult batch scheduling failed', l_retStatus);
2799           end if;
2800           raise fnd_api.g_exc_unexpected_error;
2801         end if;
2802       end if;
2803 
2804       if(l_prevResIdx is null) then
2805         l_resEndDate := p_EndDate;
2806 
2807       --if scheduling simultaneous, no need to get new end date, just use the previous end date
2808       elsif(not l_schedulingBatch) then
2809         l_resEndDate := getEndDate(p_range, p_schedFlag, x_resTbls, i, l_doneSchedBatch, l_prevResIdx);
2810       end if;
2811 
2812       backwardSchResource(p_orgID, l_resEndDate, l_minDate, i, p_repLineID, x_resTbls, x_returnStatus);
2813       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
2814         if(l_logLevel <= wip_constants.full_logging) then
2815           wip_logger.log('backward schedule failed', l_retStatus);
2816         end if;
2817         raise fnd_api.g_exc_unexpected_error;
2818       end if;
2819 
2820       l_prevResIdx := i;
2821     end loop;
2822 
2823     if(l_schedulingBatch) then
2824         if(l_logLevel <= wip_constants.full_logging) then
2825           wip_logger.log('done bkwd scheduling last batch, now fwd sched', l_retStatus);
2826         end if;
2827       forwardScheduleBatch(p_orgID        => p_orgID,
2828                            p_repLineID    => p_repLineID,
2829                            p_range        => p_range,
2830                            p_schedFlag    => p_schedFlag,
2831                            p_startIdx     => l_prevResIdx,
2832                            x_resTbls      => x_resTbls,
2833                            x_returnStatus => x_returnStatus);
2834       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
2835         if(l_logLevel <= wip_constants.full_logging) then
2836           wip_logger.log('final simult batch scheduling failed', l_retStatus);
2837         end if;
2838         raise fnd_api.g_exc_unexpected_error;
2839       end if;
2840     end if;
2841 
2842     if(l_logLevel <= wip_constants.trace_logging) then
2843       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.backwardSchedule',
2844                            p_procReturnStatus => x_returnStatus,
2845                            p_msg              => 'success',
2846                            x_returnStatus     => l_retStatus);
2847     end if;
2848 
2849   exception
2850     when fnd_api.g_exc_unexpected_error then
2851       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2852       if(l_logLevel <= wip_constants.trace_logging) then
2853         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.backwardSchedule',
2854                              p_procReturnStatus => x_returnStatus,
2855                              p_msg              => 'error',
2856                              x_returnStatus     => l_retStatus);
2857       end if;
2858     when others then
2859       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2860       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
2861                               p_procedure_name => 'backwardSchedule',
2862                               p_error_text => SQLERRM);
2863 
2864       if(l_logLevel <= wip_constants.trace_logging) then
2865         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.backwardSchedule',
2866                              p_procReturnStatus => x_returnStatus,
2867                              p_msg              => 'unexp error:' || SQLERRM,
2868                              x_returnStatus     => l_retStatus);
2869       end if;
2870   end backwardSchedule;
2871 
2872 
2873   procedure schedulePriorResources(p_orgID IN NUMBER,
2874                                    p_repLineID NUMBER,
2875                                    p_opTbl in op_tbl_t,
2876                                    x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
2877                                    x_returnStatus OUT NOCOPY VARCHAR2) is
2878     l_retStatus VARCHAR2(1);
2879     l_params wip_logger.param_tbl_t;
2880     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
2881   begin
2882     if(l_logLevel <= wip_constants.trace_logging) then
2883       l_params(1).paramName := 'p_orgID';
2884       l_params(1).paramValue := p_orgID;
2885       l_params(2).paramName := 'p_repLineID';
2886       l_params(2).paramValue := p_repLineID;
2887 
2888       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.schedulePriorResources',
2889                             p_params => l_params,
2890                             x_returnStatus => l_retStatus);
2891     end if;
2892 
2893     x_returnStatus := fnd_api.g_ret_sts_success;
2894 
2895     for i in 1..p_opTbl.count loop
2896       if(p_opTbl(i).priorsExist) then
2897         backwardSchedule(p_orgID => p_orgID,
2898                          p_repLineID    => p_repLineID,
2899                          p_EndDate      => p_opTbl(i).startDate,
2900                          p_range        => num_tbl_t(p_opTbl(i).resStartIdx, p_opTbl(i).resEndIdx),
2901                          p_schedFlag    => wip_constants.sched_prior,
2902                          x_resTbls      => x_resTbls,
2903                          x_returnStatus => x_returnStatus);
2904         if(x_returnStatus <> fnd_api.g_ret_sts_success) then
2905           raise fnd_api.g_exc_unexpected_error;
2906         end if;
2907       end if;
2908     end loop;
2909 
2910     if(l_logLevel <= wip_constants.trace_logging) then
2911       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedulePriorResources',
2912                            p_procReturnStatus => x_returnStatus,
2913                            p_msg              => 'success',
2914                            x_returnStatus     => l_retStatus);
2915     end if;
2916   exception
2917     when fnd_api.g_exc_unexpected_error then
2918       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2919       if(l_logLevel <= wip_constants.trace_logging) then
2920         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedulePriorResources',
2921                              p_procReturnStatus => x_returnStatus,
2922                              p_msg              => 'backward scheduling failed',
2923                              x_returnStatus     => l_retStatus);
2924       end if;
2925     when others then
2926       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2927       if(l_logLevel <= wip_constants.trace_logging) then
2928         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.schedulePriorResources',
2929                              p_procReturnStatus => x_returnStatus,
2930                              p_msg              => 'unexp error:' || SQLERRM,
2931                              x_returnStatus     => l_retStatus);
2932       end if;
2933   end schedulePriorResources;
2934 
2935   procedure scheduleNextResources(p_orgID IN NUMBER,
2936                                   p_repLineID NUMBER,
2937                                   p_opTbl IN OP_TBL_T,
2938                                   x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
2939                                   x_returnStatus OUT NOCOPY VARCHAR2) is
2940 
2941     l_retStatus VARCHAR2(1);
2942     l_params wip_logger.param_tbl_t;
2943     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
2944   begin
2945     if(l_logLevel <= wip_constants.trace_logging) then
2946       l_params(1).paramName := 'p_orgID';
2947       l_params(1).paramValue := p_orgID;
2948       l_params(2).paramName := 'p_repLineID';
2949       l_params(2).paramValue := p_repLineID;
2950 
2951       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.scheduleNextResources',
2952                             p_params => l_params,
2953                             x_returnStatus => l_retStatus);
2954     end if;
2955 
2956     x_returnStatus := fnd_api.g_ret_sts_success;
2957 
2958     for i in 1..p_opTbl.count loop
2959       if(p_opTbl(i).nextsExist) then
2960    -- Bug #13388579 added below flag to identify the call to forwardSchedule procedure from scheduleNextResources procedure in backward scheduling
2961       if (is_backWardSch) then
2962    g_reset_date := 1;
2963    end if;
2964         forwardSchedule(p_orgID => p_orgID,
2965                         p_repLineID => p_repLineID,
2966                         p_startDate => p_opTbl(i).endDate,
2967                         p_range => num_tbl_t(p_opTbl(i).resStartIdx, p_opTbl(i).resEndIdx),
2968                         p_schedFlag => wip_constants.sched_next,
2969                         x_resTbls => x_resTbls,
2970                         x_returnStatus => x_returnStatus);
2971    if (is_backWardSch) then
2972    g_reset_date := 0; -- Bug #13388579
2973     end if;
2974         if(x_returnStatus <> fnd_api.g_ret_sts_success) then
2975           raise fnd_api.g_exc_unexpected_error;
2976         end if;
2977       end if;
2978     end loop;
2979 
2980     if(l_logLevel <= wip_constants.trace_logging) then
2981       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.scheduleNextResources',
2982                            p_procReturnStatus => x_returnStatus,
2983                            p_msg              => 'success',
2984                            x_returnStatus     => l_retStatus);
2985     end if;
2986   exception
2987     when fnd_api.g_exc_unexpected_error then
2988       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2989       if(l_logLevel <= wip_constants.trace_logging) then
2990         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.scheduleNextResources',
2991                              p_procReturnStatus => x_returnStatus,
2992                              p_msg              => 'backward scheduling failed',
2993                              x_returnStatus     => l_retStatus);
2994       end if;
2995     when others then
2996       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
2997       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
2998                               p_procedure_name => 'scheduleNextResources',
2999                               p_error_text => SQLERRM);
3000 
3001       if(l_logLevel <= wip_constants.trace_logging) then
3002         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.scheduleNextResources',
3003                              p_procReturnStatus => x_returnStatus,
3004                              p_msg              => 'unexp error:' || SQLERRM,
3005                              x_returnStatus     => l_retStatus);
3006       end if;
3007   end scheduleNextResources;
3008 
3009 
3010   procedure resolvePriorExceptions(p_orgID IN NUMBER,
3011                                    p_repLineID  IN NUMBER,
3012                                    p_startDate IN DATE,
3013                                    x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
3014                                    x_returnStatus OUT NOCOPY VARCHAR2) is
3015     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
3016     l_params wip_logger.param_tbl_t;
3017     l_retStatus VARCHAR2(1);
3018     l_opSeqNum NUMBER := null;
3019     l_opStartDate DATE;
3020     l_count NUMBER;
3021     l_range num_tbl_t := num_tbl_t(1, x_resTbls.resID.count);
3022     l_opRange num_tbl_t := num_tbl_t(null,null);
3023     i number;
3024     l_exceptionExists boolean := false;
3025     l_errMsg VARCHAR2(200);
3026   begin
3027     x_returnStatus := fnd_api.g_ret_sts_success;
3028     if(l_logLevel <= wip_constants.trace_logging) then
3029       l_params(1).paramName := 'p_orgID';
3030       l_params(1).paramValue := p_orgID;
3031       l_params(2).paramName := 'p_repLineID';
3032       l_params(2).paramValue := p_repLineID;
3033       l_params(3).paramName := 'p_startDate';
3034       l_params(3).paramValue := to_char(p_startDate, g_logDateFmt);
3035       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.resolvePriorExceptions',
3036                             p_params => l_params,
3037                             x_returnStatus => x_returnStatus);
3038     end if;
3039     --this loop finds an exception
3040     while(getNextResIdx(l_range, wip_constants.sched_prior, g_forward, x_resTbls, i)) loop
3041       --if we have already found an exception and moved on to the next op, stop
3042       --and reschedule based on the current info
3043       if(l_exceptionExists) then
3044         if(l_opSeqNum <> x_resTbls.opSeqNum(i)) then
3045           exit;
3046         else
3047           l_opRange(2) := i; --prior resource is in same op, extend the schedule range
3048         end if;
3049       else --no exception found yet
3050 
3051         --assume current op will contain an exception.
3052         if(l_opSeqNum is null or l_opSeqNum <> x_resTbls.opSeqNum(i)) then
3053           l_opRange(1) := i;
3054           l_opSeqNum := x_resTbls.opSeqNum(i);
3055         end if;
3056 
3057         l_opRange(2) := i;
3058         l_exceptionExists := x_resTbls.startDate(i) < p_startDate;
3059       end if;
3060     end loop;
3061 
3062     --found a prior resource whose start date is earlier than job start...
3063     if(l_exceptionExists) then
3064 
3065       i := null;
3066       --going to reschedule entire job
3067       --delete usages
3068       x_resTbls.usgStartDate.delete;
3069       x_resTbls.usgEndDate.delete;
3070       x_resTbls.usgCumMinProcTime.delete;
3071       x_resTbls.usgStartIdx.delete;
3072       x_resTbls.usgEndIdx.delete;
3073 
3074       --delete resource times and reinitialize tables
3075       x_resTbls.startDate.delete;
3076       x_resTbls.endDate.delete;
3077       x_resTbls.startDate := date_tbl_t();
3078       x_resTbls.endDate := date_tbl_t();
3079       x_resTbls.startDate.extend(x_resTbls.resID.count);
3080       x_resTbls.endDate.extend(x_resTbls.resID.count);
3081       --reinitialize usage tables
3082       x_resTbls.usgStartIdx := num_tbl_t();
3083       x_resTbls.usgEndIdx := num_tbl_t();
3084       x_resTbls.usgStartIdx.extend(x_resTbls.resID.count);
3085       x_resTbls.usgEndIdx.extend(x_resTbls.resID.count);
3086       x_resTbls.usgStartDate := date_tbl_t();
3087       x_resTbls.usgEndDate := date_tbl_t();
3088       x_resTbls.usgCumMinProcTime := num_tbl_t();
3089 
3090       --forward schedule the prior resources in the 'bad' op from job start
3091       forwardSchedule(p_orgID        => p_orgID,
3092                       p_repLineID    => p_repLineID,
3093                       p_startDate    => p_startDate,
3094                       p_range        => l_opRange,
3095                       p_schedFlag    => wip_constants.sched_prior,
3096                       x_resTbls      => x_resTbls,
3097                       x_returnStatus => x_returnStatus);
3098 
3099       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
3100         l_errMsg := 'forward schedule failed';
3101         raise fnd_api.g_exc_unexpected_error;
3102       end if;
3103 
3104       --find latest completion date of the prior resources
3105       i := null;
3106       while(getNextResIdx(l_opRange, wip_constants.sched_prior, g_forward, x_resTbls, i)) loop
3107         l_opStartDate := greatest(nvl(l_opStartDate, x_resTbls.endDate(i)), x_resTbls.endDate(i));
3108       end loop;
3109 
3110       --now midpoint schedule from the new op start date...This invocation of schedule() will not invoke
3111       --resolvePriorExceptions() because it is operating in midpoint mode
3112       schedule(p_orgID => p_orgID,
3113                p_repLineID => p_repLineID,
3114                p_startDate => l_opStartDate,
3115                p_opSeqNum => x_resTbls.opSeqNum(l_opRange(1)),
3116                p_endDebug => fnd_api.g_false,
3117                x_resTbls => x_resTbls,
3118                x_returnStatus => x_returnStatus);
3119 
3120       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
3121         l_errMsg := 'schedule() failed';
3122         raise fnd_api.g_exc_unexpected_error;
3123       end if;
3124 
3125       --There still might be other exceptions. Call resolvePriorExceptions recursively. Note that this
3126       --terminates (eventually) because if schedule is called again, the resources we just re-scheduled
3127       --will be moved to an even later date guaranteeing the current exception will not cause any more problems...
3128       resolvePriorExceptions(p_orgID        => p_orgID,
3129                              p_repLineID    => p_repLineID,
3130                              p_startDate    => p_startDate,
3131                              x_resTbls      => x_resTbls,
3132                              x_returnStatus => x_returnStatus);
3133 
3134       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
3135         l_errMsg := 'resolvePriorExceptions Failed';
3136         raise fnd_api.g_exc_unexpected_error;
3137       end if;
3138     end if;
3139 
3140     if(l_logLevel <= wip_constants.trace_logging) then
3141       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.resolvePriorExceptions',
3142                            p_procReturnStatus => x_returnStatus,
3143                            p_msg              => 'success.',
3144                            x_returnStatus     => l_retStatus);
3145     end if;
3146   exception
3147     when fnd_api.g_exc_unexpected_error then
3148       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
3149       if(l_logLevel <= wip_constants.trace_logging) then
3150         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.resolvePriorExceptions',
3151                              p_procReturnStatus => x_returnStatus,
3152                              p_msg              => 'errmsg: ' || l_errMsg,
3153                              x_returnStatus     => l_retStatus);
3154       end if;
3155     when others then
3156       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
3157       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
3158                               p_procedure_name => 'resolvePriorExceptions',
3159                               p_error_text => SQLERRM);
3160 
3161       if(l_logLevel <= wip_constants.trace_logging) then
3162         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.resolvePriorExceptions',
3163                              p_procReturnStatus => x_returnStatus,
3164                              p_msg              => 'unexp error:' || SQLERRM,
3165                              x_returnStatus     => l_retStatus);
3166       end if;
3167   end resolvePriorExceptions;
3168 
3169   procedure resolveNextExceptions(p_orgID IN NUMBER,
3170                                   p_repLineID  IN NUMBER,
3171                                   p_endDate IN DATE,
3172                                   x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
3173                                   x_returnStatus OUT NOCOPY VARCHAR2) is
3174     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
3175     l_params wip_logger.param_tbl_t;
3176     l_retStatus VARCHAR2(1);
3177     l_opSeqNum NUMBER := null;
3178     l_opEndDate DATE;
3179     l_count NUMBER;
3180     l_range num_tbl_t := num_tbl_t(1,x_resTbls.resID.count);
3181     l_opRange num_tbl_t := num_tbl_t(null,null);
3182     i number;
3183     l_exceptionExists boolean := false;
3184     l_errMsg VARCHAR2(200);
3185   begin
3186     x_returnStatus := fnd_api.g_ret_sts_success;
3187     if(l_logLevel <= wip_constants.trace_logging) then
3188       l_params(1).paramName := 'p_orgID';
3189       l_params(1).paramValue := p_orgID;
3190       l_params(2).paramName := 'p_repLineID';
3191       l_params(2).paramValue := p_repLineID;
3192       l_params(3).paramName := 'p_endDate';
3193       l_params(3).paramValue := to_char(p_endDate, g_logDateFmt);
3194       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.resolveNextExceptions',
3195                             p_params => l_params,
3196                             x_returnStatus => x_returnStatus);
3197     end if;
3198     --this loop finds an exception
3199     while(getNextResIdx(l_range, wip_constants.sched_next, g_backward, x_resTbls, i)) loop
3200       --if we have already found an exception and moved on to the next op, stop
3201       --and reschedule based on the current info
3202       if(l_exceptionExists) then
3203         if(l_opSeqNum <> x_resTbls.opSeqNum(i)) then
3204           exit;
3205         else
3206           l_opRange(1) := i; --next resource is in same op, extend the schedule range
3207         end if;
3208       else --no exception found yet
3209         --assume current op will contain an exception.
3210         if(l_opSeqNum is null or l_opSeqNum <> x_resTbls.opSeqNum(i)) then
3211           l_opRange(2) := i;
3212           l_opSeqNum := x_resTbls.opSeqNum(i);
3213         end if;
3214         l_opRange(1) := i;
3215         l_exceptionExists := x_resTbls.endDate(i) > p_endDate;
3216         if(l_logLevel <= wip_constants.full_logging) then
3217           wip_logger.log('res end date: ' || to_char(x_resTbls.endDate(i), g_logDateFmt), l_retStatus);
3218           wip_logger.log('job end date: ' || to_char(p_endDate, g_logDateFmt), l_retStatus);
3219         end if;
3220       end if;
3221     end loop;
3222 
3223     --found a prior resource whose start date is earlier than job start...
3224     if(l_exceptionExists) then
3225       if(l_logLevel <= wip_constants.full_logging) then
3226         wip_logger.log('found exception', l_retStatus);
3227       end if;
3228       i := null;
3229       --going to reschedule entire job
3230       --delete usages
3231       x_resTbls.usgStartDate.delete;
3232       x_resTbls.usgEndDate.delete;
3233       x_resTbls.usgCumMinProcTime.delete;
3234       x_resTbls.usgStartIdx.delete;
3235       x_resTbls.usgEndIdx.delete;
3236 
3237       --delete resource times and reinitialize tables
3238       x_resTbls.startDate.delete;
3239       x_resTbls.endDate.delete;
3240       x_resTbls.startDate := date_tbl_t();
3241       x_resTbls.endDate := date_tbl_t();
3242       x_resTbls.startDate.extend(x_resTbls.resID.count);
3243       x_resTbls.endDate.extend(x_resTbls.resID.count);
3244 
3245       --reinitialize usage tables
3246       x_resTbls.usgStartIdx := num_tbl_t();
3247       x_resTbls.usgEndIdx := num_tbl_t();
3248       x_resTbls.usgStartIdx.extend(x_resTbls.resID.count);
3249       x_resTbls.usgEndIdx.extend(x_resTbls.resID.count);
3250       x_resTbls.usgStartDate := date_tbl_t();
3251       x_resTbls.usgEndDate := date_tbl_t();
3252       x_resTbls.usgCumMinProcTime := num_tbl_t();
3253 
3254       --backward schedule the next resources in the 'bad' op from job start
3255       backwardSchedule(p_orgID        => p_orgID,
3256                        p_repLineID    => p_repLineID,
3257                        p_endDate      => p_endDate,
3258                        p_range        => l_opRange,
3259                        p_schedFlag    => wip_constants.sched_next,
3260                        x_resTbls      => x_resTbls,
3261                        x_returnStatus => x_returnStatus);
3262 
3263       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
3264         l_errMsg := 'backward schedule failed';
3265         raise fnd_api.g_exc_unexpected_error;
3266       end if;
3267 
3268       --find earliest start date of the next resources
3269       i := null;
3270       while(getNextResIdx(l_opRange, wip_constants.sched_next, g_forward, x_resTbls, i)) loop
3271         l_opEndDate := least(nvl(l_opEndDate, x_resTbls.startDate(i)), x_resTbls.startDate(i));
3272       end loop;
3273 
3274       --now midpoint schedule from the new op start date...This invocation of schedule() will not invoke
3275       --resolveNextExceptions() because it is operating in midpoint mode
3276       schedule(p_orgID => p_orgID,
3277                p_repLineID => p_repLineID,
3278                p_endDate => l_opEndDate,
3279                p_opSeqNum => x_resTbls.opSeqNum(l_opRange(1)),
3280                p_endDebug => fnd_api.g_false,
3281                x_resTbls => x_resTbls,
3282                x_returnStatus => x_returnStatus);
3283 
3284       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
3285         l_errMsg := 'schedule() failed';
3286         raise fnd_api.g_exc_unexpected_error;
3287       end if;
3288 
3289       --There still might be other exceptions. Call resolveNextExceptions recursively. Note that this
3290       --terminates (eventually) because if schedule is called again, the resources we just re-scheduled
3291       --will be moved to an even earlier date guaranteeing the current exception will not cause any more problems...
3292       resolveNextExceptions(p_orgID        => p_orgID,
3293                             p_repLineID    => p_repLineID,
3294                             p_endDate    => p_endDate,
3295                             x_resTbls      => x_resTbls,
3296                             x_returnStatus => x_returnStatus);
3297 
3298       if(x_returnStatus <> fnd_api.g_ret_sts_success) then
3299         l_errMsg := 'resolveNextExceptions Failed';
3300         raise fnd_api.g_exc_unexpected_error;
3301       end if;
3302     end if;
3303 
3304     if(l_logLevel <= wip_constants.trace_logging) then
3305       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.resolveNextExceptions',
3306                            p_procReturnStatus => x_returnStatus,
3307                            p_msg              => 'success.',
3308                            x_returnStatus     => l_retStatus);
3309     end if;
3310   exception
3311     when fnd_api.g_exc_unexpected_error then
3312       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
3313       if(l_logLevel <= wip_constants.trace_logging) then
3314         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.resolveNextExceptions',
3315                              p_procReturnStatus => x_returnStatus,
3316                              p_msg              => l_errMsg,
3317                              x_returnStatus     => l_retStatus);
3318       end if;
3319     when others then
3320       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
3321       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
3322                               p_procedure_name => 'resolveNextExceptions',
3323                               p_error_text => SQLERRM);
3324 
3325       if(l_logLevel <= wip_constants.trace_logging) then
3326         wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.resolveNextExceptions',
3327                              p_procReturnStatus => x_returnStatus,
3328                              p_msg              => 'unexp error:' || SQLERRM,
3329                              x_returnStatus     => l_retStatus);
3330       end if;
3331   end resolveNextExceptions;
3332 
3333 
3334 
3335 
3336   procedure dumpResources(p_resTbls IN OP_RES_RECTBL_T) IS
3337     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
3338     l_params wip_logger.param_tbl_t;
3339     l_retStatus VARCHAR2(1);
3340     l_resCode VARCHAR2(10);
3341   begin
3342 
3343     if (l_logLevel <= wip_constants.trace_logging) then
3344       wip_logger.entryPoint(p_procName     => 'wip_infResSched_grp.dumpResources',
3345                             p_params       => l_params,
3346                             x_returnStatus => l_retStatus);
3347     end if;
3348 
3349     if(p_resTbls.resID is null or p_resTbls.resID.count < 1 and
3350        l_logLevel <= wip_constants.trace_logging) then
3351       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.dumpResources',
3352                            p_procReturnStatus => null,
3353                            p_msg              => 'no resources in table!',
3354                            x_returnStatus     => l_retStatus);
3355       return;
3356     end if;
3357 
3358     if (l_logLevel <= wip_constants.full_logging) then
3359       for i in 1..p_resTbls.resID.count loop
3360         select resource_code
3361           into l_resCode
3362           from bom_resources
3363          where resource_id = p_resTbls.resID(i);
3364         wip_logger.log('res:' || l_resCode || '(' || p_resTbls.resID(i) || ')', l_retStatus);
3365         wip_logger.log('+ usage (HRS):' || round(p_resTbls.totalDaysUsg(i)*24, 6),l_retStatus);
3366         wip_logger.log('+   operation:' || p_resTbls.opSeqNum(i), l_retStatus);
3367         wip_logger.log('+  department:' || p_resTbls.deptID(i), l_retStatus);
3368         wip_logger.log('+   sched seq:' || p_resTbls.schedSeqNum(i), l_retStatus);
3369         wip_logger.log('+     res seq:' || p_resTbls.resSeqNum(i), l_retStatus);
3370         wip_logger.log('+  sched flag:' || p_resTbls.schedFlag(i), l_retStatus);
3371         wip_logger.log('+  24hrs flag:' || p_resTbls.avail24Flag(i), l_retStatus);
3372         wip_logger.log('+  start date:' || to_char(p_resTbls.startDate(i), g_logDateFmt), l_retStatus);
3373         wip_logger.log('+    end date:' || to_char(p_resTbls.endDate(i), g_logDateFmt), l_retStatus);
3374         wip_logger.log('+  usg st idx:' || p_resTbls.usgStartIdx(i), l_retStatus);
3375         wip_logger.log('+ usg end idx:' || p_resTbls.usgEndIdx(i), l_retStatus);
3376         if(p_resTbls.usgStartIdx(i) is not null) then
3377           for j in p_resTbls.usgStartIdx(i)..p_resTbls.usgEndIdx(i) loop
3378             wip_logger.log('  + usage start date:' || to_char(p_resTbls.usgStartDate(j), g_logDateFmt),l_retStatus);
3379             wip_logger.log('  +   usage end date:' || to_char(p_resTbls.usgEndDate(j), g_logDateFmt),l_retStatus);
3380             wip_logger.log('  + cumulative usage:' || p_resTbls.usgCumMinProcTime(j),l_retStatus);
3381           end loop;
3382         end if;
3383       end loop;
3384     end if;
3385     if (l_logLevel <= wip_constants.trace_logging) then
3386       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.dumpResources',
3387                            p_procReturnStatus => null,
3388                            p_msg              => 'success',
3389                            x_returnStatus     => l_retStatus);
3390     end if;
3391 
3392   exception
3393     when others then
3394     if (l_logLevel <= wip_constants.trace_logging) then
3395       wip_logger.exitPoint(p_procName         => 'wip_infResSched_grp.dumpResources',
3396                            p_procReturnStatus => null,
3397                            p_msg              => 'exception:' || SQLERRM,
3398                            x_returnStatus     => l_retStatus);
3399     end if;
3400   end dumpResources;
3401 
3402   procedure scheduleNoResources(p_anchorDate IN DATE,
3403                                 x_resTbls IN OUT NOCOPY OP_RES_RECTBL_T,
3404                                 x_returnStatus OUT NOCOPY VARCHAR2) is
3405     l_range num_tbl_t := num_tbl_t(1, x_resTbls.resID.count);
3406     l_prevRange num_tbl_t := num_tbl_t(1, null);
3407     l_nextRange num_tbl_t := num_tbl_t(null, x_resTbls.resID.count);
3408     i NUMBER;
3409     j NUMBER;
3410     k NUMBER; -- bug 8669295 (FP 8651554)
3411     l_logLevel NUMBER := fnd_log.g_current_runtime_level;
3412     l_retStatus VARCHAR2(1);
3413     l_params wip_logger.param_tbl_t;
3414 
3415     l_endDate DATE; --bug 8614399 (FP 8586766)
3416   begin
3417     if(l_logLevel <= wip_constants.trace_logging) then
3418       l_params(1).paramName := 'p_anchorDate';
3419       l_params(1).paramValue := to_char(p_anchorDate, g_logDateFmt);
3420       wip_logger.entryPoint(p_procName => 'wip_infResSched_grp.scheduleNoResources',
3421                             p_params => l_params,
3422                             x_returnStatus => l_retStatus);
3423     end if;
3424     x_returnStatus := fnd_api.g_ret_sts_success;
3425 
3426     while(getNextResIdx(l_range, wip_constants.sched_no, g_forward, x_resTbls, i)) loop
3427 
3428       if(l_logLevel <= wip_constants.full_logging) then
3429         wip_logger.log('found scheduled no resource at ' || i, l_retStatus);
3430       end if;
3431 
3432       l_prevRange(2) := i;
3433       l_nextRange(1) := i;
3434       j := null;
3435       k := null; --bug 8669295 (FP 8651554)
3436       --find previous scheduled yes resource
3437       if(getNextResIdx(l_prevRange, wip_constants.sched_yes, g_backward, x_resTbls, j)) then
3438 
3439         if(l_logLevel <= wip_constants.full_logging) then
3440           wip_logger.log('found previous scheduled yes resource at ' || j, l_retStatus);
3441         end if;
3442 
3443       l_endDate := x_resTbls.endDate(j);
3444       --bug 8614399 (FP 8586766): identify the highest endDate in case of simultaneous resources
3445       if(x_resTbls.schedSeqNum(j) is not null) then
3446         for k in reverse 1..(j-1) loop --bug 8669295 (FP 8651554: range in for loop to be low..high
3447           if((x_resTbls.schedFlag(k) = wip_constants.sched_yes)
3448        and (x_resTbls.schedSeqNum(k) = x_resTbls.schedSeqNum(j))
3449        and (x_resTbls.endDate(k) > l_endDate)) then
3450          l_endDate := x_resTbls.endDate(k);
3451                if(l_logLevel <= wip_constants.full_logging) then
3452                  wip_logger.log('higher endDate found at: '|| k || ' date: ' || l_endDate,l_retStatus);
3453                end if;
3454            end if;
3455            if((k > 1) and (x_resTbls.schedSeqNum(k) <> x_resTbls.schedSeqNum(k-1))) then
3456              exit;
3457            end if;
3458          end loop;
3459        end if;
3460        x_resTbls.startDate(i) := l_endDate;
3461 
3462       --couldn't find a scheduled yes resource
3463        /* Bug 6954186: Find the next scheduled resource in forward direction*/
3464       elsif(getNextResIdx(l_nextRange, wip_constants.sched_yes, g_forward, x_resTbls, j)) then
3465         if(l_logLevel <= wip_constants.full_logging) then
3466           wip_logger.log('found later scheduled yes resource at ' || j, l_retStatus);
3467         end if;
3468 
3469         x_resTbls.startDate(i) := x_resTbls.startDate(j);
3470 
3471       else --no scheduled yes resources
3472         x_resTbls.startDate(i) := p_anchorDate;
3473         if(l_logLevel <= wip_constants.full_logging) then
3474           wip_logger.log('no scheduled yes resources found', l_retStatus);
3475         end if;
3476       end if;
3477 
3478       x_resTbls.endDate(i) := x_resTbls.startDate(i);
3479     end loop;
3480     if(l_logLevel <= wip_constants.trace_logging) then
3481       wip_logger.exitPoint(p_procName => 'wip_infResSched_grp.scheduleNoResources',
3482                            p_procReturnStatus => x_returnStatus,
3483                            p_msg => 'success',
3484                            x_returnStatus => l_retStatus);
3485     end if;
3486   exception
3487     when others then
3488       x_returnStatus := fnd_api.g_ret_sts_unexp_error;
3489       if(l_logLevel <= wip_constants.trace_logging) then
3490         wip_logger.exitPoint(p_procName => 'wip_infResSched_grp.scheduleNoResources',
3491                              p_procReturnStatus => x_returnStatus,
3492                              p_msg => 'error: ' || SQLERRM,
3493                              x_returnStatus => l_retStatus);
3494       end if;
3495       fnd_msg_pub.add_exc_msg(p_pkg_name => 'wip_infResSched_grp',
3496                               p_procedure_name => 'scheduleNoResources',
3497                               p_error_text => SQLERRM);
3498   end scheduleNoResources;
3499 end wip_infResSched_grp;