DBA Data[Home] [Help]

PACKAGE BODY: APPS.CSF_RESOURCE_PUB

Source


1 PACKAGE BODY csf_resource_pub AS
2 /* $Header: CSFPRESB.pls 120.20.12010000.3 2008/10/31 13:47:05 lokumar ship $ */
3 
4   g_pkg_name        CONSTANT VARCHAR2(30) := 'CSF_RESOURCE_PUB';
5   g_assign_doc_type CONSTANT VARCHAR2(2)  := 'SR';
6   g_earth_radius    CONSTANT NUMBER       := 6378137;
7   g_pi              CONSTANT NUMBER       := 2 * ACOS(0);
8 
9   TYPE qualifier_info_rec_type IS RECORD(
10     qual_usg_id  jtf_seeded_qual_usgs_v.qual_usg_id%TYPE
11   , label        jtf_seeded_qual_usgs_v.seeded_qual_name%TYPE
12   );
13 
14   TYPE qualifier_info_tbl_type IS TABLE OF qualifier_info_rec_type
15     INDEX BY BINARY_INTEGER;
16 
17   TYPE varchar2_tbl_type IS TABLE OF VARCHAR2(32)
18     INDEX BY BINARY_INTEGER;
19 
20   g_assign_errors            varchar2_tbl_type;
21   g_all_qualifiers           qualifier_info_tbl_type;
22 
23   TYPE res_type_name_rec_type IS RECORD(
24     resource_type_code jtf_objects_tl.object_code%TYPE
25   , resource_type_name jtf_objects_tl.NAME%TYPE
26   );
27 
28   TYPE res_type_name_tbl_type IS
29     TABLE OF res_type_name_rec_type;
30 
31   g_res_type_name_tbl        res_type_name_tbl_type;
32 
33   /**
34    * PLSQL Record Type to contain information about a Resource
35    * along with his Address. Note that this couldnt be put
36    * as an attribute as part of RESOURCE_REC_TYPE as Forms
37    * cant use Records which have Complex Data Types as attributes
38    */
39   TYPE resource_cache_rec_type IS RECORD(
40     resource_id       NUMBER
41   , resource_type     jtf_objects_b.object_code%TYPE
42   , resource_name     jtf_rs_resource_extns_tl.resource_name%TYPE
43   , resource_number   jtf_rs_resource_extns.resource_number%TYPE
44   , address           csf_resource_address_pvt.address_rec_type
45   );
46 
47   /**
48    * PLSQL Index By Table Type to contain information about many Resources
49    * where each element is of type RESOURCE_CACHE_REC_TYPE.
50    */
51   TYPE resource_cache_tbl_type IS TABLE OF resource_cache_rec_type
52     INDEX BY BINARY_INTEGER;
53 
54   g_res_info_cache           resource_cache_tbl_type;
55 
56 
57   /**
58    * Initializes the Table of possible Error Messages that can be
59    * encountered during Resource Selection Process.
60    * <br>
61    * Index to the table G_ASSIGN_ERRORS represent the flags that have
62    * been set to select the resources - namely Skills (S), Territories (T)
63    * Installed Base (I) and Contracts (B). When a Flag is set to 'Y', the
64    * corresponding bit is set to 1. Otherwise it is 0.
65    * <br>
66    * Examples:
67    *     S T I C
68    *     - - - -
69    *     0 0 0 0     No selection criteria
70    *     0 0 0 1     Only contracts
71    *     0 0 1 0     Only installed base
72    */
73   PROCEDURE init_assign_errors IS
74   BEGIN
75     g_assign_errors(0)  := 'CSF_NO_RES_SEL_CRIT';                -- 0000
76     g_assign_errors(1)  := 'CSF_NO_CONTRACT_RES';                -- 0001
77     g_assign_errors(2)  := 'CSF_NO_IB_RES';                      -- 0010
78     g_assign_errors(3)  := 'CSF_NO_CONTRACT_IB_RES';             -- 0011
79     g_assign_errors(4)  := 'CSF_NO_TERR_RES';                    -- 0100
80     g_assign_errors(5)  := 'CSF_TERR_CONTRACT_RES';              -- 0101
81     g_assign_errors(6)  := 'CSF_NO_TERR_IB_RES';                 -- 0110
82     g_assign_errors(8)  := 'CSF_NO_SKILLED_RES';                 -- 1000
83     g_assign_errors(9)  := 'CSF_NO_CONTR_SKILL_RES';             -- 1001
84     g_assign_errors(10) := 'CSF_NO_IB_SKILL_RES';                -- 1010
85     g_assign_errors(11) := 'CSF_NO_CONTR_IB_SKILL_RES';          -- 1011
86     g_assign_errors(12) := 'CSF_NO_TERR_SKILL_RES';              -- 1100
87     g_assign_errors(13) := 'CSF_NO_TERR_CONTRACT_SKILL_RES';     -- 1101
88     g_assign_errors(14) := 'CSF_NO_TERR_IB_SKILL_RES';           -- 1110
89     g_assign_errors(15) := 'CSF_NO_TERR_CONTRACT_IB_RES';        -- 1111
90   END init_assign_errors;
91 
92   /**
93    * Gets the Task Information in the format as desired by JTF Assignment
94    * Manager API.
95    *
96    * @param   p_task_id   Task Identifier
97    * @returns Task Record (JTF_ASSIGN_PUB.JTF_SRV_TASK_REC_TYPE).
98    */
99   FUNCTION get_srv_task_rec(p_task_id IN NUMBER)
100     RETURN jtf_assign_pub.jtf_srv_task_rec_type IS
101     l_rec                   jtf_assign_pub.jtf_srv_task_rec_type;
102     l_contract_service_id   NUMBER;
103 
104     -- Task, SR, Party and Address Information
105     CURSOR c_rec IS
106       SELECT tb.task_id task_id
107            , ib.incident_id service_request_id
108            , ib.customer_id party_id
109            , lo.country
110            , tb.address_id party_site_id
111            , lo.city
112            , lo.postal_code
113            , lo.state
114            , lo.county
115            , pa.party_name comp_name_range
116            , lo.province
117            , pa.employees_total num_of_employees
118            , tb.task_type_id
119            , tb.task_status_id
120            , tb.task_priority_id
121            , ib.incident_type_id
122            , ib.incident_severity_id
123            , ib.incident_urgency_id
124            , ib.problem_code
125            , ib.incident_status_id
126            , ib.platform_id
127            , ib.site_id support_site_id
128            , ib.customer_site_id
129            , it.sr_creation_channel
130            , ib.inventory_item_id
131            , ib.problem_code squal_char12
132            , ib.comm_pref_code squal_char13
133            , ib.platform_id squal_num12
134            , ib.inv_platform_org_id squal_num13
135            , ib.category_id squal_num14
136            , ib.inventory_item_id squal_num15
137            , ib.inv_organization_id squal_num16
138            , ib.owner_group_id squal_num17
139            , ib.language_id squal_num30
140            , ib.contract_service_id
141         FROM jtf_tasks_b tb
142            , cs_incidents_all_b ib
143            , cs_incidents_all_tl it
144            , hz_locations lo
145            , hz_parties pa
146        WHERE tb.task_id = p_task_id
147          AND tb.source_object_type_code = 'SR'
148          AND tb.source_object_id = ib.incident_id
149          AND tb.source_object_id = it.incident_id
150          AND it.LANGUAGE = USERENV('lang')
151          AND lo.location_id = csf_tasks_pub.get_task_location_id(tb.task_id, tb.address_id, tb.location_id)
152          AND ib.customer_id = pa.party_id(+);
153 
154     -- Phone Area Code
155     CURSOR c_contact_point(b_party_id NUMBER) IS
156       SELECT phone_area_code
157         FROM hz_contact_points
158        WHERE owner_table_id = b_party_id
159          AND owner_table_name = 'HZ_PARTIES'
160          AND contact_point_type = 'PHONE'
161          AND primary_flag = 'Y';
162 
163     -- Service Item ID and Organization ID
164     CURSOR c_contract(b_contract_service_id NUMBER) IS
165       SELECT TO_NUMBER(object1_id1) item_id
166            , TO_NUMBER(object1_id2) org_id
167         FROM okc_k_items
168        WHERE cle_id = b_contract_service_id;
169 
170     -- Contact VIP code
171     CURSOR c_class_code(b_party_id NUMBER) IS
172       SELECT class_code
173         FROM hz_code_assignments
174        WHERE owner_table_name = 'HZ_PARTIES'
175          AND owner_table_id = b_party_id;
176   BEGIN
177     OPEN c_rec;
178 
179     FETCH c_rec
180      INTO l_rec.task_id
181         , l_rec.service_request_id
182         , l_rec.party_id
183         , l_rec.country
184         , l_rec.party_site_id
185         , l_rec.city
186         , l_rec.postal_code
187         , l_rec.state
188         , l_rec.county
189         , l_rec.comp_name_range
190         , l_rec.province
191         , l_rec.num_of_employees
192         , l_rec.task_type_id
193         , l_rec.task_status_id
194         , l_rec.task_priority_id
195         , l_rec.incident_type_id
196         , l_rec.incident_severity_id
197         , l_rec.incident_urgency_id
198         , l_rec.problem_code
199         , l_rec.incident_status_id
200         , l_rec.platform_id
201         , l_rec.support_site_id
202         , l_rec.customer_site_id
203         , l_rec.sr_creation_channel
204         , l_rec.inventory_item_id
205         , l_rec.squal_char12
206         , l_rec.squal_char13
207         , l_rec.squal_num12
208         , l_rec.squal_num13
209         , l_rec.squal_num14
210         , l_rec.squal_num15
211         , l_rec.squal_num16
212         , l_rec.squal_num17
213         , l_rec.squal_num30
214         , l_contract_service_id;
215 
216     IF c_rec%FOUND THEN
217       IF l_rec.party_id IS NOT NULL THEN
218         -- Contact Phone Area Code
219         OPEN c_contact_point(l_rec.party_id);
220         FETCH c_contact_point INTO l_rec.area_code;
221         CLOSE c_contact_point;
222 
223         -- contact VIP code
224         OPEN c_class_code(l_rec.party_id);
225         FETCH c_class_code INTO l_rec.squal_char11;
226         CLOSE c_class_code;
227       END IF;
228 
229       IF l_contract_service_id IS NOT NULL THEN
230         -- Service item item_id and org_id
231         OPEN c_contract(l_contract_service_id);
232         FETCH c_contract INTO l_rec.squal_num18, l_rec.squal_num19;
233         CLOSE c_contract;
234       END IF;
235     ELSE
236       -- fill in only the task_id
237       l_rec.task_id := p_task_id;
238     END IF;
239 
240     CLOSE c_rec;
241 
242     RETURN l_rec;
243   END get_srv_task_rec;
244 
245   /**
246    * Gets the Seeded Enabled Qualifier Names  (and if required Labels) and
247    * populates the table G_ALL_QUALIFIERS.
248    */
249   PROCEDURE get_all_qualifiers IS
250     k       PLS_INTEGER;
251     CURSOR c_desc IS
252       SELECT   qual_usg_id qual_usg_id
253              , seeded_qual_name label
254           FROM jty_all_enabled_attributes_v
255          WHERE source_id = -1002
256            AND qual_type_id IN(-1002, -1005, -1006)
257       ORDER BY UPPER(seeded_qual_name);
258     l_rec   qualifier_info_rec_type;
259   BEGIN
260     g_all_qualifiers.DELETE;
261     OPEN c_desc;
262     LOOP
263       FETCH c_desc INTO l_rec;
264       EXIT WHEN c_desc%NOTFOUND;
265       g_all_qualifiers(c_desc%ROWCOUNT) := l_rec;
266     END LOOP;
267     CLOSE c_desc;
268   END get_all_qualifiers;
269 
270   /**
271    * Returns the Display Value for the Qualifier.
272    *
273    * If Tracing is not enabled, then it returns only Value concatenated
274    * with the Associated Value. If Tracing is enabled, it uses the SQL
275    * associated with the Qualifier and gets the Name / Description for
276    * the Qualifier (ID to Name Conversion).
277    *
278    * @param   p_index            Index to the Global All Qualifiers Table
279    * @param   p_value            Value for the Qualifier
280    * @param   p_associated_value Associated Value for the Qualifier
281    */
282   FUNCTION get_display_value(
283     p_index              IN   PLS_INTEGER
284   , p_value              IN   VARCHAR2
285   , p_associated_value   IN   VARCHAR2
286   )
287     RETURN VARCHAR2 IS
288     l_tmp     VARCHAR2(4000);
289     l_value   VARCHAR2(360);
290   BEGIN
291     -- for the default case use the provided values
292     IF p_associated_value IS NULL THEN
293       l_value := p_value;
294     ELSE
295       l_value := SUBSTR(p_value || '/' || p_associated_value, 1, 360);
296     END IF;
297     RETURN l_value;
298   END get_display_value;
299 
300   PROCEDURE set_generic_planwindow (
301     p_res_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
302   , p_start                 DATE
303   , p_end                   DATE
304   ) IS
305     i PLS_INTEGER;
306   BEGIN
307     i := p_res_tbl.FIRST;
308     WHILE i IS NOT NULL LOOP
309       p_res_tbl(i).start_date := p_start;
310       p_res_tbl(i).end_date   := p_end;
311       i := p_res_tbl.NEXT(i);
312     END LOOP;
313   END set_generic_planwindow;
314 
315   /**
316    * Adds the Qualifier identified by the Index to the global Task Qualifer Table with
317    * the value taken from the given Task Record and only when the value is Not Null.
318    * <br>
319    * Uses a Hard Coded Mapping between JTF_SEEDED_QUAL_USGS_V.QUAL_USG_ID
320    * and the fields in JTF_ASSIGN_PUB.JTF_SRV_TASK_REC_TYPE.
321    * <br>
322    * Qualifiers of type -1211, -1212 and -1218 have been disabled and
323    * therefore wont be set by this API.
324    *
325    * @param p_qualifiers Qualifier Table storing the Qualifiers
326    * @param p_index      Index to the Global All Qualifiers Table
327    * @param p_task_rec   Task Record containing the required Information
328    */
329   PROCEDURE add_qualifier(
330     p_qualifier_tbl IN OUT NOCOPY resource_qualifier_tbl_type
331   , p_index         IN            PLS_INTEGER
332   , p_task_rec      IN            jtf_assign_pub.jtf_srv_task_rec_type
333   ) IS
334     l_value            VARCHAR2(360);
335     l_associated_value VARCHAR2(360);
336     i                  PLS_INTEGER;
337   BEGIN
338     IF g_all_qualifiers(p_index).qual_usg_id = -1037 THEN
339       l_value := p_task_rec.party_id;
340     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1038 THEN
341       l_value := p_task_rec.country;
342     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1039 THEN
343       l_value := p_task_rec.party_site_id;
344     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1040 THEN
345       l_value := p_task_rec.city;
346     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1041 THEN
347       l_value := p_task_rec.postal_code;
348     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1042 THEN
349       l_value := p_task_rec.state;
350     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1043 THEN
351       l_value := p_task_rec.area_code;
352     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1044 THEN
353       l_value := p_task_rec.county;
354     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1045 THEN
355       l_value := p_task_rec.comp_name_range;
356     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1046 THEN
357       l_value := p_task_rec.province;
358     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1047 THEN
359       l_value := p_task_rec.num_of_employees;
360     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1060 THEN
361       l_value := p_task_rec.task_type_id;
362     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1061 THEN
363       l_value := p_task_rec.task_status_id;
364     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1062 THEN
365       l_value := p_task_rec.task_priority_id;
366     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1048 THEN
367       l_value := p_task_rec.incident_type_id;
368     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1049 THEN
369       l_value := p_task_rec.incident_severity_id;
370     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1050 THEN
371       l_value := p_task_rec.incident_urgency_id;
372     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1051 THEN
373       l_value := p_task_rec.problem_code;
374     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1091 THEN
375       l_value := p_task_rec.incident_status_id;
376     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1092 THEN
377       l_value := p_task_rec.platform_id;
378     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1093 THEN
379       l_value := p_task_rec.support_site_id;
380     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1094 THEN
381       l_value := p_task_rec.customer_site_id;
382     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1095 THEN
383       l_value := p_task_rec.sr_creation_channel;
384     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1096 THEN
385       l_value := p_task_rec.inventory_item_id;
386     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1210 THEN
387       l_value := p_task_rec.squal_num14;
388     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1216 THEN
389       l_value := p_task_rec.squal_num18;
390       l_associated_value := p_task_rec.squal_num19;
391     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1213 THEN
392       l_value := p_task_rec.squal_num30;
393     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1215 THEN
394       l_value := p_task_rec.squal_char11;
395     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1214 THEN
396       l_value := p_task_rec.squal_char13;
397     ELSIF g_all_qualifiers(p_index).qual_usg_id = -1217 THEN
398       l_value := p_task_rec.squal_num17;
399     END IF;
400 
401     IF l_value IS NOT NULL THEN
402       i := p_qualifier_tbl.COUNT + 1;
403       p_qualifier_tbl(i).qual_usg_id      := g_all_qualifiers(p_index).qual_usg_id;
404       p_qualifier_tbl(i).label            := g_all_qualifiers(p_index).label;
405       p_qualifier_tbl(i).use_flag         := 'Y';
406       p_qualifier_tbl(i).value            := l_value;
407       p_qualifier_tbl(i).associated_value := l_associated_value;
408       p_qualifier_tbl(i).display_value    := get_display_value(p_index, l_value, l_associated_value);
409     END IF;
410   END add_qualifier;
411 
412   /**
413    * Returns the Qualifier Table having the list of valid Qualifiers
414    * based on the Task Information of the given Task ID.
415    */
416   FUNCTION get_res_qualifier_table(p_task_id NUMBER)
417     RETURN resource_qualifier_tbl_type IS
418     m               PLS_INTEGER;
419     l_task_rec      jtf_assign_pub.jtf_srv_task_rec_type;
420     l_qualifier_tbl resource_qualifier_tbl_type;
421   BEGIN
422     -- Fetch all the Enabled Qualifiers
423     IF g_all_qualifiers.COUNT = 0 THEN
424       get_all_qualifiers;
425     END IF;
426 
427     -- Get the Task Information
428     l_task_rec := get_srv_task_rec(p_task_id);
429 
430     -- Loop thru the Qualifiers and add the valid Qualifier alone to the Table
431     m := g_all_qualifiers.FIRST;
432     WHILE m IS NOT NULL LOOP
433       add_qualifier(l_qualifier_tbl, m, l_task_rec);
434       m := g_all_qualifiers.NEXT(m);
435     END LOOP;
436 
437     RETURN l_qualifier_tbl;
438   END get_res_qualifier_table;
439 
440   /**
441    * Converts the given Qualifier Table to Assignment Manager API Record
442    * type.
443    * Assembles the selected Qualifiers for this Task from the Qualifier
444    * Table in to a Record Type understandable by JTF Assignment Manager.
445    * <br>
446    * Uses a Hard Coded Mapping between JTF_SEEDED_QUAL_USGS_V.QUAL_USG_ID
447    * and the fields in JTF_ASSIGN_PUB.JTF_SRV_TASK_REC_TYPE.
448    * <br>
449    * The Task and SR Number must be set by the caller and wont be set by
450    * this API. Moreover Qualifiers of type -1211, -1212 and -1218 have
451    * been disabled and therefore wont be set by this API.
452    *
453    * @param p_table   Qualifier Table having the list of Task Qualifiers
454    */
455   FUNCTION get_qualified_task_rec(p_table resource_qualifier_tbl_type)
456     RETURN jtf_assign_pub.jtf_srv_task_rec_type IS
457     k         PLS_INTEGER;
458     task_rec  jtf_assign_pub.jtf_srv_task_rec_type;
459   BEGIN
460     k := p_table.FIRST;
461     WHILE k IS NOT NULL LOOP
462       IF p_table(k).use_flag = 'Y' THEN
463         IF p_table(k).qual_usg_id = -1037 THEN
464           task_rec.party_id := p_table(k).VALUE;
465         ELSIF p_table(k).qual_usg_id = -1038 THEN
466           task_rec.country := p_table(k).VALUE;
467         ELSIF p_table(k).qual_usg_id = -1039 THEN
468           task_rec.party_site_id := p_table(k).VALUE;
469         ELSIF p_table(k).qual_usg_id = -1040 THEN
470           task_rec.city := p_table(k).VALUE;
471         ELSIF p_table(k).qual_usg_id = -1041 THEN
472           task_rec.postal_code := p_table(k).VALUE;
473         ELSIF p_table(k).qual_usg_id = -1042 THEN
474           task_rec.state := p_table(k).VALUE;
475         ELSIF p_table(k).qual_usg_id = -1043 THEN
476           task_rec.area_code := p_table(k).VALUE;
477         ELSIF p_table(k).qual_usg_id = -1044 THEN
478           task_rec.county := p_table(k).VALUE;
479         ELSIF p_table(k).qual_usg_id = -1045 THEN
480           task_rec.comp_name_range := p_table(k).VALUE;
481         ELSIF p_table(k).qual_usg_id = -1046 THEN
482           task_rec.province := p_table(k).VALUE;
483         ELSIF p_table(k).qual_usg_id = -1047 THEN
484           task_rec.num_of_employees := p_table(k).VALUE;
485         ELSIF p_table(k).qual_usg_id = -1060 THEN
486           task_rec.task_type_id := p_table(k).VALUE;
487         ELSIF p_table(k).qual_usg_id = -1061 THEN
488           task_rec.task_status_id := p_table(k).VALUE;
489         ELSIF p_table(k).qual_usg_id = -1062 THEN
490           task_rec.task_priority_id := p_table(k).VALUE;
491         ELSIF p_table(k).qual_usg_id = -1048 THEN
492           task_rec.incident_type_id := p_table(k).VALUE;
493         ELSIF p_table(k).qual_usg_id = -1049 THEN
494           task_rec.incident_severity_id := p_table(k).VALUE;
495         ELSIF p_table(k).qual_usg_id = -1050 THEN
496           task_rec.incident_urgency_id := p_table(k).VALUE;
497         ELSIF p_table(k).qual_usg_id = -1051 THEN
498           task_rec.problem_code := p_table(k).VALUE;
499         ELSIF p_table(k).qual_usg_id = -1091 THEN
500           task_rec.incident_status_id := p_table(k).VALUE;
501         ELSIF p_table(k).qual_usg_id = -1092 THEN
502           task_rec.platform_id := p_table(k).VALUE;
503         ELSIF p_table(k).qual_usg_id = -1093 THEN
504           task_rec.support_site_id := p_table(k).VALUE;
505         ELSIF p_table(k).qual_usg_id = -1094 THEN
506           task_rec.customer_site_id := p_table(k).VALUE;
507         ELSIF p_table(k).qual_usg_id = -1095 THEN
508           task_rec.sr_creation_channel := p_table(k).VALUE;
509         ELSIF p_table(k).qual_usg_id = -1096 THEN
510           task_rec.inventory_item_id := p_table(k).VALUE;
511         ELSIF p_table(k).qual_usg_id = -1210 THEN
512           task_rec.squal_num14 := p_table(k).VALUE;
513         ELSIF p_table(k).qual_usg_id = -1217 THEN
514           task_rec.squal_num17 := p_table(k).VALUE;
515         ELSIF p_table(k).qual_usg_id = -1216 THEN
516           task_rec.squal_num18 := p_table(k).VALUE;
517           task_rec.squal_num19 := p_table(k).associated_value;
518         ELSIF p_table(k).qual_usg_id = -1213 THEN
519           task_rec.squal_num30 := p_table(k).VALUE;
520         ELSIF p_table(k).qual_usg_id = -1215 THEN
521           task_rec.squal_char11 := p_table(k).VALUE;
522         ELSIF p_table(k).qual_usg_id = -1214 THEN
523           task_rec.squal_char13 := p_table(k).VALUE;
524         END IF;
525       END IF;
526       k := p_table.NEXT(k);
527     END LOOP;
528     RETURN task_rec;
529   END get_qualified_task_rec;
530 
531   /**
532    * Intersect the Resource results found in two tables and returns a
533    * Table having only those Resources found in both the Tables.
534    *
535    * The parameters P_START and P_END signify the Plan Window for which
536    * Resources are desired. If either of the input tables doesnt have
537    * the Plan Window stamped for any resource, these two dates will be used
538    * in place of them. After this action, the most restrictive Plan Window
539    * among the two windows is used as the Plan Window of the output table.
540    * <br>
541    * Side Effect of the API. Second Table may have entries deleted after
542    * the operation.
543    *
544    * @param   p_res_1_tbl   Resource Table 1
545    * @param   p_res_2_tbl   Resource Table 2
546    * @param   p_start       Start Date of the Window
547    * @param   p_end         End Date of the Window
548    * @return  Common Resource Table (JTF_ASSIGN_PUB.ASSIGNRESOURCES_TBL_TYPE)
549    */
550   FUNCTION intersect_results(
551     p_res_1_tbl   IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
552   , p_res_2_tbl   IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
553   , p_start                     DATE
554   , p_end                       DATE
555   ) RETURN jtf_assign_pub.assignresources_tbl_type IS
556     i           PLS_INTEGER;
557     j           PLS_INTEGER;
558     k           PLS_INTEGER;
559     l_res_tbl   jtf_assign_pub.assignresources_tbl_type;
560   BEGIN
561     k := 0;
562     i := p_res_1_tbl.FIRST;
563     WHILE i IS NOT NULL LOOP
564       j := p_res_2_tbl.FIRST;
565       WHILE j IS NOT NULL LOOP
566         EXIT WHEN p_res_2_tbl(j).resource_id = p_res_1_tbl(i).resource_id
567               AND p_res_2_tbl(j).resource_type = p_res_1_tbl(i).resource_type;
568         j := p_res_2_tbl.NEXT(j);
569       END LOOP;
570 
571       -- We have an intersection between first table and second. Add to the output table
572       IF j IS NOT NULL THEN
573         k := k + 1;
574         l_res_tbl(k) := p_res_1_tbl(i);
575         l_res_tbl(k).start_date := GREATEST( NVL(p_res_1_tbl(i).start_date, p_start)
576                                            , NVL(p_res_2_tbl(j).start_date, p_start)
577                                            );
578         l_res_tbl(k).end_date   := LEAST( NVL(p_res_1_tbl(i).end_date, p_end)
579                                         , NVL(p_res_2_tbl(j).end_date, p_end)
580                                         );
581         p_res_2_tbl.DELETE(j); -- So that Table is smaller for other iterations.
582       END IF;
583       i := p_res_1_tbl.NEXT(i);
584     END LOOP;
585     RETURN l_res_tbl;
586   END intersect_results;
587 
588   /**
589    * Returns the Skilled Resources for a Task overlapping the given
590    * Plan Window.
591    * <br>
592    * This API will return the list of all Skilled Resources for the Task
593    * with the activity date lying between the passed Plan Window. There
594    * will be an individual plan window (Adapted) for each resource.
595    * <br>
596    * If Resource ID is passed, then the API returns only one record
597    * corresponding to the passed Resource if he has the Skill Active
598    * during the given Times as desired by the Task.
599    * <br>
600    * The API makes use of the profile CSF_SKILL_LEVEL_MATCH to determine
601    * whether the Resource has a Skill Level comparable with the Task requirements
602    * as dictated by the profile.
603    * Usage of the Profile is as follows
604    *   1 - EQUAL TO or SMALLER THAN
605    *   2 - EQUAL TO                  --> (Default Value)
606    *   3 - EQUAL TO or GREATER THAN
607    * <br>
608    * Note that the API is made a PROCEDURE from its initial version of being a
609    * FUNCTION so that we can use the NOCOPY Compiler Directive and avoid the
610    * expensive Table Copy Happening during each call.
611    *
612    * @param    p_task_id          Task ID of the Task to be considered
613    * @param    p_start            Start Date Time of the Window
614    * @param    p_end              End Date Time of the Window
615    * @param    p_resource_id      Resource ID (Optional)
616    * @param    p_resource_type    Resource Type (Optional)
617    * @param    x_skilled_res_tbl  Skilled Resource Table
618    */
619   PROCEDURE get_skilled_resources(
620     p_task_id          IN        NUMBER
621   , p_start            IN        DATE
622   , p_end              IN        DATE
623   , p_resource_id      IN        NUMBER   DEFAULT NULL
624   , p_resource_type    IN        VARCHAR2 DEFAULT NULL
625   , x_skilled_res_tbl OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
626   ) IS
627     l_levelmatch   CONSTANT NUMBER := NVL(fnd_profile.VALUE('CSF_SKILL_LEVEL_MATCH'), 2);
628     j                       PLS_INTEGER;
629 
630     CURSOR c_resource_plan_window IS
631       SELECT rs.resource_id
632            , rs.resource_type
633            , rs.winstart
634            , rs.winend
635            , rs.amount
636         FROM (SELECT   rs.resource_id
637                      , rs.resource_type
638                      , GREATEST(MAX(rs.start_date_active), NVL(MAX(ss.start_date_active), p_start)
639                        , p_start) winstart
640                      , LEAST(
641                          NVL(MIN(rs.end_date_active + 1), p_end)
642                        , NVL(MIN(ss.end_date_active + 1), p_end)
643                        , p_end
644                        ) winend
645                      , COUNT(*) amount
646                   FROM csf_resource_skills_b rs
647                      , csf_required_skills_b ts
648                      , csf_skill_levels_b rsl
649                      , csf_skill_levels_b tsl
650                      , csf_skills_b ss
651                  WHERE DECODE(
652                          SIGN(rsl.step_value - tsl.step_value)
653                        , -1, DECODE(l_levelmatch, 1, 'Y', 'N')
654                        , 0, 'Y'
655                        , 1, DECODE(l_levelmatch, 3, 'Y', 'N')
656                        ) = 'Y'
657                    AND rsl.skill_level_id = rs.skill_level_id
658                    AND tsl.skill_level_id = ts.skill_level_id
659                    AND ts.skill_id = rs.skill_id
660                    AND ts.skill_type_id = rs.skill_type_id
661                    AND TRUNC(rs.start_date_active) < p_end
662                    AND (TRUNC(rs.end_date_active + 1) > p_start OR rs.end_date_active IS NULL)
663                    AND (rs.resource_id = p_resource_id OR p_resource_id IS NULL)
664                    AND (rs.resource_type = p_resource_type OR p_resource_type IS NULL)
665                    AND NVL(ts.disabled_flag, 'N') <> 'Y'
666                    AND ts.has_skill_type = 'TASK'
667                    AND ts.has_skill_id = p_task_id
668                    AND ss.skill_id(+) = rs.skill_id
669                    AND (
670                            (
671                                 rs.skill_type_id <> 2
672                             AND TRUNC(ss.start_date_active) < p_end
673                             AND (TRUNC(ss.end_date_active + 1) > p_start OR ss.end_date_active IS NULL)
674                            )
675                         OR EXISTS(SELECT 1
676                                     FROM mtl_system_items_kfv msi
677                                    WHERE msi.inventory_item_id = ts.skill_id)
678                        )
679               GROUP BY rs.resource_id, rs.resource_type) rs
680            , (SELECT COUNT(*) amount
681                 FROM csf_required_skills_b
682                WHERE NVL(disabled_flag, 'N') <> 'Y' AND has_skill_type = 'TASK'
683                      AND has_skill_id = p_task_id) ts
684        WHERE rs.amount = ts.amount AND rs.winstart < rs.winend;
685   BEGIN
686     x_skilled_res_tbl.DELETE;
687     j := 0;
688     FOR i IN c_resource_plan_window LOOP
689       j := j + 1;
690       x_skilled_res_tbl(j).resource_id   := i.resource_id;
691       x_skilled_res_tbl(j).resource_type := i.resource_type;
692       x_skilled_res_tbl(j).start_date    := i.winstart;
693       x_skilled_res_tbl(j).end_date      := i.winend;
694       x_skilled_res_tbl(j).terr_id       := -1;
695       x_skilled_res_tbl(j).terr_rank     := -1;
696     END LOOP;
697   END get_skilled_resources;
698 
699   FUNCTION geo_distance(p_lon1 NUMBER, p_lat1 NUMBER, p_lon2 NUMBER, p_lat2 NUMBER)
700     RETURN NUMBER IS
701     l_north     NUMBER;
702     l_east      NUMBER;
703   BEGIN
704     l_north := ( (p_lat2*g_pi/180.0) - (p_lat1*g_pi/180.0) ) * g_earth_radius;
705     l_east  := ( ( (p_lon2*g_pi/180.0) -(p_lon1*g_pi/180.0) ) * COS(p_lat2* g_pi/180.0) )
706               * g_earth_radius;
707     RETURN SQRT ( (l_north * l_north) + (l_east * l_east) );
708   END geo_distance;
709 
710   /**
711    * Sorts the Resources in the given list based on their distance to the given
712    * Task from their Home Address.
713    *
714    * If the Task doesnt have a valid Geometry, then the API doesnt do anything. It
715    * merely returns the original list of resources without sorting.
716    * <br>
717    * Each Resource in the given list is picked up iteratively and its Geo-Distance
718    * from the Task is computed using the Geometry of the Task and that of the
719    * Resource Home Address (Location Finder will be invoked if necessary).
720    *
721    * @param   p_unsorted_res_tbl  List of UnSorted Resources
722    * @param   p_task_id           Task ID of the Task to be performed
723    * @param   p_start             Start of the Window to get that Period's Address
724    * @param   p_end               End of the Window to get that Period's Address
725    * @returns Sorted Resources List (JTF_ASSIGN_PUB.ASSIGNRESOURCES_TBL_TYPE)
726    */
727   FUNCTION sort_resource_by_distance(
728     p_unsorted_res_tbl   jtf_assign_pub.assignresources_tbl_type
729   , p_task_id            NUMBER
730   , p_start              DATE
731   , p_end                DATE
732   )
733     RETURN jtf_assign_pub.assignresources_tbl_type IS
734     l_return_status    VARCHAR2(1);
735     l_msg_count        NUMBER;
736     l_msg_data         VARCHAR2(2000);
737     l_sorted_res_tbl   jtf_assign_pub.assignresources_tbl_type;
738     l_res_dist_tbl     csf_resource_tbl;
739     i                  PLS_INTEGER;
740     j                  PLS_INTEGER;
741     l_pref_res_cnt     PLS_INTEGER;
742     l_address          csf_resource_address_pvt.address_rec_type;
743     l_geometry         MDSYS.SDO_GEOMETRY;
744     l_task_lat         NUMBER;
745     l_task_lon         NUMBER;
746     l_res_lat          NUMBER;
747     l_res_lon          NUMBER;
748     l_valid_geo        VARCHAR2(5);
749     l_distance         NUMBER;
750 
751     CURSOR c_task_geometry IS
752       SELECT l.geometry
753         FROM jtf_tasks_b t, hz_locations l
754        WHERE t.task_id = p_task_id
755          AND l.location_id = csf_tasks_pub.get_task_location_id(t.task_id, t.address_id, t.location_id);
756 
757     CURSOR c_sorted_resources IS
758       SELECT resource_index
759            , distance
760         FROM TABLE(CAST(l_res_dist_tbl AS csf_resource_tbl) )
761        ORDER BY preferred_resource_flag desc, distance, resource_index;
762   BEGIN
763     -- Validate the Geometry of the Task.
764     -- If Task has no or invalid geometry, no need to sort by distance at all
765     OPEN c_task_geometry;
766     FETCH c_task_geometry INTO l_geometry;
767     CLOSE c_task_geometry;
768 
769     IF l_geometry IS NULL THEN
770       RETURN p_unsorted_res_tbl;
771     END IF;
772     csf_locus_pub.verify_locus(
773       p_api_version       => 1.0
774     , x_msg_count         => l_msg_count
775     , x_msg_data          => l_msg_data
776     , x_return_status     => l_return_status
777     , p_locus             => l_geometry
778     , x_result            => l_valid_geo
779     );
780 
781     IF l_valid_geo = 'FALSE' THEN
782       RETURN p_unsorted_res_tbl;
783     END IF;
784 
785     l_task_lon     := l_geometry.sdo_ordinates(1);
786     l_task_lat     := l_geometry.sdo_ordinates(2);
787     l_res_dist_tbl := csf_resource_tbl();
788     i := p_unsorted_res_tbl.FIRST;
789     l_pref_res_cnt := 1;
790     WHILE i IS NOT NULL LOOP
791       l_address := get_resource_party_address(
792                      p_res_id   => p_unsorted_res_tbl(i).resource_id
793                    , p_res_type => p_unsorted_res_tbl(i).resource_type
794                    , p_date     => p_start
795                    );
796       l_distance := csf_util_pvt.get_miss_num;
797 
798       -- Fetch the Geometry corresponding to the Address
799       IF l_address.geometry IS NOT NULL THEN
800         csf_locus_pub.verify_locus(p_api_version       => 1.0
801                                  , p_locus             => l_address.geometry
802                                  , x_msg_count         => l_msg_count
803                                  , x_msg_data          => l_msg_data
804                                  , x_return_status     => l_return_status
805                                  , x_result            => l_valid_geo
806                                   );
807         -- Compute the Distance between the Resource and the Task
808         IF l_valid_geo = 'TRUE' THEN
809           l_res_lon := l_address.geometry.sdo_ordinates(1);
810           l_res_lat := l_address.geometry.sdo_ordinates(2);
811           l_distance := geo_distance(l_task_lon, l_task_lat, l_res_lon, l_res_lat);
812         END IF;
813       END IF;
814       l_res_dist_tbl.EXTEND;
815 
816       IF p_unsorted_res_tbl(i).preference_type = 'I' OR p_unsorted_res_tbl(i).preference_type = 'C' THEN
817         l_res_dist_tbl(i) := csf_resource('Y', i, l_distance,null,null,null,null,null);
818       ELSE
819         l_res_dist_tbl(i) := csf_resource('N', i, l_distance,null,null,null,null,null);
820       END IF;
821 
822       i := p_unsorted_res_tbl.NEXT(i);
823     END LOOP;
824 
825     i := 0;
826     FOR v_resource IN c_sorted_resources LOOP
827       i := i + 1;
828       l_sorted_res_tbl(i) := p_unsorted_res_tbl(v_resource.resource_index);
829     END LOOP;
830     RETURN l_sorted_res_tbl;
831   EXCEPTION
832     WHEN OTHERS THEN
833       RETURN p_unsorted_res_tbl;
834   END sort_resource_by_distance;
835 
836   /**
837    * Reduce the number of Resources passed to a maximum value as determined by
838    * the profile "CSR: Maximum number of Resources".
839    *
840    * The API doesnt delete resources as such. It first prunes the resource list
841    * by considering only those Resources who have valid Shift Definitions between
842    * the given dates and then give the top N resources. Note that it will be
843    * better if the Resources are already sorted in the order of their preference.
844    *
845    * @param   p_res_tbl  List of Sorted Resources
846    * @param   p_start    Start of the Window for Valid Shifts Consideration
847    * @param   p_end      End of the Window for Valid Shifts Consideration
848    * @returns Top N Resources as determined by the MAXNRSELECTEDRES profile.
849    */
850   FUNCTION reduce_resource_list(
851     p_res_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
852   , p_start   DATE
853   , p_end     DATE
854   )
855     RETURN jtf_assign_pub.assignresources_tbl_type IS
856     l_max_resources  NUMBER;
857     l_return_status  VARCHAR2(1);
858     l_msg_count      NUMBER;
859     l_msg_data       VARCHAR2(2000);
860     l_shift_tbl      jtf_calendar_pub.shift_tbl_type;
861     l_out_tbl        jtf_assign_pub.assignresources_tbl_type;
862     i                PLS_INTEGER;
863     j                PLS_INTEGER;
864     cnt              PLS_INTEGER;
865   BEGIN
866     -- Get the maximum number of allowed Resources
867     l_max_resources := fnd_profile.VALUE('MAXNRSELECTEDRES');
868 
869     -- Validate retrieved maximum value
870     IF NVL(l_max_resources, 0) <= 0 THEN
871       l_max_resources := p_res_tbl.COUNT;
872     END IF;
873 
874     i := p_res_tbl.FIRST;
875     j := 0;
876     WHILE i IS NOT NULL LOOP
877       cnt:= p_res_tbl.NEXT(i);
878       WHILE cnt <= p_res_tbl.LAST LOOP
879         IF p_res_tbl(i).resource_id = p_res_tbl(cnt).resource_id AND
880           p_res_tbl(i).resource_type = p_res_tbl(cnt).resource_type THEN
881           p_res_tbl.delete(cnt);
882         END IF;
883         cnt:= p_res_tbl.next(cnt);
884       END LOOP;
885 
886       jtf_calendar_pub.get_resource_shifts(
887         p_api_version       => 1
888       , p_init_msg_list     => fnd_api.g_true
889       , x_return_status     => l_return_status
890       , x_msg_count         => l_msg_count
891       , x_msg_data          => l_msg_data
892       , p_resource_id       => p_res_tbl(i).resource_id
893       , p_resource_type     => p_res_tbl(i).resource_type
894       , p_start_date        => p_start
895       , p_end_date          => p_end
896       , x_shift             => l_shift_tbl
897       );
898       IF l_return_status = fnd_api.g_ret_sts_success OR l_shift_tbl.COUNT > 0 THEN
899         j := j + 1;
900         l_out_tbl(j) := p_res_tbl(i);
901         EXIT WHEN j = l_max_resources;
902       END IF;
903       i := p_res_tbl.NEXT(i);
904     END LOOP;
905     RETURN l_out_tbl;
906   EXCEPTION
907     WHEN OTHERS THEN
908       RETURN p_res_tbl;
909   END reduce_resource_list;
910 
911   /**
912    * Returns the Error Message that is encountered during Resource Selection
913    * process based on the Flags passed. Each Flag corresponds to a But in the
914    * Error Message Table. See INIT_ASSIGN_ERRORS for more information.
915    *
916    * @param   p_flags   Flags used to select Resources for the Task
917    * @return  Name of the Error Message encountered.
918    */
919   FUNCTION get_assign_error_msg(p_flags IN NUMBER)
920     RETURN VARCHAR2 IS
921     l_msg VARCHAR2(100);
922   BEGIN
923     l_msg := 'CSF_R_NO_RES_FOR_TASK';
924     IF p_flags IS NOT NULL AND g_assign_errors.EXISTS(p_flags) THEN
925       l_msg := g_assign_errors(p_flags);
926     END IF;
927     RETURN l_msg;
928   END get_assign_error_msg;
929 
930   /**
931    * Adds the suggested resources to the end of the given resource table if
932    * the resource is not already present in the resource table.
933    * @param p_res_tbl                Resource Table and where suggested res will be added
934    * @param p_suggested_res_id_tbl   Suggested Resource ID Table
935    * @param p_suggested_res_type_tbl Suggested Resource Type Table
936    */
937   PROCEDURE add_suggested_resources(
938     p_res_tbl                IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
939   , p_suggested_res_id_tbl   IN            jtf_number_table
940   , p_suggested_res_type_tbl IN            jtf_varchar2_table_100
941   , p_start_date             IN            DATE
942   , p_end_date               IN            DATE
943   ) IS
944     i           PLS_INTEGER;
945     j           PLS_INTEGER;
946     l_res_found BOOLEAN;
947   BEGIN
948     -- Validate the Inputs.
949     IF    p_suggested_res_id_tbl IS NULL
950        OR p_suggested_res_type_tbl IS NULL
951        OR p_suggested_res_id_tbl.COUNT <= 0
952        OR p_suggested_res_type_tbl.COUNT <> p_suggested_res_id_tbl.COUNT
953     THEN
954       RETURN;
955     END IF;
956 
957     -- Add each Suggested Resource Info to the Resource List if its not already present.
958     j := p_suggested_res_id_tbl.FIRST;
959     WHILE j IS NOT NULL LOOP
960 
961       -- Check whether the Resource list already has the Suggested Resource.
962       l_res_found := FALSE;
963       i := p_res_tbl.FIRST;
964       WHILE i IS NOT NULL LOOP
965         l_res_found :=      p_res_tbl(i).resource_id   = p_suggested_res_id_tbl(j)
966                         AND p_res_tbl(i).resource_type = p_suggested_res_type_tbl(j);
967 
968         EXIT WHEN l_res_found;
969         i := p_res_tbl.NEXT(i);
970       END LOOP;
971 
972       IF NOT l_res_found THEN
973         i := NVL(p_res_tbl.LAST, 0) + 1;
974 
975         p_res_tbl(i).resource_id              := p_suggested_res_id_tbl(j);
976         p_res_tbl(i).resource_type            := p_suggested_res_type_tbl(j);
977         p_res_tbl(i).start_date               := p_start_date;
978         p_res_tbl(i).end_date                 := p_end_date;
979         p_res_tbl(i).terr_id                  := -1;
980         p_res_tbl(i).terr_rank                := -1;
981       END IF;
982 
983       j := p_suggested_res_id_tbl.NEXT(j);
984     END LOOP;
985   END add_suggested_resources;
986 
987 
988   /**
989    * Gets the Qualified Resources for a Task by calling JTF Assignment Manager
990    * and also making use of the Required Skills of the Task if Required to reduce
991    * the Resource List.
992    *
993    * <br>
994    *
995    * The reason for CSF to maintain its own Assignment Manager rather than
996    * completely relying on JTF Assignment Manager has two fold reasons.
997    *
998    * <br>
999    *
1000    * TQ is secondary for JTF Assignment Manager API.
1001    *    Suppose in Schedule Advise Window, all the Flags are checked... then
1002    *    JTF Assignment Manager will give preference to Contracts and IB only.
1003    *    Only when both of returns ZERO resources, then JTF will consider TQ.
1004    *    But DC expects an intersection of the three results.
1005    *    Moreover if both Contracts and IB are checked, then JTF will use
1006    *    the profile "JTFAM: Resource Search Order (JTF_AM_PREF_RES_ORDER)" to
1007    *    find out which one to return ultimately. If the value CONTRACTS, then
1008    *      CONTRACTS - Only Contracts is returned. If None, IB is returned.
1009    *      IB        - Only IB is returned. If None, Contracts is returned.
1010    *      BOTH      - Intersection of Contracts and IB Resources are returned.
1011    *
1012    * <br>
1013    *
1014    * JTF doesnt know "ABC of Skills"
1015    *    Resources and Skills is completely a Field Service Functionality. A
1016    *    Resource can be attached to a Skill with a particular Skill Level.
1017    *    So can a Task be tied to a Skill with a particular Skill Level. If
1018    *    Skill based Flag is checked, then the Resource needs to have the same
1019    *    Skill Set with a Comparable Skill Level as required by the Task.
1020    *    Comparable Skill Level !!! - What is that ?
1021    *    The profile "CSF: Skill Level Match (CSF_SKILL_LEVEL_MATCH)" is used
1022    *    to decide whether the Resource has the Required Skill Level as required
1023    *    by the Task.
1024    *      EQUAL TO OR SMALLER THAN - Resource should have a Skill Level equal to
1025    *                                 or lesser than that of the Task.
1026    *      EQUAL TO                 - Resource should have a Skill Level equal to
1027    *                                 that of the Task.
1028    *      EQUAL TO OR GREATER THAN - Resource should have a Skill Level equal to
1029    *                                 or greater than that of the Task.
1030    *    Note that the Task needs to have Skills. Otherwise the Flag wont be used
1031    *    at all for getting the Qualified Resources.
1032    *
1033    * <br>
1034    *
1035    * Thus CSF Assignment Manager API will call JTF Assignment Manager separately
1036    * for Contracts / IB and then for Territory. Do an intersection of the Resources
1037    * obtained thru the two calls and pruned by Skill Sets. Note that it gets
1038    * Contracts / IB Resources from JTF in one call and so the user should make use
1039    * the profile JTF_AM_PREF_RES_ORDER to get intersected results.
1040    *
1041    * <br>
1042    *
1043    * CSF Assignment Manager still doesnt pass the parameter P_FILTER_EXCLUDED_RESOURCE
1044    * so that JTF Assignment Manager doesnt return Excluded Resources.
1045    * CSF Assignment Manager still doesnt pass the parameter P_BUSINESS_PROCESS_ID
1046    * so that JTF Assignment Manager returns only those Resources who belong to
1047    * Field Service Business Process when Preferred Resources are entered in Contracts.
1048    *
1049    * @param   p_api_version             API Version (1.0)
1050    * @param   p_init_msg_list           Initialize Message List
1051    * @param   x_return_status           Return Status of the Procedure.
1052    * @param   x_msg_count               Number of Messages in the Stack.
1053    * @param   x_msg_data                Stack of Error Messages.
1054    * @param   p_task_id                 Task Idenfifier
1055    * @param   p_task_rec                Qualified Task Record
1056    * @param   p_scheduling_mode         Scheduling Mode used. (A, I, W)
1057    * @param   p_start                   Start Date of the Plan Window
1058    * @param   p_end                     End Date of the Plan Window
1059    * @param   p_duration                Duration of the Task (Used by JTF to find out Available Resources)
1060    * @param   p_duration_uom            UOM of the above Duration
1061    * @param   p_contracts_flag          Get Contracts Preferred Resources ('Y'/'N')
1062    * @param   p_ib_flag                 Get IB Preferred Resources ('Y'/'N')
1063    * @param   p_territory_flag          Get Winning Territory Resources ('Y'/'N')
1064    * @param   p_skill_flag              Get Skilled Resources ('Y'/'N')
1065    * @param   p_calendar_flag           Get only Available Resources. Passed to JTF ('Y'/'N')
1066    * @param   p_sort_flag               Sort the Resources based on their distance from Task ('Y'/'N')
1067    * @param   p_suggested_res_id_tbl    Suggested Resource ID Table
1068    * @param   p_suggested_res_type_tbl  Suggested Resource Type Table
1069    * @param   x_res_tbl                 Qualified Resource suitable for Scheduling
1070    */
1071   PROCEDURE get_resources_to_schedule(
1072     p_api_version            IN              NUMBER
1073   , p_init_msg_list          IN              VARCHAR2
1074   , x_return_status          OUT NOCOPY      VARCHAR2
1075   , x_msg_count              OUT NOCOPY      NUMBER
1076   , x_msg_data               OUT NOCOPY      VARCHAR2
1077   , p_task_id                IN              NUMBER
1078   , p_incident_id            IN              NUMBER
1079   , p_res_qualifier_tbl      IN              resource_qualifier_tbl_type
1080   , p_scheduling_mode        IN              VARCHAR2
1081   , p_start                  IN              DATE
1082   , p_end                    IN              DATE
1083   , p_duration               IN              NUMBER
1084   , p_duration_uom           IN              VARCHAR2
1085   , p_contracts_flag         IN              VARCHAR2
1086   , p_ib_flag                IN              VARCHAR2
1087   , p_territory_flag         IN              VARCHAR2
1088   , p_skill_flag             IN              VARCHAR2
1089   , p_calendar_flag          IN              VARCHAR2
1090   , p_sort_flag              IN              VARCHAR2
1091   , p_suggested_res_id_tbl   IN              jtf_number_table
1092   , p_suggested_res_type_tbl IN              jtf_varchar2_table_100
1093   , x_res_tbl                OUT NOCOPY      jtf_assign_pub.assignresources_tbl_type
1094   ) IS
1095     l_api_name      CONSTANT VARCHAR2(30) := 'GET_RESOURCES_TO_SCHEDULE';
1096     l_api_version   CONSTANT NUMBER       := 1.0;
1097 
1098     l_task_has_skill_id      NUMBER;
1099     l_business_process_id    NUMBER;
1100     l_contracts_flag         VARCHAR2(1);
1101     l_ib_flag                VARCHAR2(1);
1102     l_territory_flag         VARCHAR2(1);
1103     l_skills_flag            VARCHAR2(1);
1104     l_has_suggested_res      BOOLEAN;
1105     l_continue_search        BOOLEAN;
1106     l_sr_task_rec            jtf_assign_pub.jtf_srv_task_rec_type;
1107 
1108     l_contracts_ib_res_tbl   jtf_assign_pub.assignresources_tbl_type;
1109     l_territory_res_tbl      jtf_assign_pub.assignresources_tbl_type;
1110     l_skilled_res_tbl        jtf_assign_pub.assignresources_tbl_type;
1111     l_stic                   NUMBER;
1112 
1113     e_no_res                 EXCEPTION;
1114 
1115     -- Cursor to determine if the Task has any required skills
1116     -- and returns the has_skill_id
1117     CURSOR c_task_skills  IS
1118       SELECT has_skill_id
1119         FROM csf_required_skills_b,jtf_tasks_b t
1120        WHERE t.task_id = p_task_id
1121          AND has_skill_type = 'TASK'
1122          AND has_skill_id = nvl(t.parent_task_id, t.task_id)
1123          AND NVL(disabled_flag, 'N') <> 'Y'
1124          AND NVL(t.deleted_flag, 'N') <> 'Y';
1125 
1126     --Introduced by lokumar for bug#7340932
1127     CURSOR c_business_process IS
1128       select iv.business_process_id
1129         from jtf_tasks_b t, cs_incidents_all i, cs_incident_types_vl iv
1130        where t.task_id = p_task_id
1131          and t.source_object_id = i.incident_id
1132          and i.incident_type_id = iv.incident_type_id;
1133 
1134 
1135   BEGIN
1136     IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
1137       RAISE fnd_api.g_exc_unexpected_error;
1138     END IF;
1139 
1140     IF fnd_api.to_boolean(p_init_msg_list) THEN
1141       fnd_msg_pub.initialize;
1142     END IF;
1143 
1144     x_return_status := fnd_api.g_ret_sts_success;
1145 
1146     IF csf_util_pvt.g_timing_activated THEN
1147       csf_util_pvt.add_timer(105, 'Get resources to schedule (init)', 0, NULL);
1148     END IF;
1149 
1150     l_contracts_flag    := NVL(p_contracts_flag, 'N');
1151     l_ib_flag           := NVL(p_ib_flag, 'N');
1152     l_territory_flag    := NVL(p_territory_flag, 'N');
1153     l_skills_flag       := NVL(p_skill_flag, 'N');
1154     l_stic              := 0;
1155     l_has_suggested_res := p_suggested_res_id_tbl IS NOT NULL AND p_suggested_res_id_tbl.COUNT > 0;
1156 
1157     -- Check that at least one flag has been set.
1158     IF    l_contracts_flag = 'N'
1159       AND l_ib_flag = 'N'
1160       AND l_territory_flag = 'N'
1161       AND l_skills_flag = 'N'
1162       AND NOT l_has_suggested_res
1163     THEN
1164       RAISE e_no_res;
1165     END IF;
1166 
1167     -- start with an empty list
1168     x_res_tbl.DELETE;
1169 
1170     -- Find out whether the Task has any Required Skills Attached.
1171     IF l_skills_flag = 'Y' THEN
1172       OPEN c_task_skills;
1173       FETCH c_task_skills INTO l_task_has_skill_id;
1174       CLOSE c_task_skills;
1175 
1176       IF l_task_has_skill_id IS NULL THEN
1177         -- Task has no Skills attached. Turn off Skills Flag.
1178         l_skills_flag := 'N';
1179         -- If none of the other Flags are set we have an error situation
1180         IF l_contracts_flag = 'N' AND l_ib_flag = 'N' AND l_territory_flag = 'N' AND NOT l_has_suggested_res THEN
1181           fnd_message.set_name('CSF', 'CSF_NO_TASK_SKILL_RES');
1182           fnd_msg_pub.ADD;
1183           RAISE fnd_api.g_exc_error;
1184         END IF;
1185       END IF;
1186     END IF;
1187 
1188     -- Convert the given Task ID or the Qualifier Table to SR Task Record
1189     IF l_contracts_flag = 'Y' OR l_ib_flag = 'Y' OR l_territory_flag = 'Y'  THEN
1190       IF p_res_qualifier_tbl.COUNT > 0 THEN
1191         IF csf_util_pvt.g_timing_activated THEN
1192           csf_util_pvt.add_timer(106, 'convert territory qualifiers to record', 0, NULL);
1193         END IF;
1194         l_sr_task_rec := get_qualified_task_rec(p_res_qualifier_tbl);
1195         IF csf_util_pvt.g_timing_activated THEN
1196           csf_util_pvt.add_timer(106, 'convert territory qualifiers to record', 1, NULL);
1197         END IF;
1198       ELSE
1199         IF csf_util_pvt.g_timing_activated THEN
1200           csf_util_pvt.add_timer(107, 'get territory qualifiers for task', 0, NULL);
1201         END IF;
1202         l_sr_task_rec := get_qualified_task_rec(get_res_qualifier_table(p_task_id));
1203         IF csf_util_pvt.g_timing_activated THEN
1204           csf_util_pvt.add_timer(107, 'get territory qualifiers for task', 1, NULL);
1205         END IF;
1206       END IF;
1207       l_sr_task_rec.task_id            := p_task_id;
1208       l_sr_task_rec.service_request_id := p_incident_id;
1209     END IF;
1210 
1211     IF csf_util_pvt.g_timing_activated THEN
1212       csf_util_pvt.add_timer(105, 'get resources to schedule (init)', 1, NULL);
1213     END IF;
1214 
1215     l_continue_search := TRUE;
1216 
1217     -- Retrieve the Resources defined in Contracts / IB
1218     IF l_contracts_flag = 'Y' OR l_ib_flag = 'Y' THEN
1219       IF csf_util_pvt.g_timing_activated THEN
1220         csf_util_pvt.add_timer(108, 'Get contract/IB resources', 0, NULL);
1221       END IF;
1222 
1223       IF l_contracts_flag = 'Y' THEN
1224         -- Added by lokumar for bug#7340932
1225         --business process id is used only when contracts are selected
1226         OPEN c_business_process;
1227         FETCH c_business_process INTO l_business_process_id;
1228         CLOSE c_business_process;
1229 
1230         l_stic := l_stic + 1;
1231 
1232       END IF;
1233 
1234       IF l_ib_flag = 'Y' THEN
1235         l_stic := l_stic + 2;
1236       END IF;
1237 
1238       jtf_assign_pub.get_assign_resources(
1239         p_api_version                   => 1.0
1240       , p_init_msg_list                 => fnd_api.g_false
1241       , p_commit                        => fnd_api.g_false
1242       , x_return_status                 => x_return_status
1243       , x_msg_count                     => x_msg_count
1244       , x_msg_data                      => x_msg_data
1245       , p_sr_task_rec                   => l_sr_task_rec
1246       , p_contracts_preferred_engineer  => l_contracts_flag
1247       , p_ib_preferred_engineer         => l_ib_flag
1248       , p_territory_flag                => 'N'
1249       , p_effort_duration               => p_duration
1250       , p_effort_uom                    => p_duration_uom
1251       , p_start_date                    => p_start
1252       , p_end_date                      => p_end
1253       , p_auto_select_flag              => 'N'
1254       , p_calendar_flag                 => NVL(p_calendar_flag, 'N')
1255       , p_calendar_check                => 'N'
1256       , p_calling_doc_id                => l_sr_task_rec.service_request_id
1257       , p_calling_doc_type              => g_assign_doc_type
1258       , p_business_process_id           => l_business_process_id
1259       , x_assign_resources_tbl          => l_contracts_ib_res_tbl
1260       );
1261 
1262       IF x_return_status = fnd_api.g_ret_sts_unexp_error THEN
1263         RAISE fnd_api.g_exc_unexpected_error;
1264       END IF;
1265 
1266       IF l_contracts_ib_res_tbl.COUNT = 0 THEN
1267         l_continue_search := FALSE;
1268       END IF;
1269 
1270       -- Since JTF Assignment Manager doesnt return End Windows properly,
1271       -- setting them to the given Plan Window.
1272       set_generic_planwindow(l_contracts_ib_res_tbl, p_start, p_end);
1273 
1274       IF csf_util_pvt.g_timing_activated THEN
1275         csf_util_pvt.add_timer(108, 'get contract/IB resources', 1, NULL);
1276       END IF;
1277     END IF;
1278 
1279     -- Retrieve Resources from Territory
1280     IF l_territory_flag = 'Y' AND l_continue_search THEN
1281       IF csf_util_pvt.g_timing_activated THEN
1282         csf_util_pvt.add_timer(109, 'get territory resources', 0, NULL);
1283       END IF;
1284 
1285       l_stic := l_stic + 4;
1286 
1287       jtf_assign_pub.get_assign_resources(
1288         p_api_version                   => 1.0
1289       , p_init_msg_list                 => fnd_api.g_false
1290       , p_commit                        => fnd_api.g_false
1291       , x_return_status                 => x_return_status
1292       , x_msg_count                     => x_msg_count
1293       , x_msg_data                      => x_msg_data
1294       , p_sr_task_rec                   => l_sr_task_rec
1295       , p_contracts_preferred_engineer  => 'N'
1296       , p_ib_preferred_engineer         => 'N'
1297       , p_territory_flag                => 'Y'
1298       , p_effort_duration               => p_duration
1299       , p_effort_uom                    => p_duration_uom
1300       , p_start_date                    => p_start
1301       , p_end_date                      => p_end
1302       , p_auto_select_flag              => 'N'
1303       , p_calendar_flag                 => NVL(p_calendar_flag, 'N')
1304       , p_calendar_check                => 'N'
1305       , p_calling_doc_id                => l_sr_task_rec.service_request_id
1306       , p_calling_doc_type              => g_assign_doc_type
1307       , x_assign_resources_tbl          => l_territory_res_tbl
1308       );
1309       IF x_return_status = fnd_api.g_ret_sts_unexp_error THEN
1310         RAISE fnd_api.g_exc_unexpected_error;
1311       END IF;
1312 
1313       IF l_territory_res_tbl.COUNT = 0 THEN
1314         l_continue_search := FALSE;
1315       END IF;
1316 
1317       -- Since JTF Assignment Manager doesnt return End Windows properly,
1318       -- setting them to the given Plan Window.
1319       set_generic_planwindow(l_territory_res_tbl, p_start, p_end);
1320 
1321       IF csf_util_pvt.g_timing_activated THEN
1322         csf_util_pvt.add_timer(109, 'get territory resources', 1, NULL);
1323       END IF;
1324     END IF;
1325 
1326     -- Retrieve the Skilled Resources for the Task
1327     IF l_skills_flag = 'Y' AND l_continue_search THEN
1328       l_stic := l_stic + 8;
1329       get_skilled_resources(
1330         p_task_id         => l_task_has_skill_id
1331       , p_start           => p_start
1332       , p_end             => p_end
1333       , x_skilled_res_tbl => l_skilled_res_tbl
1334       );
1335       IF l_skilled_res_tbl.COUNT = 0 THEN
1336         l_continue_search := FALSE;
1337       END IF;
1338     END IF;
1339 
1340     -- Intersect the results obtained from the three Qualifiers.
1341     IF l_continue_search THEN
1342       IF l_stic > 0 AND l_stic <= 3 THEN  --> Only Contracts / IB was chosen
1343         x_res_tbl := l_contracts_ib_res_tbl;
1344       ELSIF l_stic = 4 THEN               --> Only Territory was chosen
1345         x_res_tbl := l_territory_res_tbl;
1346       ELSIF l_stic = 8 THEN               --> Only Skills were chosen
1347         x_res_tbl := l_skilled_res_tbl;
1348       ELSIF l_stic <= 7 THEN              --> Both Contracts/IB and Terr were chosen
1349         x_res_tbl := intersect_results(l_contracts_ib_res_tbl, l_territory_res_tbl, p_start, p_end);
1350       ELSIF l_stic <= 11 THEN             --> Both Contracts/IB and Skills where chosen
1351         x_res_tbl := intersect_results(l_contracts_ib_res_tbl, l_skilled_res_tbl, p_start, p_end);
1352       ELSIF l_stic <= 12 THEN             --> Both Terr and SKills were chosen
1353         x_res_tbl := intersect_results(l_territory_res_tbl, l_skilled_res_tbl, p_start, p_end);
1354       ELSIF l_stic <= 15 THEN             --> All the Flags were chosen
1355         x_res_tbl := intersect_results(l_contracts_ib_res_tbl, l_territory_res_tbl, p_start, p_end);
1356         x_res_tbl := intersect_results(x_res_tbl, l_skilled_res_tbl, p_start, p_end);
1357       END IF;
1358     END IF;
1359 
1360     -- Add the suggested resources at the end (if the resource is not already there)
1361     IF l_has_suggested_res THEN
1362       add_suggested_resources(
1363         p_res_tbl                => x_res_tbl
1364       , p_suggested_res_id_tbl   => p_suggested_res_id_tbl
1365       , p_suggested_res_type_tbl => p_suggested_res_type_tbl
1366       , p_start_date             => p_start
1367       , p_end_date               => p_end
1368       );
1369     END IF;
1370 
1371     -- make sure there were results
1372     IF x_res_tbl.COUNT = 0 THEN
1373       RAISE e_no_res;
1374     END IF;
1375 
1376     IF p_scheduling_mode <> 'A' THEN
1377       -- Sort the Resources by their distance to the Task.
1378       IF csf_util_pvt.g_timing_activated THEN
1379         csf_util_pvt.add_timer(113, 'sort resources list', 0, NULL);
1380       END IF;
1381 
1382       IF x_res_tbl.COUNT > 1 AND NVL(p_sort_flag, 'Y') = 'Y' THEN
1383         x_res_tbl := sort_resource_by_distance(x_res_tbl, p_task_id, p_start, p_end);
1384       END IF;
1385 
1386       IF csf_util_pvt.g_timing_activated THEN
1387         csf_util_pvt.add_timer(113, 'sort resources list', 1, NULL);
1388       END IF;
1389 
1390     END IF;
1391 
1392 
1393     -- The number of Resources are restricted from the Sorted List.
1394       IF csf_util_pvt.g_timing_activated THEN
1395         csf_util_pvt.add_timer(114, 'reduce sorted resources list', 0, NULL);
1396       END IF;
1397 
1398       x_res_tbl := reduce_resource_list(x_res_tbl, p_start, p_end);
1399 
1400       IF csf_util_pvt.g_timing_activated THEN
1401         csf_util_pvt.add_timer(114, 'reduce sorted resources list', 1, NULL);
1402       END IF;
1403   EXCEPTION
1404     WHEN e_no_res THEN
1405       x_return_status := fnd_api.g_ret_sts_error;
1406       fnd_message.set_name('CSF', get_assign_error_msg(l_stic));
1407       fnd_msg_pub.ADD;
1408       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1409     WHEN fnd_api.g_exc_error THEN
1410       x_return_status := fnd_api.g_ret_sts_error;
1411       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1412     WHEN fnd_api.g_exc_unexpected_error THEN
1413       x_return_status := fnd_api.g_ret_sts_unexp_error;
1414       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1415     WHEN OTHERS THEN
1416       x_return_status := fnd_api.g_ret_sts_unexp_error;
1417       IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
1418         fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
1419       END IF;
1420       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1421   END get_resources_to_schedule;
1422 
1423   /**
1424    * Gets the Qualified Resources for a Task in a format understood by Request Model.
1425    * <br>
1426    * In turn calls the GET_RESOURCES_TO_SCHEDULE which gets the Resources in JTF
1427    * Assignment Manager Format.
1428    */
1429   PROCEDURE get_resources_to_schedule(
1430     p_api_version            IN              NUMBER
1431   , p_init_msg_list          IN              VARCHAR2 DEFAULT NULL
1432   , x_return_status          OUT NOCOPY      VARCHAR2
1433   , x_msg_count              OUT NOCOPY      NUMBER
1434   , x_msg_data               OUT NOCOPY      VARCHAR2
1435   , p_task_id                IN              NUMBER
1436   , p_incident_id            IN              NUMBER
1437   , p_res_qualifier_tbl      IN              resource_qualifier_tbl_type
1438   , p_scheduling_mode        IN              VARCHAR2
1439   , p_start                  IN              DATE
1440   , p_end                    IN              DATE
1441   , p_duration               IN              NUMBER                 DEFAULT NULL
1442   , p_duration_uom           IN              VARCHAR2               DEFAULT NULL
1443   , p_contracts_flag         IN              VARCHAR2               DEFAULT NULL
1444   , p_ib_flag                IN              VARCHAR2               DEFAULT NULL
1445   , p_territory_flag         IN              VARCHAR2               DEFAULT NULL
1446   , p_skill_flag             IN              VARCHAR2               DEFAULT NULL
1447   , p_calendar_flag          IN              VARCHAR2               DEFAULT NULL
1448   , p_sort_flag              IN              VARCHAR2               DEFAULT NULL
1449   , p_suggested_res_id_tbl   IN              jtf_number_table       DEFAULT NULL
1450   , p_suggested_res_type_tbl IN              jtf_varchar2_table_100 DEFAULT NULL
1451   , x_res_tbl                IN OUT NOCOPY   csf_requests_pvt.resource_tbl_type
1452   ) IS
1453     l_api_name      CONSTANT VARCHAR2(30) := 'GET_RESOURCES_TO_SCHEDULE(2)';
1454     l_api_version   CONSTANT NUMBER       := 1.0;
1455 
1456     l_assign_resource_tbl   jtf_assign_pub.assignresources_tbl_type;
1457     j                       PLS_INTEGER;
1458     k                       PLS_INTEGER;
1459   BEGIN
1460     IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
1461       RAISE fnd_api.g_exc_unexpected_error;
1462     END IF;
1463 
1464     IF fnd_api.to_boolean(p_init_msg_list) THEN
1465       fnd_msg_pub.initialize;
1466     END IF;
1467 
1468     x_return_status := fnd_api.g_ret_sts_success;
1469 
1470     get_resources_to_schedule(
1471       p_api_version            => 1
1472     , p_init_msg_list          => fnd_api.g_false
1473     , x_return_status          => x_return_status
1474     , x_msg_count              => x_msg_count
1475     , x_msg_data               => x_msg_data
1476     , p_task_id                => p_task_id
1477     , p_incident_id            => p_incident_id
1478     , p_res_qualifier_tbl      => p_res_qualifier_tbl
1479     , p_scheduling_mode        => p_scheduling_mode
1480     , p_start                  => p_start
1481     , p_end                    => p_end
1482     , p_duration               => p_duration
1483     , p_duration_uom           => p_duration_uom
1484     , p_contracts_flag         => p_contracts_flag
1485     , p_ib_flag                => p_ib_flag
1486     , p_territory_flag         => p_territory_flag
1487     , p_skill_flag             => p_skill_flag
1488     , p_calendar_flag          => p_calendar_flag
1489     , p_sort_flag              => p_sort_flag
1490     , p_suggested_res_id_tbl   => p_suggested_res_id_tbl
1491     , p_suggested_res_type_tbl => p_suggested_res_type_tbl
1492     , x_res_tbl                => l_assign_resource_tbl
1493     );
1494 
1495     IF x_res_tbl IS NULL THEN
1496         x_res_tbl := csf_requests_pvt.resource_tbl_type();
1497     END IF;
1498 
1499     --start with an empty table so that previous value are deleted
1500     x_res_tbl.delete;
1501 
1502     -- if qualified resoucres are found, add them to the output list
1503     IF x_return_status = fnd_api.g_ret_sts_success AND l_assign_resource_tbl.COUNT > 0 THEN
1504 
1505       j := l_assign_resource_tbl.FIRST;
1506       WHILE j IS NOT NULL LOOP
1507         x_res_tbl.EXTEND;
1508         k := x_res_tbl.LAST;
1509         x_res_tbl(k).resource_id   := l_assign_resource_tbl(j).resource_id;
1510         x_res_tbl(k).resource_type := l_assign_resource_tbl(j).resource_type;
1511         x_res_tbl(k).planwin_start := l_assign_resource_tbl(j).start_date;
1512         x_res_tbl(k).planwin_end   := l_assign_resource_tbl(j).end_date;
1513         x_res_tbl(k).territory_id  := l_assign_resource_tbl(j).terr_id;
1514         IF l_assign_resource_tbl(j).terr_rank = jtf_assign_pub.am_miss_num THEN
1515           x_res_tbl(k).territory_rank := NULL;
1516         ELSE
1517           x_res_tbl(k).territory_rank := l_assign_resource_tbl(j).terr_rank;
1518         END IF;
1519         IF l_assign_resource_tbl(j).preference_type = 'I' OR l_assign_resource_tbl(j).preference_type = 'C' THEN
1520           x_res_tbl(k).preferred_resources_flag := 'Y';
1521         ELSE
1522           x_res_tbl(k).preferred_resources_flag := 'N';
1523         END IF;
1524 
1525         j := l_assign_resource_tbl.NEXT(j);
1526       END LOOP;
1527     END IF;
1528   EXCEPTION
1529     WHEN fnd_api.g_exc_error THEN
1530       x_return_status := fnd_api.g_ret_sts_error;
1531       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1532     WHEN fnd_api.g_exc_unexpected_error THEN
1533       x_return_status := fnd_api.g_ret_sts_unexp_error;
1534       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1535     WHEN OTHERS THEN
1536       x_return_status := fnd_api.g_ret_sts_unexp_error;
1537       IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
1538         fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
1539       END IF;
1540       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1541   END get_resources_to_schedule;
1542 
1543 
1544   /**
1545    * Returns the Resource Type Code corresponding to a Resource Category.
1546    * <br>
1547    * In sync with the code done in JTF_RS_ALL_RESOURCES_VL
1548    *
1549    * @param   p_category    Resource Category
1550    * @returns Resource Type Code (VARCHAR2).
1551    */
1552   FUNCTION rs_category_type(p_category VARCHAR2)
1553     RETURN VARCHAR2 IS
1554   BEGIN
1555     IF p_category = 'EMPLOYEE' THEN
1556       RETURN 'RS_EMPLOYEE';
1557     ELSIF p_category = 'PARTNER' THEN
1558       RETURN 'RS_PARTNER';
1559     ELSIF p_category = 'SUPPLIER_CONTACT' THEN
1560       RETURN 'RS_SUPPLIER';
1561     ELSIF p_category = 'PARTY' THEN
1562       RETURN 'RS_PARTY';
1563     ELSIF p_category = 'OTHER' THEN
1564       RETURN 'RS_OTHER';
1565     ELSE
1566       RETURN NULL;
1567     END IF;
1568   END rs_category_type;
1569 
1570   /**
1571    * Returns the ID of the Resource tied to the given User (FND User).
1572    * <br>
1573    * If no User is passed in, then it will take the User who has logged in
1574    * (FND_GLOBAL.USER_ID).
1575    *
1576    * @param   p_user_id   Identifier to the User desired (Optional)
1577    * @returns Resource ID (NUMBER)
1578    */
1579   FUNCTION resource_id(p_user_id NUMBER DEFAULT NULL)
1580     RETURN NUMBER IS
1581     CURSOR c_resource IS
1582       SELECT resource_id
1583         FROM jtf_rs_resource_extns
1584        WHERE user_id = NVL(p_user_id, fnd_global.user_id);
1585     l_id   NUMBER := NULL;
1586   BEGIN
1587     OPEN c_resource;
1588     FETCH c_resource INTO l_id;
1589     CLOSE c_resource;
1590 
1591     RETURN l_id;
1592   END resource_id;
1593 
1594   /**
1595    * Returns the Resource Type of the Resource tied to the given user. (FND User)
1596    * <br>
1597    * If no User is passed in, then it will take the User who has logged in
1598    * (FND_GLOBAL.USER_ID).
1599    *
1600    * @param   p_user_id   Identifier to the User desired (Optional)
1601    * @returns Resource Type (VARCHAR2)
1602    */
1603   FUNCTION resource_type(p_user_id NUMBER DEFAULT NULL)
1604     RETURN VARCHAR2 IS
1605     CURSOR c_resource_type IS
1606       SELECT category
1607         FROM jtf_rs_resource_extns
1608        WHERE user_id = NVL(p_user_id, fnd_global.user_id);
1609     l_type   jtf_rs_resource_extns.category%TYPE;
1610   BEGIN
1611     OPEN c_resource_type;
1612     FETCH c_resource_type INTO l_type;
1613     CLOSE c_resource_type;
1614 
1615     RETURN rs_category_type(l_type);
1616   END resource_type;
1617 
1618   FUNCTION get_resource_from_cache(
1619     p_res_id       NUMBER
1620   , p_res_type     VARCHAR2
1621   , p_get_address  BOOLEAN   DEFAULT FALSE
1622   , p_date         DATE      DEFAULT NULL
1623   )
1624     RETURN resource_cache_rec_type IS
1625 
1626     l_return_status  VARCHAR2(1);
1627     l_msg_data       VARCHAR2(2000);
1628     l_msg_count      NUMBER;
1629     l_found          BOOLEAN;
1630     l_res_cache_info resource_cache_rec_type;
1631 
1632     CURSOR c_normal_resource IS
1633       SELECT resource_id
1634            , p_res_type resource_type
1635            , resource_name
1636            , resource_number
1637         FROM jtf_rs_resource_extns_vl
1638        WHERE resource_id = p_res_id;
1639 
1640     CURSOR c_group_resource IS
1641       SELECT group_id resource_id
1642            , 'RS_GROUP' resource_type
1643            , group_name resource_name
1644            , group_number resource_number
1645         FROM jtf_rs_groups_vl
1646        WHERE group_id = p_res_id;
1647 
1648     CURSOR c_team_resource IS
1649       SELECT team_id resource_id
1650            , 'RS_TEAM' resource_type
1651            , team_name resource_name
1652            , team_number resource_number
1653         FROM jtf_rs_teams_vl
1654        WHERE team_id = p_res_id;
1655 
1656     l_resource c_normal_resource%ROWTYPE;
1657   BEGIN
1658     IF p_res_id IS NULL OR p_res_type IS NULL THEN
1659       RETURN NULL;
1660     END IF;
1661 
1662     -- Check whether the Resource exists in the Cache
1663     l_found := FALSE;
1664     IF g_res_info_cache.EXISTS(p_res_id) THEN
1665       l_res_cache_info := g_res_info_cache(p_res_id);
1666       l_found          := l_res_cache_info.resource_type = p_res_type;
1667     END IF;
1668 
1669     IF NOT l_found THEN
1670       IF p_res_type = 'RS_GROUP' THEN
1671         OPEN c_group_resource;
1672         FETCH c_group_resource INTO l_resource;
1673         CLOSE c_group_resource;
1674       ELSIF p_res_type = 'RS_TEAM' THEN
1675         OPEN c_team_resource;
1676         FETCH c_team_resource INTO l_resource;
1677         CLOSE c_team_resource;
1678       ELSE
1679         OPEN c_normal_resource;
1680         FETCH c_normal_resource INTO l_resource;
1681         CLOSE c_normal_resource;
1682       END IF;
1683 
1684       -- Populate the Resource Cache Record
1685       l_res_cache_info.resource_id     := l_resource.resource_id;
1686       l_res_cache_info.resource_type   := l_resource.resource_type;
1687       l_res_cache_info.resource_name   := l_resource.resource_name;
1688       l_res_cache_info.resource_number := l_resource.resource_number;
1689     END IF;
1690 
1691     IF p_get_address THEN
1692       -- Check the validity of the Address in the Cache for the date
1693       IF    l_res_cache_info.address.party_site_id IS NULL
1694          OR TRUNC(p_date) < l_res_cache_info.address.start_date_active
1695          OR TRUNC(p_date) > NVL(l_res_cache_info.address.end_date_active, p_date + 1)
1696       THEN
1697         csf_resource_address_pvt.get_resource_address(
1698           p_api_version       => 1.0
1699         , x_return_status     => l_return_status
1700         , x_msg_count         => l_msg_count
1701         , x_msg_data          => l_msg_data
1702         , p_resource_id       => p_res_id
1703         , p_resource_type     => p_res_type
1704         , p_date              => p_date
1705         , x_address_rec       => l_res_cache_info.address
1706         );
1707 
1708         IF l_return_status <> fnd_api.g_ret_sts_success THEN
1709           RETURN NULL;
1710         END IF;
1711 
1712         l_found := FALSE;
1713       END IF;
1714     END IF;
1715 
1716     -- Cache the Resource Information for future use.
1717     IF NOT l_found THEN
1718       g_res_info_cache(p_res_id) := l_res_cache_info;
1719     END IF;
1720 
1721     RETURN l_res_cache_info;
1722   END get_resource_from_cache;
1723 
1724   /**
1725    * Returns the Resource Name given the Resource ID and Type.
1726    *
1727    * @param   p_res_id    Resource ID
1728    * @param   p_res_type  Resource Type Code
1729    * @returns Resource Name (VARCHAR2)
1730    */
1731   FUNCTION get_resource_name(p_res_id NUMBER, p_res_type VARCHAR2)
1732     RETURN VARCHAR2 IS
1733   BEGIN
1734     RETURN get_resource_from_cache(p_res_id, p_res_type).resource_name;
1735   END get_resource_name;
1736 
1737   /**
1738    * Returns the Complete Resource Information given the Resource ID and Type.
1739    * The returned record includes Resource Number and Resource Name.
1740    *
1741    * @param   p_res_id    Resource ID
1742    * @param   p_res_type  Resource Type Code
1743    * @returns Resource Information filled in RESOURCE_REC_TYPE
1744    */
1745   FUNCTION get_resource_info(p_res_id NUMBER, p_res_type VARCHAR2)
1746     RETURN resource_rec_type IS
1747     l_res_cache_info  resource_cache_rec_type;
1748     l_res_info        resource_rec_type;
1749   BEGIN
1750     l_res_cache_info := get_resource_from_cache(p_res_id, p_res_type);
1751 
1752     l_res_info.resource_id     := l_res_cache_info.resource_id;
1753     l_res_info.resource_type   := l_res_cache_info.resource_type;
1754     l_res_info.resource_name   := l_res_cache_info.resource_name;
1755     l_res_info.resource_number := l_res_cache_info.resource_number;
1756 
1757     RETURN l_res_info;
1758   END get_resource_info;
1759 
1760   /**
1761    * Returns the Address of the Party created for the Resource as of the
1762    * date passed.
1763    *
1764    * @param   p_res_id    Resource ID
1765    * @param   p_res_type  Resource Type Code
1766    * @param   p_date      Active Party Site for the given date
1767    *
1768    * @returns Party Address of the Resource
1769    */
1770   FUNCTION get_resource_party_address (
1771     p_res_id    NUMBER
1772   , p_res_type  VARCHAR2
1773   , p_date      DATE
1774   )
1775     RETURN csf_resource_address_pvt.address_rec_type IS
1776   BEGIN
1777     RETURN get_resource_from_cache(p_res_id, p_res_type, TRUE, p_date).address;
1778   END get_resource_party_address;
1779 
1780   /**
1781    * Returns the Resource Type Name corresponding to the Resource Type Code
1782    *
1783    * @param   p_res_type   Resource Type Code
1784    * @returns Resource Type Name (VARCHAR2)
1785    */
1786   FUNCTION get_resource_type_name(p_res_type VARCHAR2)
1787     RETURN VARCHAR2 IS
1788     i      PLS_INTEGER;
1789 
1790     CURSOR c_resource_type_names IS
1791       SELECT o.object_code code, o.name
1792         FROM jtf_object_usages u
1793            , jtf_objects_tl o
1794        WHERE u.object_user_code = 'RESOURCE_TYPES'
1795          AND o.object_code = u.object_code
1796          AND o.language = userenv('LANG');
1797   BEGIN
1798     IF g_res_type_name_tbl IS NULL THEN
1799       g_res_type_name_tbl := res_type_name_tbl_type();
1800       FOR v_resource_type_name IN c_resource_type_names LOOP
1801         g_res_type_name_tbl.extend();
1802         i := g_res_type_name_tbl.LAST;
1803         g_res_type_name_tbl(i).resource_type_code := v_resource_type_name.code;
1804         g_res_type_name_tbl(i).resource_type_name := v_resource_type_name.name;
1805       END LOOP;
1806     END IF;
1807 
1808     FOR i IN 1..g_res_type_name_tbl.COUNT LOOP
1809       IF g_res_type_name_tbl(i).resource_type_code = p_res_type THEN
1810         RETURN g_res_type_name_tbl(i).resource_type_name;
1811       END IF;
1812     END LOOP;
1813     RETURN p_res_type;
1814   END get_resource_type_name;
1815 
1816   /**
1817    * Converts the given Time from Resource Timezone to Server Timezone
1818    * or vice versa.
1819    * <br>
1820    * By default, the given date is assumed to be in Resource Timezone and the
1821    * date returned is Server Timezone. Set p_server_to_resource parameter as
1822    * 'T' (FND_API.G_TRUE) to make it return the other way round.
1823    * <br>
1824    * Note that the API doesnt support RS_TEAM or RS_GROUP resources.
1825    *
1826    * @param  p_api_version             API Version (1.0)
1827    * @param  p_init_msg_list           Initialize Message List
1828    * @param  x_return_status           Return Status of the Procedure.
1829    * @param  x_msg_count               Number of Messages in the Stack.
1830    * @param  x_msg_data                Stack of Error Messages.
1831    * @param  p_resource_id             Resource ID
1832    * @param  p_resource_type           Resource Type
1833    * @param  p_datetime                Date to be converted
1834    * @param  p_server_to_resource      Server to Resource Timezone
1835    */
1836   PROCEDURE convert_timezone(
1837     p_api_version          IN              NUMBER
1838   , p_init_msg_list        IN              VARCHAR2
1839   , x_return_status        OUT    NOCOPY   VARCHAR2
1840   , x_msg_count            OUT    NOCOPY   NUMBER
1841   , x_msg_data             OUT    NOCOPY   VARCHAR2
1842   , p_resource_id          IN              NUMBER
1843   , p_resource_type        IN              VARCHAR2
1844   , x_datetime             IN OUT NOCOPY   DATE
1845   , p_server_to_resource   IN              VARCHAR2
1846   ) IS
1847     l_api_name      CONSTANT VARCHAR2(30) := 'CONVERT_TIMEZONE';
1848     l_api_version   CONSTANT NUMBER       := 1.0;
1849     l_source_tz_id           NUMBER;
1850     l_dest_tz_id             NUMBER;
1851     l_temp_tz_id             NUMBER;
1852     CURSOR c_resource IS
1853       SELECT time_zone
1854         FROM jtf_rs_resource_extns
1855        WHERE resource_id = p_resource_id
1856          AND p_resource_type NOT IN('RS_GROUP', 'RS_TEAM');
1857   BEGIN
1858     -- Standard call to check for call compatibility
1859     IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, 'CSF_TASKS_PUB') THEN
1860       RAISE fnd_api.g_exc_unexpected_error;
1861     END IF;
1862 
1863     -- Initialize message list if p_init_msg_list is set to TRUE
1864     IF fnd_api.to_boolean(p_init_msg_list) THEN
1865       fnd_msg_pub.initialize;
1866     END IF;
1867 
1868     -- Initialize API return status to success
1869     x_return_status := fnd_api.g_ret_sts_success;
1870 
1871     -- Start actual processing
1872     fnd_profile.get('SERVER_TIMEZONE_ID', l_dest_tz_id);
1873 
1874     OPEN c_resource;
1875     FETCH c_resource INTO l_source_tz_id;
1876     CLOSE c_resource;
1877 
1878     -- Reverse conversion when requested
1879     IF fnd_api.to_boolean(p_server_to_resource) THEN
1880       l_temp_tz_id   := l_source_tz_id;
1881       l_source_tz_id := l_dest_tz_id;
1882       l_dest_tz_id   := l_source_tz_id;
1883     END IF;
1884 
1885     -- Only try conversion when source and destination timezones are found
1886     IF l_source_tz_id IS NOT NULL AND l_dest_tz_id IS NOT NULL THEN
1887       hz_timezone_pub.get_time(
1888         p_api_version         => 1.0
1889       , p_init_msg_list       => fnd_api.g_false
1890       , p_source_tz_id        => l_source_tz_id
1891       , p_dest_tz_id          => l_dest_tz_id
1892       , p_source_day_time     => x_datetime
1893       , x_dest_day_time       => x_datetime
1894       , x_return_status       => x_return_status
1895       , x_msg_count           => x_msg_count
1896       , x_msg_data            => x_msg_data
1897       );
1898     END IF;
1899 
1900   EXCEPTION
1901     WHEN fnd_api.g_exc_error THEN
1902       x_return_status := fnd_api.g_ret_sts_error;
1903       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1904     WHEN fnd_api.g_exc_unexpected_error THEN
1905       x_return_status := fnd_api.g_ret_sts_unexp_error;
1906       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1907     WHEN OTHERS THEN
1908       x_return_status := fnd_api.g_ret_sts_unexp_error;
1909       IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
1910         fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
1911       END IF;
1912       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1913   END convert_timezone;
1914 
1915   /**
1916    * Gets the Shift Definitions of the given Resource between the two given Dates.
1917    *
1918    * CSF has its own "Get Resource Shifts" API in addition to JTF providing it is
1919    * because CSF is still calling JTF Calendar API rather than JTF Calendar 24 API.
1920    * Going forward, we should be calling JTF_CALENDAR24_PUB rather than
1921    * JTF_CALENDAR_PUB.
1922    * Because of this the following Shift Definition is returned as two Shifts.
1923    * <br>
1924    * Shift Construct #101: Start = 1-JAN-2005 18:00:00 to 2-JAN-2005 07:00:00
1925    *    is returned as
1926    *       Shift Record #1
1927    *           Shift Construct = 101
1928    *           Shift Date      = 1-JAN-2005
1929    *           Start Time      = 18:00
1930    *           End Time        = 23:59
1931    *
1932    *       Shift Record #2
1933    *           Shift Construct = 101
1934    *           Shift Date      = 2-JAN-2005
1935    *           Start Time      = 00:00
1936    *           End Time        = 07:00
1937    * <br>
1938    * Note that Shift Record#1 and Shift Record#2 are adjacent in the returned
1939    * Shifts Table. Morever both has the same Shift Construct ID and the difference
1940    * between End Time of the first record and the start time of the second is
1941    * One Minute (1/1440 days).
1942    *
1943    * This feature is being used by this API to merge those shifts in a single
1944    * record structure.
1945    *
1946    * @param   p_api_version           API Version (1.0)
1947    * @param   p_init_msg_list         Initialize Message List
1948    * @param   x_return_status         Return Status of the Procedure.
1949    * @param   x_msg_count             Number of Messages in the Stack.
1950    * @param   x_msg_data              Stack of Error Messages.
1951    * @param   p_resource_id           Resource Identifier for whom Shifts are required.
1952    * @param   p_resource_type         Resource Type of the above Resource.
1953    * @param   p_start_date            Start of the Window between which Shifts are required.
1954    * @param   p_end_date              End of the Window between which Shifts are required.
1955    * @param   x_shifts                Shift Definitions
1956    */
1957   PROCEDURE get_resource_shifts(
1958     p_api_version     IN          NUMBER
1959   , p_init_msg_list   IN          VARCHAR2
1960   , x_return_status   OUT NOCOPY  VARCHAR2
1961   , x_msg_count       OUT NOCOPY  NUMBER
1962   , x_msg_data        OUT NOCOPY  VARCHAR2
1963   , p_resource_id     IN          NUMBER
1964   , p_resource_type   IN          VARCHAR2
1965   , p_start_date      IN          DATE
1966   , p_end_date        IN          DATE
1967   , x_shifts          OUT NOCOPY  shift_tbl_type
1968   ) IS
1969     l_api_name      CONSTANT VARCHAR2(30) := 'GET_RESOURCE_SHIFTS';
1970     l_api_version   CONSTANT NUMBER       := 1.0;
1971 
1972     l_multiday_shifts        jtf_calendar_pub.shift_tbl_type;
1973     l_time                   DATE;
1974     l_shift_starttime        DATE;
1975     l_shift_endtime          DATE;
1976     i                        PLS_INTEGER; -- Iterator for JTF's Shift Table
1977     j                        PLS_INTEGER; -- Iterator for CSF's Shift Table
1978   BEGIN
1979     IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
1980       RAISE fnd_api.g_exc_unexpected_error;
1981     END IF;
1982 
1983     IF fnd_api.to_boolean(p_init_msg_list) THEN
1984       fnd_msg_pub.initialize;
1985     END IF;
1986 
1987     x_return_status := fnd_api.g_ret_sts_success;
1988 
1989     jtf_calendar_pub.get_resource_shifts(
1990       p_api_version       => 1.0
1991     , p_resource_id       => p_resource_id
1992     , p_resource_type     => p_resource_type
1993     , p_start_date        => p_start_date
1994     , p_end_date          => p_end_date
1995     , x_return_status     => x_return_status
1996     , x_msg_count         => x_msg_count
1997     , x_msg_data          => x_msg_data
1998     , x_shift             => l_multiday_shifts
1999     );
2000 
2001     IF x_return_status <> fnd_api.g_ret_sts_success OR l_multiday_shifts.COUNT = 0 THEN
2002       IF x_return_status = fnd_api.g_ret_sts_unexp_error THEN
2003         RAISE fnd_api.g_exc_unexpected_error;
2004       END IF;
2005       RAISE fnd_api.g_exc_error;
2006     END IF;
2007 
2008     i := l_multiday_shifts.FIRST;
2009     j := 0;
2010     WHILE i IS NOT NULL LOOP
2011       l_time            := to_date(l_multiday_shifts(i).start_time, 'HH24:MI');
2012       l_shift_starttime := l_multiday_shifts(i).shift_date + (l_time - trunc(l_time));
2013       l_time            := to_date(l_multiday_shifts(i).end_time, 'HH24:MI');
2014       l_shift_endtime   := l_multiday_shifts(i).shift_date + (l_time - trunc(l_time));
2015 
2016       IF l_shift_endtime > p_start_date AND l_shift_starttime < p_end_date THEN
2017         -- Check whether the previous shift is same as the current one with a Minute Difference
2018         IF ( x_shifts.EXISTS(j)
2019              AND x_shifts(j).shift_construct_id = l_multiday_shifts(i).shift_construct_id
2020              AND (x_shifts(j).end_datetime + 1/1440) = l_shift_starttime )
2021         THEN
2022           -- Its the same shift but crossing the 24 Hour Boundary. Merge them.
2023           x_shifts(j).end_datetime := l_shift_endtime;
2024         ELSE
2025           j := j+1;
2026           x_shifts(j).shift_construct_id := l_multiday_shifts(i).shift_construct_id;
2027           x_shifts(j).availability_type  := l_multiday_shifts(i).availability_type;
2028           x_shifts(j).start_datetime     := l_shift_starttime;
2029           x_shifts(j).end_datetime       := l_shift_endtime;
2030         END IF;
2031       END IF;
2032 
2033       i := l_multiday_shifts.NEXT(i);
2034     END LOOP;
2035 
2036   EXCEPTION
2037     WHEN fnd_api.g_exc_error THEN
2038       x_return_status := fnd_api.g_ret_sts_error;
2039       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2040     WHEN fnd_api.g_exc_unexpected_error THEN
2041       x_return_status := fnd_api.g_ret_sts_unexp_error;
2042       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2043     WHEN OTHERS THEN
2044       x_return_status := fnd_api.g_ret_sts_unexp_error;
2045       IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
2046         fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
2047       END IF;
2048       fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2049   END get_resource_shifts;
2050 
2051 
2052 BEGIN
2053   init_assign_errors;
2054 END csf_resource_pub;