1 PACKAGE BODY CSF_RESOURCE_PUB AS
2 /* $Header: CSFPRESB.pls 120.58 2011/04/26 10:09:38 vakulkar 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 g_res_add_prof VARCHAR2(200);
9 g_debug VARCHAR2(1):= NVL(fnd_profile.value('AFLOG_ENABLED'), 'N');
10
11 g_debug_level NUMBER := NVL(fnd_profile.value_specific('AFLOG_LEVEL'), fnd_log.level_event);
12
13
14 TYPE qualifier_info_rec_type IS RECORD(
15 qual_usg_id jtf_seeded_qual_usgs_v.qual_usg_id%TYPE
16 , label jtf_seeded_qual_usgs_v.seeded_qual_name%TYPE
17 );
18
19 TYPE qualifier_info_tbl_type IS TABLE OF qualifier_info_rec_type
20 INDEX BY BINARY_INTEGER;
21
22 TYPE varchar2_tbl_type IS TABLE OF VARCHAR2(32)
23 INDEX BY BINARY_INTEGER;
24
25 g_assign_errors varchar2_tbl_type;
26 g_all_qualifiers qualifier_info_tbl_type;
27
28 TYPE res_type_name_rec_type IS RECORD(
29 resource_type_code jtf_objects_tl.object_code%TYPE
30 , resource_type_name jtf_objects_tl.NAME%TYPE
31 );
32
33 TYPE res_type_name_tbl_type IS
34 TABLE OF res_type_name_rec_type;
35
36 g_res_type_name_tbl res_type_name_tbl_type;
37
38 /**
39 * PLSQL Record Type to contain information about a Resource
40 * along with his Address. Note that this couldnt be put
41 * as an attribute as part of RESOURCE_REC_TYPE as Forms
42 * cant use Records which have Complex Data Types as attributes
43 */
44 TYPE resource_cache_rec_type IS RECORD(
45 resource_id NUMBER
46 , resource_type jtf_objects_b.object_code%TYPE
47 , resource_name jtf_rs_resource_extns_tl.resource_name%TYPE
48 , resource_number jtf_rs_resource_extns.resource_number%TYPE
49 , address csf_resource_address_pvt.address_rec_type
50 );
51
52 /**
53 * PLSQL Index By Table Type to contain information about many Resources
54 * where each element is of type RESOURCE_CACHE_REC_TYPE.
55 */
56 TYPE resource_cache_tbl_type IS TABLE OF resource_cache_rec_type
57 INDEX BY BINARY_INTEGER;
58
59 g_res_info_cache resource_cache_tbl_type;
60
61 PROCEDURE debug(p_level NUMBER, p_module VARCHAR2, p_message VARCHAR2) IS
62 BEGIN
63 IF g_debug = 'Y' AND p_level >= g_debug_level THEN
64 fnd_log.string(p_level, 'csf.plsql.CSF_RESOURCE_PUB.' || p_module, p_message);
65 END IF;
66 END debug;
67
68 /**
69 * Initializes the Table of possible Error Messages that can be
70 * encountered during Resource Selection Process.
71 * <br>
72 * Index to the table G_ASSIGN_ERRORS represent the flags that have
73 * been set to select the resources - namely Skills (S), Territories (T)
74 * Installed Base (I) and Contracts (B). When a Flag is set to 'Y', the
75 * corresponding bit is set to 1. Otherwise it is 0.
76 * <br>
77 * Examples:
78 * S T I C
79 * - - - -
80 * 0 0 0 0 No selection criteria
81 * 0 0 0 1 Only contracts
82 * 0 0 1 0 Only installed base
83 */
84 PROCEDURE init_assign_errors IS
85 BEGIN
86 g_assign_errors(0) := 'CSF_NO_RES_SEL_CRIT'; -- 0000
87 g_assign_errors(1) := 'CSF_NO_CONTRACT_RES'; -- 0001
88 g_assign_errors(2) := 'CSF_NO_IB_RES'; -- 0010
89 g_assign_errors(3) := 'CSF_NO_CONTRACT_IB_RES'; -- 0011
90 g_assign_errors(4) := 'CSF_NO_TERR_RES'; -- 0100
91 g_assign_errors(5) := 'CSF_TERR_CONTRACT_RES'; -- 0101
92 g_assign_errors(6) := 'CSF_NO_TERR_IB_RES'; -- 0110
93 g_assign_errors(8) := 'CSF_NO_SKILLED_RES'; -- 1000
94 g_assign_errors(9) := 'CSF_NO_CONTR_SKILL_RES'; -- 1001
95 g_assign_errors(10) := 'CSF_NO_IB_SKILL_RES'; -- 1010
96 g_assign_errors(11) := 'CSF_NO_CONTR_IB_SKILL_RES'; -- 1011
97 g_assign_errors(12) := 'CSF_NO_TERR_SKILL_RES'; -- 1100
98 g_assign_errors(13) := 'CSF_NO_TERR_CONTRACT_SKILL_RES'; -- 1101
99 g_assign_errors(14) := 'CSF_NO_TERR_IB_SKILL_RES'; -- 1110
100 g_assign_errors(15) := 'CSF_NO_TERR_CONTRACT_IB_RES'; -- 1111
101 END init_assign_errors;
102
103 /**
104 * Gets the Task Information in the format as desired by JTF Assignment
105 * Manager API.
106 *
107 * @param p_task_id Task Identifier
108 * @returns Task Record (JTF_ASSIGN_PUB.JTF_SRV_TASK_REC_TYPE).
109 */
110 FUNCTION get_srv_task_rec(p_task_id IN NUMBER)
111 RETURN jtf_assign_pub.jtf_srv_task_rec_type IS
112 l_rec jtf_assign_pub.jtf_srv_task_rec_type;
113 l_contract_service_id NUMBER;
114 l_planned_start_date date;
115 -- Task, SR, Party and Address Information
116 CURSOR c_rec IS
117 SELECT tb.task_id task_id
118 , ib.incident_id service_request_id
119 , ib.customer_id party_id
120 , lo.country
121 , tb.address_id party_site_id
122 , lo.city
123 , lo.postal_code
124 , lo.state
125 , lo.county
126 , pa.party_name comp_name_range
127 , lo.province
128 , pa.employees_total num_of_employees
129 , tb.task_type_id
130 , tb.task_status_id
131 , tb.task_priority_id
132 , ib.incident_type_id
133 , ib.incident_severity_id
134 , ib.incident_urgency_id
135 , ib.problem_code
136 , ib.incident_status_id
137 , ib.platform_id
138 , ib.site_id support_site_id
139 , ib.customer_site_id
140 , ib.sr_creation_channel
141 , ib.inventory_item_id
142 , ib.problem_code squal_char12
143 , ib.comm_pref_code squal_char13
144 , ib.platform_id squal_num12
145 , ib.inv_platform_org_id squal_num13
146 , ib.category_id squal_num14
147 , ib.inventory_item_id squal_num15
148 , ib.org_id squal_16 -- THIS CODE WAS COMMENTED BY VAKULKAR AS TERRITORY POPULATE VALUE3_ID AS ORG_ID
149 -- 1ST VALUE WILL BE 1373( Inv.Items - COMPUTER.DESKTOP - Desktop Computers)
150 -- 2ND VALUE WILL BE 8980 (FS54888 - Sentinel Standard Desktop - FS Series)
151 -- 3RD VALUE IS 204 -- THAT IS WHAT TERRITORY IS CREATED FOR
152 -- AND WE ARE PASSING ib.inv_organization_id IN squal_num16 WHICH HAS VALUE 207
153 -- SO IT DOES NOT QUALIFY TERRITORY. SO now i am passsign org_id as squal_num16
154 , ib.owner_group_id squal_num17
155 , ib.language_id squal_num30
156 , ib.contract_service_id
157 , TB.PLANNED_START_DATE
158 , ib.system_id
159 , ib.cust_pref_lang_code
160 FROM jtf_tasks_b tb
161 , cs_incidents_all_b ib
162 , cs_incidents_all_tl it
163 , hz_locations lo
164 , hz_parties pa
165 WHERE tb.task_id = p_task_id
166 AND tb.source_object_type_code = 'SR'
167 AND tb.source_object_id = ib.incident_id
168 AND tb.source_object_id = it.incident_id
169 AND it.LANGUAGE = USERENV('lang')
170 AND lo.location_id = csf_tasks_pub.get_task_location_id(tb.task_id, tb.address_id, tb.location_id)
171 AND ib.customer_id = pa.party_id(+);
172
173 -- Phone Area Code
174 CURSOR c_contact_point(b_party_id NUMBER) IS
175 SELECT phone_area_code
176 FROM hz_contact_points
177 WHERE owner_table_id = b_party_id
178 AND owner_table_name = 'HZ_PARTIES'
179 AND contact_point_type = 'PHONE'
180 AND primary_flag = 'Y';
181
182 -- Service Item ID and Organization ID
183 CURSOR c_contract(b_contract_service_id NUMBER) IS
184 SELECT TO_NUMBER(object1_id1) item_id
185 , TO_NUMBER(object1_id2) org_id
186 FROM okc_k_items
187 WHERE cle_id = b_contract_service_id;
188
189 -- Contact VIP code
190 CURSOR c_class_code(b_party_id NUMBER) IS
191 SELECT class_code
192 FROM hz_code_assignments
193 WHERE owner_table_name = 'HZ_PARTIES'
194 AND owner_table_id = b_party_id;
195 BEGIN
196 OPEN c_rec;
197
198 FETCH c_rec
199 INTO l_rec.task_id
200 , l_rec.service_request_id
201 , l_rec.party_id
202 , l_rec.country
203 , l_rec.party_site_id
204 , l_rec.city
205 , l_rec.postal_code
206 , l_rec.state
207 , l_rec.county
208 , l_rec.comp_name_range
209 , l_rec.province
210 , l_rec.num_of_employees
211 , l_rec.task_type_id
212 , l_rec.task_status_id
213 , l_rec.task_priority_id
214 , l_rec.incident_type_id
215 , l_rec.incident_severity_id
216 , l_rec.incident_urgency_id
217 , l_rec.problem_code
218 , l_rec.incident_status_id
219 , l_rec.platform_id
220 , l_rec.support_site_id
221 , l_rec.customer_site_id
222 , l_rec.sr_creation_channel
223 , l_rec.inventory_item_id
224 , l_rec.squal_char12
225 , l_rec.squal_char13
226 , l_rec.squal_num12
227 , l_rec.squal_num13
228 , l_rec.squal_num14
229 , l_rec.squal_num15
230 , l_rec.squal_num16
231 , l_rec.squal_num17
232 , l_rec.squal_num30
233 , l_contract_service_id
234 , L_PLANNED_START_DATE
235 , l_rec.SQUAL_NUM60
236 , l_rec.SQUAL_CHAR20;
237
238 IF c_rec%FOUND THEN
239 IF l_rec.party_id IS NOT NULL THEN
240 -- Contact Phone Area Code
241 OPEN c_contact_point(l_rec.party_id);
242 FETCH c_contact_point INTO l_rec.area_code;
243 CLOSE c_contact_point;
244
245 -- contact VIP code
246 OPEN c_class_code(l_rec.party_id);
247 FETCH c_class_code INTO l_rec.squal_char11;
248 CLOSE c_class_code;
249 END IF;
250
251 IF l_contract_service_id IS NOT NULL THEN
252 -- Service item item_id and org_id
253 OPEN c_contract(l_contract_service_id);
254 FETCH c_contract INTO l_rec.squal_num18, l_rec.squal_num19;
255 CLOSE c_contract;
256 END IF;
257 ELSE
258 -- fill in only the task_id
259 l_rec.task_id := p_task_id;
260 END IF;
261
262 CLOSE c_rec;
263
264 if l_planned_start_date < sysdate
265 then
266 l_planned_start_date := sysdate;
267 end if;
268
269 l_rec.time_of_day := to_char(l_planned_start_date,'HH24:MI');
270 l_rec.day_of_week := to_char(l_planned_start_date,'D');
271
272 RETURN l_rec;
273 END get_srv_task_rec;
274
275 /**
276 * Gets the Seeded Enabled Qualifier Names (and if required Labels) and
277 * populates the table G_ALL_QUALIFIERS.
278 */
279 PROCEDURE get_all_qualifiers IS
280 k PLS_INTEGER;
281 CURSOR c_desc IS
282 SELECT qual_usg_id qual_usg_id
283 , seeded_qual_name label
284 FROM jty_all_enabled_attributes_v
285 WHERE source_id = -1002
286 AND qual_type_id IN(-1002, -1005, -1006)
287 ORDER BY UPPER(seeded_qual_name);
288 l_rec qualifier_info_rec_type;
289 BEGIN
290 g_all_qualifiers.DELETE;
291 OPEN c_desc;
292 LOOP
293 FETCH c_desc INTO l_rec;
294 EXIT WHEN c_desc%NOTFOUND;
295 g_all_qualifiers(c_desc%ROWCOUNT) := l_rec;
296 END LOOP;
297 CLOSE c_desc;
298 END get_all_qualifiers;
299
300 /**
301 * Returns the Display Value for the Qualifier.
302 *
303 * If Tracing is not enabled, then it returns only Value concatenated
304 * with the Associated Value. If Tracing is enabled, it uses the SQL
305 * associated with the Qualifier and gets the Name / Description for
306 * the Qualifier (ID to Name Conversion).
307 *
308 * @param p_index Index to the Global All Qualifiers Table
309 * @param p_value Value for the Qualifier
310 * @param p_associated_value Associated Value for the Qualifier
311 */
312 FUNCTION get_display_value(
313 p_index IN PLS_INTEGER
314 , p_value IN VARCHAR2
315 , p_associated_value IN VARCHAR2
316 )
317 RETURN VARCHAR2 IS
318 l_tmp VARCHAR2(4000);
319 l_value VARCHAR2(360);
320 BEGIN
321 -- for the default case use the provided values
322 IF p_associated_value IS NULL THEN
323 l_value := p_value;
324 ELSE
325 l_value := SUBSTR(p_value || '/' || p_associated_value, 1, 360);
326 END IF;
327 RETURN l_value;
328 END get_display_value;
329
330 PROCEDURE set_generic_planwindow (
331 p_res_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
332 , p_start DATE
333 , p_end DATE
334 ) IS
335 i PLS_INTEGER;
336 BEGIN
337 i := p_res_tbl.FIRST;
338 WHILE i IS NOT NULL LOOP
339 p_res_tbl(i).start_date := p_start;
340 p_res_tbl(i).end_date := p_end;
341 i := p_res_tbl.NEXT(i);
342 END LOOP;
343 END set_generic_planwindow;
344
345 /**
346 * Adds the Qualifier identified by the Index to the global Task Qualifer Table with
347 * the value taken from the given Task Record and only when the value is Not Null.
348 * <br>
349 * Uses a Hard Coded Mapping between JTF_SEEDED_QUAL_USGS_V.QUAL_USG_ID
350 * and the fields in JTF_ASSIGN_PUB.JTF_SRV_TASK_REC_TYPE.
351 * <br>
352 * Qualifiers of type -1211, -1212 and -1218 have been disabled and
353 * therefore wont be set by this API.
354 *
355 * @param p_qualifiers Qualifier Table storing the Qualifiers
356 * @param p_index Index to the Global All Qualifiers Table
357 * @param p_task_rec Task Record containing the required Information
358 */
359 PROCEDURE add_qualifier(
360 p_qualifier_tbl IN OUT NOCOPY resource_qualifier_tbl_type
361 , p_index IN PLS_INTEGER
362 , p_task_rec IN jtf_assign_pub.jtf_srv_task_rec_type
363 ) IS
364 l_value VARCHAR2(360);
365 l_associated_value VARCHAR2(360);
366 i PLS_INTEGER;
367 BEGIN
368 IF g_all_qualifiers(p_index).qual_usg_id = -1037 THEN
369 l_value := p_task_rec.party_id;
370 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1038 THEN
371 l_value := p_task_rec.country;
372 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1039 THEN
373 l_value := p_task_rec.party_site_id;
374 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1040 THEN
375 l_value := p_task_rec.city;
376 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1041 THEN
377 l_value := p_task_rec.postal_code;
378 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1042 THEN
379 l_value := p_task_rec.state;
380 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1043 THEN
381 l_value := p_task_rec.area_code;
382 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1044 THEN
383 l_value := p_task_rec.county;
384 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1045 THEN
385 l_value := p_task_rec.comp_name_range;
386 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1046 THEN
387 l_value := p_task_rec.province;
388 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1047 THEN
389 l_value := p_task_rec.num_of_employees;
390 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1060 THEN
391 l_value := p_task_rec.task_type_id;
392 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1061 THEN
393 l_value := p_task_rec.task_status_id;
394 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1062 THEN
395 l_value := p_task_rec.task_priority_id;
396 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1048 THEN
397 l_value := p_task_rec.incident_type_id;
398 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1049 THEN
399 l_value := p_task_rec.incident_severity_id;
400 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1050 THEN
401 l_value := p_task_rec.incident_urgency_id;
402 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1051 THEN
403 l_value := p_task_rec.problem_code;
404 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1091 THEN
405 l_value := p_task_rec.incident_status_id;
406 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1092 THEN
407 l_value := p_task_rec.platform_id;
408 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1093 THEN
409 l_value := p_task_rec.support_site_id;
410 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1094 THEN
411 l_value := p_task_rec.customer_site_id;
412 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1095 THEN
413 l_value := p_task_rec.sr_creation_channel;
414 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1096 THEN
415 l_value := p_task_rec.inventory_item_id;
416 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1210 THEN
417 l_value := p_task_rec.squal_num14;
418 l_associated_value :=p_task_rec.squal_num15||'-'||p_task_rec.squal_num16;
419 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1216 THEN
420 l_value := p_task_rec.squal_num18;
421 l_associated_value := p_task_rec.squal_num19;
422 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1213 THEN
423 l_value := p_task_rec.squal_char20;
424 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1215 THEN
425 l_value := p_task_rec.squal_char11;
426 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1214 THEN
427 l_value := p_task_rec.squal_char13;
428 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1217 THEN
429 l_value := p_task_rec.squal_num17;
430 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1734 THEN
431 l_value := p_task_Rec.day_of_week;
432 ELSIF g_all_qualifiers(p_index).qual_usg_id = -1744 THEN
433 L_VALUE := P_TASK_REC.TIME_OF_DAY;
434 ELSIF G_ALL_QUALIFIERS(P_INDEX).QUAL_USG_ID = -1206 THEN
435 l_value := p_task_Rec.SQUAL_NUM60;
436 ELSIF G_ALL_QUALIFIERS(P_INDEX).QUAL_USG_ID = -1218 THEN
437 l_value := p_task_Rec.SQUAL_NUM15;
438 l_associated_value :=p_task_rec.squal_num16;
439 END IF;
440
441 IF l_value IS NOT NULL THEN
442 i := p_qualifier_tbl.COUNT + 1;
443 p_qualifier_tbl(i).qual_usg_id := g_all_qualifiers(p_index).qual_usg_id;
444 p_qualifier_tbl(i).label := g_all_qualifiers(p_index).label;
445 p_qualifier_tbl(i).use_flag := 'Y';
446 p_qualifier_tbl(i).value := l_value;
447 p_qualifier_tbl(i).associated_value := l_associated_value;
448 p_qualifier_tbl(i).display_value := get_display_value(p_index, l_value, l_associated_value);
449 END IF;
450 END add_qualifier;
451
452 /**
453 * Returns the Qualifier Table having the list of valid Qualifiers
454 * based on the Task Information of the given Task ID.
455 */
456 FUNCTION get_res_qualifier_table(p_task_id NUMBER)
457 RETURN resource_qualifier_tbl_type IS
458 m PLS_INTEGER;
459 l_task_rec jtf_assign_pub.jtf_srv_task_rec_type;
460 l_qualifier_tbl resource_qualifier_tbl_type;
461 BEGIN
462 -- Fetch all the Enabled Qualifiers
463 IF g_all_qualifiers.COUNT = 0 THEN
464 get_all_qualifiers;
465 END IF;
466
467 -- Get the Task Information
468 l_task_rec := get_srv_task_rec(p_task_id);
469
470 -- Loop thru the Qualifiers and add the valid Qualifier alone to the Table
471 m := g_all_qualifiers.FIRST;
472 WHILE m IS NOT NULL LOOP
473 add_qualifier(l_qualifier_tbl, m, l_task_rec);
474 m := g_all_qualifiers.NEXT(m);
475 END LOOP;
476
477 RETURN l_qualifier_tbl;
478 END get_res_qualifier_table;
479
480 /**
481 * Converts the given Qualifier Table to Assignment Manager API Record
482 * type.
483 * Assembles the selected Qualifiers for this Task from the Qualifier
484 * Table in to a Record Type understandable by JTF Assignment Manager.
485 * <br>
486 * Uses a Hard Coded Mapping between JTF_SEEDED_QUAL_USGS_V.QUAL_USG_ID
487 * and the fields in JTF_ASSIGN_PUB.JTF_SRV_TASK_REC_TYPE.
488 * <br>
489 * The Task and SR Number must be set by the caller and wont be set by
490 * this API. Moreover Qualifiers of type -1211, -1212 and -1218 have
491 * been disabled and therefore wont be set by this API.
492 *
493 * @param p_table Qualifier Table having the list of Task Qualifiers
494 */
495 FUNCTION get_qualified_task_rec(p_table resource_qualifier_tbl_type)
496 RETURN jtf_assign_pub.jtf_srv_task_rec_type IS
497 k PLS_INTEGER;
498 task_rec jtf_assign_pub.jtf_srv_task_rec_type;
499 BEGIN
500 k := p_table.FIRST;
501 WHILE k IS NOT NULL LOOP
502 IF p_table(k).use_flag = 'Y' THEN
503 IF p_table(k).qual_usg_id = -1037 THEN
504 task_rec.party_id := p_table(k).VALUE;
505 ELSIF p_table(k).qual_usg_id = -1038 THEN
506 task_rec.country := p_table(k).VALUE;
507 ELSIF p_table(k).qual_usg_id = -1039 THEN
508 task_rec.party_site_id := p_table(k).VALUE;
509 ELSIF p_table(k).qual_usg_id = -1040 THEN
510 task_rec.city := p_table(k).VALUE;
511 ELSIF p_table(k).qual_usg_id = -1041 THEN
512 task_rec.postal_code := p_table(k).VALUE;
513 ELSIF p_table(k).qual_usg_id = -1042 THEN
514 task_rec.state := p_table(k).VALUE;
515 ELSIF p_table(k).qual_usg_id = -1043 THEN
516 task_rec.area_code := p_table(k).VALUE;
517 ELSIF p_table(k).qual_usg_id = -1044 THEN
518 task_rec.county := p_table(k).VALUE;
519 ELSIF p_table(k).qual_usg_id = -1045 THEN
520 task_rec.comp_name_range := p_table(k).VALUE;
521 ELSIF p_table(k).qual_usg_id = -1046 THEN
522 task_rec.province := p_table(k).VALUE;
523 ELSIF p_table(k).qual_usg_id = -1047 THEN
524 task_rec.num_of_employees := p_table(k).VALUE;
525 ELSIF p_table(k).qual_usg_id = -1060 THEN
526 task_rec.task_type_id := p_table(k).VALUE;
527 ELSIF p_table(k).qual_usg_id = -1061 THEN
528 task_rec.task_status_id := p_table(k).VALUE;
529 ELSIF p_table(k).qual_usg_id = -1062 THEN
530 task_rec.task_priority_id := p_table(k).VALUE;
531 ELSIF p_table(k).qual_usg_id = -1048 THEN
532 task_rec.incident_type_id := p_table(k).VALUE;
533 ELSIF p_table(k).qual_usg_id = -1049 THEN
534 task_rec.incident_severity_id := p_table(k).VALUE;
535 ELSIF p_table(k).qual_usg_id = -1050 THEN
536 task_rec.incident_urgency_id := p_table(k).VALUE;
537 ELSIF p_table(k).qual_usg_id = -1051 THEN
538 task_rec.problem_code := p_table(k).VALUE;
539 ELSIF p_table(k).qual_usg_id = -1091 THEN
540 task_rec.incident_status_id := p_table(k).VALUE;
541 ELSIF p_table(k).qual_usg_id = -1092 THEN
542 task_rec.platform_id := p_table(k).VALUE;
543 ELSIF p_table(k).qual_usg_id = -1093 THEN
544 task_rec.support_site_id := p_table(k).VALUE;
545 ELSIF p_table(k).qual_usg_id = -1094 THEN
546 task_rec.customer_site_id := p_table(k).VALUE;
547 ELSIF p_table(k).qual_usg_id = -1095 THEN
548 task_rec.sr_creation_channel := p_table(k).VALUE;
549 ELSIF p_table(k).qual_usg_id = -1096 THEN
550 task_rec.inventory_item_id := p_table(k).VALUE;
551 ELSIF p_table(k).qual_usg_id = -1210 THEN
552 task_rec.squal_num14 := p_table(k).VALUE;
553 task_rec.squal_num15 := SUBSTR(p_table(k).associated_value,1,INSTR(p_table(k).associated_value,'-')-1);
554 if task_rec.squal_num15 is not null
555 then
556 task_rec.squal_num16 := SUBSTR(p_table(k).associated_value,INSTR(p_table(k).associated_value,'-')+1,LENGTH(p_table(k).associated_value));
557 end if;
558 ELSIF p_table(k).qual_usg_id = -1217 THEN
559 task_rec.squal_num17 := p_table(k).VALUE;
560 ELSIF p_table(k).qual_usg_id = -1216 THEN
561 task_rec.squal_num18 := p_table(k).VALUE;
562 task_rec.squal_num19 := p_table(k).associated_value;
563 ELSIF p_table(k).qual_usg_id = -1213 THEN
564 task_rec.squal_char20 := p_table(k).VALUE;
565 ELSIF p_table(k).qual_usg_id = -1215 THEN
566 task_rec.squal_char11 := p_table(k).VALUE;
567 ELSIF p_table(k).qual_usg_id = -1214 THEN
568 task_rec.squal_char13 := p_table(k).VALUE;
569 ELSIF p_table(k).qual_usg_id = -1734 THEN
570 task_rec.DAY_OF_WEEK := p_table(k).VALUE;
571 ELSIF p_table(k).qual_usg_id = -1744 THEN
572 TASK_REC.TIME_OF_DAY := P_TABLE(K).VALUE;
573 ELSIF p_table(k).qual_usg_id = -1206 THEN
574 task_rec.squal_num60 := p_table(k).VALUE;
575 ELSIF p_table(k).qual_usg_id = -1218 THEN
576 task_rec.squal_num15 := p_table(k).VALUE;
577 task_rec.squal_num16 := p_table(k).associated_value;
578
579 END IF;
580 END IF;
581 k := p_table.NEXT(k);
582 END LOOP;
583 RETURN task_rec;
584 END get_qualified_task_rec;
585
586 /**
587 * Intersect the Resource results found in two tables and returns a
588 * Table having only those Resources found in both the Tables.
589 *
590 * The parameters P_START and P_END signify the Plan Window for which
591 * Resources are desired. If either of the input tables doesnt have
592 * the Plan Window stamped for any resource, these two dates will be used
593 * in place of them. After this action, the most restrictive Plan Window
594 * among the two windows is used as the Plan Window of the output table.
595 * <br>
596 * Side Effect of the API. Second Table may have entries deleted after
597 * the operation.
598 *
599 * @param p_res_1_tbl Resource Table 1
600 * @param p_res_2_tbl Resource Table 2
601 * @param p_start Start Date of the Window
602 * @param p_end End Date of the Window
603 * @return Common Resource Table (JTF_ASSIGN_PUB.ASSIGNRESOURCES_TBL_TYPE)
604 */
605 FUNCTION intersect_results(
606 p_res_1_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
607 , p_res_2_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
608 , p_start DATE
609 , p_end DATE
610 ) RETURN jtf_assign_pub.assignresources_tbl_type IS
611 i PLS_INTEGER;
612 j PLS_INTEGER;
613 k PLS_INTEGER;
614 l_res_tbl jtf_assign_pub.assignresources_tbl_type;
615 BEGIN
616 k := 0;
617 i := p_res_1_tbl.FIRST;
618 WHILE i IS NOT NULL LOOP
619 j := p_res_2_tbl.FIRST;
620 WHILE j IS NOT NULL LOOP
621 EXIT WHEN p_res_2_tbl(j).resource_id = p_res_1_tbl(i).resource_id
622 AND p_res_2_tbl(j).resource_type = p_res_1_tbl(i).resource_type;
623 j := p_res_2_tbl.NEXT(j);
624 END LOOP;
625
626 -- We have an intersection between first table and second. Add to the output table
627 IF j IS NOT NULL THEN
628 k := k + 1;
629 l_res_tbl(k) := p_res_1_tbl(i);
630 l_res_tbl(k).start_date := GREATEST( NVL(p_res_1_tbl(i).start_date, p_start)
631 , NVL(p_res_2_tbl(j).start_date, p_start)
632 );
633 l_res_tbl(k).end_date := LEAST( NVL(p_res_1_tbl(i).end_date, p_end)
634 , NVL(p_res_2_tbl(j).end_date, p_end)
635 );
636
637 IF p_res_2_tbl(j).skill_level IS NOT NULL THEN
638 l_res_tbl(k).skill_level := p_res_2_tbl(j).skill_level;
639 END IF;
640
641 IF p_res_2_tbl(j).TERR_ID IS NOT NULL AND p_res_2_tbl(j).TERR_ID <> -1 THEN
642 l_res_tbl(k).TERR_ID := p_res_2_tbl(j).TERR_ID;
643 END IF;
644
645 IF p_res_2_tbl(j).TERR_RANK IS NOT NULL AND p_res_2_tbl(j).TERR_RANK <> -1 THEN
646 l_res_tbl(k).TERR_RANK := p_res_2_tbl(j).TERR_RANK;
647 END IF;
648
649 p_res_2_tbl.DELETE(j); -- So that Table is smaller for other iterations.
650
651 END IF;
652 i := p_res_1_tbl.NEXT(i);
653 END LOOP;
654 RETURN l_res_tbl;
655 END intersect_results;
656
657 /**
658 * Union the Resource results found in two tables and returns a
659 * Table having all those Resources found in both the Tables.
660 *
661 * In case of duplicate rows, row from 'p_res_1_tbl' will override.
662 *
663 * Side Effect of the API. Second Table may have entries deleted after
664 * the operation.
665 *
666 * @param p_res_1_tbl Resource Table 1
667 * @param p_res_2_tbl Resource Table 2
668 * @return Common Resource Table (JTF_ASSIGN_PUB.ASSIGNRESOURCES_TBL_TYPE)
669 */
670 FUNCTION union_results(
671 p_res_1_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
672 , p_res_2_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
673 ) RETURN jtf_assign_pub.assignresources_tbl_type IS
674 i PLS_INTEGER;
675 j PLS_INTEGER;
676 k PLS_INTEGER;
677 l_res_tbl jtf_assign_pub.assignresources_tbl_type;
678 BEGIN
679 k := p_res_1_tbl.LAST;
680 i := p_res_2_tbl.FIRST;
681
682 IF p_res_1_tbl.COUNT > 0 AND p_res_2_tbl.COUNT < 1
683 THEN
684 RETURN p_res_1_tbl;
685 END IF;
686
687 IF p_res_2_tbl.COUNT > 0 AND p_res_1_tbl.COUNT < 1
688 THEN
689 RETURN p_res_2_tbl;
690 END IF;
691
692 IF p_res_2_tbl.COUNT = 0 AND p_res_1_tbl.COUNT = 0
693 THEN
694 RETURN l_res_tbl;
695 END IF;
696
697 WHILE i IS NOT NULL LOOP
698 j := p_res_1_tbl.FIRST;
699 WHILE j IS NOT NULL LOOP
700 EXIT WHEN p_res_2_tbl(i).resource_id = p_res_1_tbl(j).resource_id
701 AND p_res_2_tbl(i).resource_type = p_res_1_tbl(j).resource_type;
702
703 j := p_res_1_tbl.NEXT(j);
704 END LOOP;
705
706 IF j IS NULL THEN
707 p_res_1_tbl(k+1) := p_res_2_tbl(i);
708 k := p_res_1_tbl.LAST;
709 END IF;
710
711
712 i := p_res_2_tbl.NEXT(i);
713 END LOOP;
714 RETURN p_res_1_tbl;
715 END union_results;
716
717
718 /**
719 * Returns the Skilled Resources for a Task overlapping the given
720 * Plan Window.
721 * <br>
722 * This API will return the list of all Skilled Resources for the Task
723 * with the activity date lying between the passed Plan Window. There
724 * will be an individual plan window (Adapted) for each resource.
725 * <br>
726 * If Resource ID is passed, then the API returns only one record
727 * corresponding to the passed Resource if he has the Skill Active
728 * during the given Times as desired by the Task.
729 * <br>
730 * The API makes use of the profile CSF_SKILL_LEVEL_MATCH to determine
731 * whether the Resource has a Skill Level comparable with the Task requirements
732 * as dictated by the profile.
733 * Usage of the Profile is as follows
734 * 1 - EQUAL TO or SMALLER THAN
735 * 2 - EQUAL TO --> (Default Value)
736 * 3 - EQUAL TO or GREATER THAN
737 * <br>
738 * Note that the API is made a PROCEDURE from its initial version of being a
739 * FUNCTION so that we can use the NOCOPY Compiler Directive and avoid the
740 * expensive Table Copy Happening during each call.
741 *
742 * @param p_task_id Task ID of the Task to be considered
743 * @param p_start Start Date Time of the Window
744 * @param p_end End Date Time of the Window
745 * @param p_resource_id Resource ID (Optional)
746 * @param p_resource_type Resource Type (Optional)
747 * @param x_skilled_res_tbl Skilled Resource Table
748 */
749 PROCEDURE get_skilled_resources(
750 p_task_id IN NUMBER
751 , p_start IN DATE
752 , p_end IN DATE
753 , p_resource_id IN NUMBER DEFAULT NULL
754 , p_resource_type IN VARCHAR2 DEFAULT NULL
755 , x_skilled_res_tbl OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
756 ) IS
757 l_levelmatch CONSTANT NUMBER := NVL(fnd_profile.VALUE('CSF_SKILL_LEVEL_MATCH'), 2);
758 j PLS_INTEGER;
759
760 CURSOR c_resource_plan_window IS
761 SELECT rs.resource_id
762 , rs.resource_type
763 , rs.winstart
764 , rs.winend
765 , rs.count_of_matching_skills
766 , rs.skill_level
767 FROM (SELECT rs.resource_id
768 , rs.resource_type
769 , GREATEST(
770 MAX(rs.start_date_active)
771 , NVL(MAX(ss.start_date_active), p_start)
772 , p_start
773 ) winstart
774 , LEAST(
775 NVL(MIN(rs.end_date_active + 1), p_end)
776 , NVL(MIN(ss.end_date_active + 1), p_end)
777 , p_end
778 ) winend
779 , COUNT(*) count_of_matching_skills
780 , SUM( 1/rsl.step_value ) skill_level
781 FROM csf_resource_skills_b rs
782 , csf_required_skills_b ts
783 , csf_skill_levels_b rsl
784 , csf_skill_levels_b tsl
785 , csf_skills_b ss
786 WHERE DECODE(
787 SIGN(rsl.step_value - tsl.step_value)
788 , -1, DECODE(l_levelmatch, 1, 'Y', 'N')
789 , 0, 'Y'
790 , 1, DECODE(l_levelmatch, 3, 'Y', 'N')
791 ) = 'Y'
792 AND rsl.skill_level_id = rs.skill_level_id
793 AND tsl.skill_level_id = ts.skill_level_id
794 AND TRUNC(rs.start_date_active) < p_end
795 AND (TRUNC(rs.end_date_active + 1) > p_start OR rs.end_date_active IS NULL)
796 AND (rs.resource_id = p_resource_id OR p_resource_id IS NULL)
797 AND (rs.resource_type = p_resource_type OR p_resource_type IS NULL)
798 AND NVL(ts.disabled_flag, 'N') <> 'Y'
799 AND ts.has_skill_type = 'TASK'
800 AND ts.has_skill_id = p_task_id
801 AND ss.skill_id(+) = rs.skill_id
802 AND (
803 ts.skill_type_id NOT IN (2, 3)
804 AND rs.skill_id = ts.skill_id
805 AND ts.skill_type_id = rs.skill_type_id
806 AND TRUNC(ss.start_date_active) < SYSDATE
807 AND TRUNC(NVL(ss.end_date_active, SYSDATE) + 1) > SYSDATE
808 OR ts.skill_type_id = 2
809 AND rs.skill_id = ts.skill_id
810 AND ts.skill_type_id = rs.skill_type_id
811 AND EXISTS (SELECT 1 FROM mtl_system_items_kfv msi WHERE msi.inventory_item_id = rs.skill_id)
812 OR ts.skill_type_id = 3
813 AND rs.skill_id = ts.skill_id
814 AND ts.skill_type_id = rs.skill_type_id
815 AND EXISTS (SELECT 1
816 FROM mtl_item_categories mic
817 WHERE mic.category_id = rs.skill_id
818 AND category_set_id = fnd_profile.VALUE('CS_SR_DEFAULT_CATEGORY_SET'))
819 /* OR ts.skill_type_id = 2
820 AND rs.skill_type_id = 3
821 AND NOT EXISTS (SELECT 1
822 FROM csf_required_skills_b ts2
823 , mtl_item_categories mic
824 WHERE NVL(ts2.disabled_flag, 'N') <> 'Y'
825 AND ts2.has_skill_type = ts.has_skill_type
826 AND ts2.has_skill_id = ts.has_skill_id
827 AND ts2.required_skill_id <> ts.required_skill_id
828 AND ts2.skill_type_id = 3
829 AND mic.inventory_item_id = ts.skill_id
830 AND mic.category_set_id = fnd_profile.VALUE('CS_SR_DEFAULT_CATEGORY_SET')
831 AND mic.category_id = ts2.skill_id)
832 AND NOT EXISTS (SELECT 1
833 FROM csf_resource_skills_b rs2
834 WHERE TRUNC(rs2.start_date_active) < p_end
835 AND (TRUNC(rs2.end_date_active + 1) > p_start OR rs2.end_date_active IS NULL)
836 AND rs2.resource_id = rs.resource_id
837 AND rs2.skill_id = ts.skill_id
838 AND rs2.skill_type_id = ts.skill_type_id)
839 AND EXISTS (SELECT category_id
840 FROM mtl_item_categories mic
841 WHERE mic.inventory_item_id = ts.skill_id
842 AND mic.category_set_id = fnd_profile.VALUE('CS_SR_DEFAULT_CATEGORY_SET')
843 AND mic.category_id = rs.skill_id) */
844 )
845 GROUP BY rs.resource_id, rs.resource_type) rs
846 , (
847 SELECT COUNT(*) count_of_req_skills
848 FROM csf_required_skills_b
849 WHERE NVL(disabled_flag, 'N') <> 'Y'
850 AND has_skill_type = 'TASK'
851 AND has_skill_id = p_task_id
852 ) ts
853 WHERE rs.count_of_matching_skills = ts.count_of_req_skills
854 AND rs.winstart < rs.winend;
855
856
857 BEGIN
858 x_skilled_res_tbl.DELETE;
859 j := 0;
860 FOR i IN c_resource_plan_window LOOP
861 j := j + 1;
862 x_skilled_res_tbl(j).resource_id := i.resource_id;
863 x_skilled_res_tbl(j).resource_type := i.resource_type;
864 x_skilled_res_tbl(j).start_date := i.winstart;
865 x_skilled_res_tbl(j).end_date := i.winend;
866 x_skilled_res_tbl(j).terr_id := -1;
867 x_skilled_res_tbl(j).terr_rank := -1;
868 x_skilled_res_tbl(j).skill_level := i.skill_level;
869 x_skilled_res_tbl(j).preference_type := 'SK';
870 END LOOP;
871 END get_skilled_resources;
872
873 /**
874 * Sorts the Resources in the given list based on their distance to the given
875 * Task from their Home Address.
876 *
877 * If the Task doesnt have a valid Geometry, then the API doesnt do anything. It
878 * merely returns the original list of resources without sorting.
879 * <br>
880 * Each Resource in the given list is picked up iteratively and its Geo-Distance
881 * from the Task is computed using the Geometry of the Task and that of the
882 * Resource Home Address (Location Finder will be invoked if necessary).
883 *
884 * @param p_unsorted_res_tbl List of UnSorted Resources
885 * @param p_task_id Task ID of the Task to be performed
886 * @param p_start Start of the Window to get that Period's Address
887 * @param p_end End of the Window to get that Period's Address
888 * @returns Sorted Resources List (JTF_ASSIGN_PUB.ASSIGNRESOURCES_TBL_TYPE)
889 */
890 FUNCTION sort_resource_by_distance(
891 p_unsorted_res_tbl jtf_assign_pub.assignresources_tbl_type
892 , p_task_id NUMBER
893 , p_start DATE
894 , p_end DATE
895 )
896 RETURN jtf_assign_pub.assignresources_tbl_type IS
897 l_return_status VARCHAR2(1);
898 l_msg_count NUMBER;
899 l_msg_data VARCHAR2(2000);
900 l_sorted_res_tbl jtf_assign_pub.assignresources_tbl_type;
901 l_res_dist_tbl csf_resource_tbl;
902 i PLS_INTEGER;
903 j PLS_INTEGER;
904 l_pref_res_cnt PLS_INTEGER;
905 l_address csf_resource_address_pvt.address_rec_type;
906 l_geometry MDSYS.SDO_GEOMETRY;
907 l_task_lat NUMBER;
908 l_task_lon NUMBER;
909 l_res_lat NUMBER;
910 l_res_lon NUMBER;
911 l_res_position MDSYS.SDO_POINT_TYPE;
912 l_valid_geo VARCHAR2(5);
913 l_distance NUMBER;
914
915 CURSOR c_task_geometry IS
916 SELECT l.geometry
917 FROM jtf_tasks_b t, hz_locations l
918 WHERE t.task_id = p_task_id
919 AND l.location_id = csf_tasks_pub.get_task_location_id(t.task_id, t.address_id, t.location_id);
920
921 CURSOR c_sorted_resources IS
922 SELECT resource_index
923 , distance
924 FROM TABLE(CAST(l_res_dist_tbl AS csf_resource_tbl) )
925 ORDER BY preferred_resource_flag desc, distance, resource_index;
926 BEGIN
927 -- Validate the Geometry of the Task.
928 -- If Task has no or invalid geometry, no need to sort by distance at all
929 OPEN c_task_geometry;
930 FETCH c_task_geometry INTO l_geometry;
931 CLOSE c_task_geometry;
932
933 IF l_geometry IS NULL THEN
934 RETURN p_unsorted_res_tbl;
935 END IF;
936
937 csf_locus_pub.verify_locus(
938 p_api_version => 1.0
939 , x_msg_count => l_msg_count
940 , x_msg_data => l_msg_data
941 , x_return_status => l_return_status
942 , p_locus => l_geometry
943 , x_result => l_valid_geo
944 );
945
946 IF l_valid_geo = 'FALSE' THEN
947 RETURN p_unsorted_res_tbl;
948 END IF;
949
950 IF l_geometry.sdo_elem_info IS NOT NULL
951 AND l_geometry.sdo_ordinates IS NOT NULL
952 THEN
953 l_task_lon := ROUND(l_geometry.sdo_ordinates(1), 8);
954 l_task_lat := ROUND(l_geometry.sdo_ordinates(2), 8);
955 ELSIF l_geometry.sdo_point IS NOT NULL
956 THEN
957 l_task_lon := ROUND(l_geometry.sdo_point.x, 8);
958 l_task_lat := ROUND(l_geometry.sdo_point.y, 8);
959 ELSE
960 l_task_lon := -9999;
961 l_task_lat := -9999;
962 END IF;
963
964 l_res_dist_tbl := csf_resource_tbl();
965 i := p_unsorted_res_tbl.FIRST;
966 l_pref_res_cnt := 1;
967 WHILE i IS NOT NULL LOOP
968 l_res_position := get_location(p_unsorted_res_tbl(i).resource_id, p_unsorted_res_tbl(i).resource_type, p_start);
969
970 IF l_res_position IS NOT NULL AND l_res_position.x <> -9999 AND l_res_position.y <> -9999 THEN
971 l_distance := geo_distance(l_task_lon, l_task_lat, l_res_position.x, l_res_position.y);
972 ELSE
973 l_distance := fnd_api.g_miss_num;
974 END IF;
975
976 l_res_dist_tbl.EXTEND;
977 l_res_dist_tbl(i) :=
978 csf_resource(
979 'N'
980 , i
981 , l_distance
982 , NULL
983 , NULL
984 , NULL
985 , NULL
986 , NULL
987 );
988
989 IF p_unsorted_res_tbl(i).preference_type = 'I' OR p_unsorted_res_tbl(i).preference_type = 'C' THEN
990 l_res_dist_tbl(i).preferred_resource_flag := 'Y';
991 END IF;
992
993 i := p_unsorted_res_tbl.NEXT(i);
994 END LOOP;
995
996 i := 0;
997 FOR v_resource IN c_sorted_resources LOOP
998 i := i + 1;
999 l_sorted_res_tbl(i) := p_unsorted_res_tbl(v_resource.resource_index);
1000 END LOOP;
1001 RETURN l_sorted_res_tbl;
1002 EXCEPTION
1003 WHEN OTHERS THEN
1004 RETURN p_unsorted_res_tbl;
1005 END sort_resource_by_distance;
1006
1007 /**
1008 * Reduce the number of Resources passed to a maximum value as determined by
1009 * the profile "CSR: Maximum number of Resources".
1010 *
1011 * The API doesnt delete resources as such. It first prunes the resource list
1012 * by considering only those Resources who have valid Shift Definitions between
1013 * the given dates and then give the top N resources. Note that it will be
1014 * better if the Resources are already sorted in the order of their preference.
1015 *
1016 * @param p_res_tbl List of Sorted Resources
1017 * @param p_start Start of the Window for Valid Shifts Consideration
1018 * @param p_end End of the Window for Valid Shifts Consideration
1019 * @returns Top N Resources as determined by the MAXNRSELECTEDRES profile.
1020 */
1021 FUNCTION reduce_resource_list(
1022 p_res_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
1023 , p_start DATE
1024 , p_end DATE
1025 )
1026 RETURN jtf_assign_pub.assignresources_tbl_type IS
1027 l_max_resources NUMBER;
1028 l_return_status VARCHAR2(1);
1029 l_msg_count NUMBER;
1030 l_msg_data VARCHAR2(2000);
1031 l_shift_tbl jtf_calendar_pub.shift_tbl_type;
1032 l_out_tbl jtf_assign_pub.assignresources_tbl_type;
1033 i PLS_INTEGER;
1034 j PLS_INTEGER;
1035 cnt PLS_INTEGER;
1036 BEGIN
1037 -- Get the maximum number of allowed Resources
1038 -- Modified to get the profile value from Scheduler API
1039 l_max_resources := csr_scheduler_pub.get_sch_parameter_value('spMaxResources');
1040
1041 -- Validate retrieved maximum value
1042 IF NVL(l_max_resources, 0) <= 0 THEN
1043 l_max_resources := p_res_tbl.COUNT;
1044 END IF;
1045
1046 i := p_res_tbl.FIRST;
1047 j := 0;
1048
1049
1050 WHILE i IS NOT NULL LOOP
1051 cnt:= p_res_tbl.NEXT(i);
1052 WHILE cnt <= p_res_tbl.LAST LOOP
1053 IF p_res_tbl(i).resource_id = p_res_tbl(cnt).resource_id AND
1054 p_res_tbl(i).resource_type = p_res_tbl(cnt).resource_type THEN
1055 p_res_tbl.delete(cnt);
1056 END IF;
1057 cnt:= p_res_tbl.next(cnt);
1058 END LOOP;
1059
1060 jtf_calendar_pub.get_resource_shifts(
1061 p_api_version => 1
1062 , p_init_msg_list => fnd_api.g_true
1063 , x_return_status => l_return_status
1064 , x_msg_count => l_msg_count
1065 , x_msg_data => l_msg_data
1066 , p_resource_id => p_res_tbl(i).resource_id
1067 , p_resource_type => p_res_tbl(i).resource_type
1068 , p_start_date => p_start
1069 , p_end_date => p_end
1070 , x_shift => l_shift_tbl
1071 );
1072
1073
1074 IF l_return_status = fnd_api.g_ret_sts_success OR l_shift_tbl.COUNT > 0 THEN
1075 j := j + 1;
1076 l_out_tbl(j) := p_res_tbl(i);
1077 EXIT WHEN j = l_max_resources;
1078 END IF;
1079 i := p_res_tbl.NEXT(i);
1080 END LOOP;
1081
1082
1083 RETURN l_out_tbl;
1084 EXCEPTION
1085 WHEN OTHERS THEN
1086 RETURN p_res_tbl;
1087 END reduce_resource_list;
1088
1089 /**
1090 * Returns the Error Message that is encountered during Resource Selection
1091 * process based on the Flags passed. Each Flag corresponds to a But in the
1092 * Error Message Table. See INIT_ASSIGN_ERRORS for more information.
1093 *
1094 * @param p_flags Flags used to select Resources for the Task
1095 * @return Name of the Error Message encountered.
1096 */
1097 FUNCTION get_assign_error_msg(p_flags IN NUMBER)
1098 RETURN VARCHAR2 IS
1099 l_msg VARCHAR2(100);
1100 BEGIN
1101 l_msg := 'CSF_R_NO_RES_FOR_TASK';
1102 IF p_flags IS NOT NULL AND g_assign_errors.EXISTS(p_flags) THEN
1103 l_msg := g_assign_errors(p_flags);
1104 END IF;
1105 RETURN l_msg;
1106 END get_assign_error_msg;
1107
1108 /**
1109 * Adds the suggested resources to the end of the given resource table if
1110 * the resource is not already present in the resource table.
1111 * @param p_res_tbl Resource Table and where suggested res will be added
1112 * @param p_suggested_res_id_tbl Suggested Resource ID Table
1113 * @param p_suggested_res_type_tbl Suggested Resource Type Table
1114 */
1115 PROCEDURE add_suggested_resources(
1116 p_res_tbl IN OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
1117 , p_suggested_res_id_tbl IN jtf_number_table
1118 , p_suggested_res_type_tbl IN jtf_varchar2_table_100
1119 , p_start_date IN DATE
1120 , p_end_date IN DATE
1121 ) IS
1122 i PLS_INTEGER;
1123 j PLS_INTEGER;
1124 l_res_found BOOLEAN;
1125 BEGIN
1126 -- Validate the Inputs.
1127 IF p_suggested_res_id_tbl IS NULL
1128 OR p_suggested_res_type_tbl IS NULL
1129 OR p_suggested_res_id_tbl.COUNT <= 0
1130 OR p_suggested_res_type_tbl.COUNT <> p_suggested_res_id_tbl.COUNT
1131 THEN
1132 RETURN;
1133 END IF;
1134
1135 -- Add each Suggested Resource Info to the Resource List if its not already present.
1136 j := p_suggested_res_id_tbl.FIRST;
1137 WHILE j IS NOT NULL LOOP
1138
1139 -- Check whether the Resource list already has the Suggested Resource.
1140 l_res_found := FALSE;
1141 i := p_res_tbl.FIRST;
1142 WHILE i IS NOT NULL LOOP
1143 l_res_found := p_res_tbl(i).resource_id = p_suggested_res_id_tbl(j)
1144 AND p_res_tbl(i).resource_type = p_suggested_res_type_tbl(j);
1145
1146 EXIT WHEN l_res_found;
1147 i := p_res_tbl.NEXT(i);
1148 END LOOP;
1149
1150 IF NOT l_res_found THEN
1151 i := NVL(p_res_tbl.LAST, 0) + 1;
1152
1153 p_res_tbl(i).resource_id := p_suggested_res_id_tbl(j);
1154 p_res_tbl(i).resource_type := p_suggested_res_type_tbl(j);
1155 p_res_tbl(i).start_date := p_start_date;
1156 p_res_tbl(i).end_date := p_end_date;
1157 p_res_tbl(i).terr_id := -1;
1158 p_res_tbl(i).terr_rank := -1;
1159 END IF;
1160
1161 j := p_suggested_res_id_tbl.NEXT(j);
1162 END LOOP;
1163 END add_suggested_resources;
1164
1165
1166 /**
1167 * Gets the Qualified Resources for a Task by calling JTF Assignment Manager
1168 * and also making use of the Required Skills of the Task if Required to reduce
1169 * the Resource List.
1170 *
1171 * <br>
1172 *
1173 * The reason for CSF to maintain its own Assignment Manager rather than
1174 * completely relying on JTF Assignment Manager has two fold reasons.
1175 *
1176 * <br>
1177 *
1178 * TQ is secondary for JTF Assignment Manager API.
1179 * Suppose in Schedule Advise Window, all the Flags are checked... then
1180 * JTF Assignment Manager will give preference to Contracts and IB only.
1181 * Only when both of returns ZERO resources, then JTF will consider TQ.
1182 * But DC expects an intersection of the three results.
1183 * Moreover if both Contracts and IB are checked, then JTF will use
1184 * the profile "JTFAM: Resource Search Order (JTF_AM_PREF_RES_ORDER)" to
1185 * find out which one to return ultimately. If the value CONTRACTS, then
1186 * CONTRACTS - Only Contracts is returned. If None, IB is returned.
1187 * IB - Only IB is returned. If None, Contracts is returned.
1188 * BOTH - Intersection of Contracts and IB Resources are returned.
1189 *
1190 * <br>
1191 *
1192 * JTF doesnt know "ABC of Skills"
1193 * Resources and Skills is completely a Field Service Functionality. A
1194 * Resource can be attached to a Skill with a particular Skill Level.
1195 * So can a Task be tied to a Skill with a particular Skill Level. If
1196 * Skill based Flag is checked, then the Resource needs to have the same
1197 * Skill Set with a Comparable Skill Level as required by the Task.
1198 * Comparable Skill Level !!! - What is that ?
1199 * The profile "CSF: Skill Level Match (CSF_SKILL_LEVEL_MATCH)" is used
1200 * to decide whether the Resource has the Required Skill Level as required
1201 * by the Task.
1202 * EQUAL TO OR SMALLER THAN - Resource should have a Skill Level equal to
1203 * or lesser than that of the Task.
1204 * EQUAL TO - Resource should have a Skill Level equal to
1205 * that of the Task.
1206 * EQUAL TO OR GREATER THAN - Resource should have a Skill Level equal to
1207 * or greater than that of the Task.
1208 * Note that the Task needs to have Skills. Otherwise the Flag wont be used
1209 * at all for getting the Qualified Resources.
1210 *
1211 * <br>
1212 *
1213 * Thus CSF Assignment Manager API will call JTF Assignment Manager separately
1214 * for Contracts / IB and then for Territory. Do an intersection of the Resources
1215 * obtained thru the two calls and pruned by Skill Sets. Note that it gets
1216 * Contracts / IB Resources from JTF in one call and so the user should make use
1217 * the profile JTF_AM_PREF_RES_ORDER to get intersected results.
1218 *
1219 * <br>
1220 *
1221 * CSF Assignment Manager still doesnt pass the parameter P_FILTER_EXCLUDED_RESOURCE
1222 * so that JTF Assignment Manager doesnt return Excluded Resources.
1223 * CSF Assignment Manager still doesnt pass the parameter P_BUSINESS_PROCESS_ID
1224 * so that JTF Assignment Manager returns only those Resources who belong to
1225 * Field Service Business Process when Preferred Resources are entered in Contracts.
1226 *
1227 * @param p_api_version API Version (1.0)
1228 * @param p_init_msg_list Initialize Message List
1229 * @param x_return_status Return Status of the Procedure.
1230 * @param x_msg_count Number of Messages in the Stack.
1231 * @param x_msg_data Stack of Error Messages.
1232 * @param p_task_id Task Idenfifier
1233 * @param p_task_rec Qualified Task Record
1234 * @param p_scheduling_mode Scheduling Mode used. (A, I, W)
1235 * @param p_start Start Date of the Plan Window
1236 * @param p_end End Date of the Plan Window
1237 * @param p_duration Duration of the Task (Used by JTF to find out Available Resources)
1238 * @param p_duration_uom UOM of the above Duration
1239 * @param p_contracts_flag Get Contracts Preferred Resources ('Y'/'N')
1240 * @param p_ib_flag Get IB Preferred Resources ('Y'/'N')
1241 * @param p_territory_flag Get Winning Territory Resources ('Y'/'N')
1242 * @param p_skill_flag Get Skilled Resources ('Y'/'N')
1243 * @param p_calendar_flag Get only Available Resources. Passed to JTF ('Y'/'N')
1244 * @param p_sort_flag Sort the Resources based on their distance from Task ('Y'/'N')
1245 * @param p_suggested_res_id_tbl Suggested Resource ID Table
1246 * @param p_suggested_res_type_tbl Suggested Resource Type Table
1247 * @param x_res_tbl Qualified Resource suitable for Scheduling
1248 */
1249 PROCEDURE get_resources_to_schedule(
1250 p_api_version IN NUMBER
1251 , p_init_msg_list IN VARCHAR2
1252 , x_return_status OUT NOCOPY VARCHAR2
1253 , x_msg_count OUT NOCOPY NUMBER
1254 , x_msg_data OUT NOCOPY VARCHAR2
1255 , p_task_id IN NUMBER
1256 , p_incident_id IN NUMBER
1257 , p_res_qualifier_tbl IN resource_qualifier_tbl_type
1258 , p_scheduling_mode IN VARCHAR2
1259 , p_start IN DATE
1260 , p_end IN DATE
1261 , p_duration IN NUMBER
1262 , p_duration_uom IN VARCHAR2
1263 , p_contracts_flag IN VARCHAR2
1264 , p_ib_flag IN VARCHAR2
1265 , p_territory_flag IN VARCHAR2
1266 , p_skill_flag IN VARCHAR2
1267 , p_calendar_flag IN VARCHAR2
1268 , p_sort_flag IN VARCHAR2
1269 , p_suggested_res_id_tbl IN jtf_number_table
1270 , p_suggested_res_type_tbl IN jtf_varchar2_table_100
1271 , x_res_tbl OUT NOCOPY jtf_assign_pub.assignresources_tbl_type
1272 ) IS
1273 l_api_name CONSTANT VARCHAR2(30) := 'GET_RESOURCES_TO_SCHEDULE';
1274 l_api_version CONSTANT NUMBER := 1.0;
1275
1276 l_end_date DATE;
1277 l_task_has_skill_id NUMBER;
1278 l_business_process_id NUMBER;
1279 l_contracts_flag VARCHAR2(1);
1280 l_ib_flag VARCHAR2(1);
1281 l_territory_flag VARCHAR2(1);
1282 l_skills_flag VARCHAR2(1);
1283 l_has_suggested_res BOOLEAN;
1284 l_continue_search BOOLEAN;
1285 l_cont_ib_res_found BOOLEAN := TRUE;
1286 l_terr_res_found BOOLEAN := TRUE;
1287 l_sr_task_rec jtf_assign_pub.jtf_srv_task_rec_type;
1288
1289 l_contracts_ib_res_tbl jtf_assign_pub.assignresources_tbl_type;
1290 l_territory_res_tbl jtf_assign_pub.assignresources_tbl_type;
1291 l_skilled_res_tbl jtf_assign_pub.assignresources_tbl_type;
1292 l_stic NUMBER;
1293
1294 e_no_res EXCEPTION;
1295
1296 -- Cursor to determine if the Task has any required skills
1297 -- and returns the has_skill_id
1298 CURSOR c_task_skills IS
1299 SELECT has_skill_id
1300 FROM csf_required_skills_b,jtf_tasks_b t
1301 WHERE t.task_id = p_task_id
1302 AND has_skill_type = 'TASK'
1303 AND has_skill_id = nvl(t.parent_task_id, t.task_id)
1304 AND NVL(disabled_flag, 'N') <> 'Y'
1305 AND NVL(t.deleted_flag, 'N') <> 'Y';
1306
1307 --Introduced by lokumar for bug#7340932
1308 CURSOR c_business_process IS
1309 select iv.business_process_id
1310 from jtf_tasks_b t, cs_incidents_all i, cs_incident_types_vl iv
1311 where t.task_id = p_task_id
1312 and t.source_object_id = i.incident_id
1313 and i.incident_type_id = iv.incident_type_id;
1314
1315
1316 BEGIN
1317
1318 debug( fnd_log.level_statement, l_api_name, 'Get Resources To Schedule API Started');
1319
1320 IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
1321 RAISE fnd_api.g_exc_unexpected_error;
1322 END IF;
1323
1324 IF fnd_api.to_boolean(p_init_msg_list) THEN
1325 fnd_msg_pub.initialize;
1326 END IF;
1327
1328 x_return_status := fnd_api.g_ret_sts_success;
1329
1330 IF csf_util_pvt.g_timing_activated THEN
1331 csf_util_pvt.add_timer(105, 'Get resources to schedule (init)', 0, NULL);
1332 END IF;
1333
1334
1335 debug( fnd_log.level_statement, l_api_name, ' Task ID:' || p_task_id
1336 || ' Incident Id:' || p_incident_id
1337 || ' Scheduling Mode:' || p_scheduling_mode
1338 || ' Start Date:' || to_char(p_start, 'DD-MON-YYYY HH24:MI:SS')
1339 || ' End Date:' || to_char(p_end , 'DD-MON-YYYY HH24:MI:SS')
1340 || ' Calendar Flag:' || p_calendar_flag
1341 || ' Sort Flag:' || p_sort_flag
1342 || ' Contracts Flag:' || p_contracts_flag
1343 || ' IB Flag:' || p_ib_flag
1344 || ' Terr Flag:' || p_territory_flag
1345 || ' Skills Flag:' || p_skill_flag
1346 );
1347
1348 l_contracts_flag := NVL(p_contracts_flag, 'N');
1349 l_ib_flag := NVL(p_ib_flag, 'N');
1350 l_territory_flag := NVL(p_territory_flag, 'N');
1351 l_skills_flag := NVL(p_skill_flag, 'N');
1352 l_stic := 0;
1353 l_has_suggested_res := p_suggested_res_id_tbl IS NOT NULL AND p_suggested_res_id_tbl.COUNT > 0;
1354
1355 -- Check that at least one flag has been set.
1356 IF l_contracts_flag = 'N'
1357 AND l_ib_flag = 'N'
1358 AND l_territory_flag = 'N'
1359 AND l_skills_flag = 'N'
1360 AND NOT l_has_suggested_res
1361 THEN
1362 debug( fnd_log.level_statement, l_api_name, 'No Resource Selection Criteria is specified');
1363 RAISE e_no_res;
1364 END IF;
1365
1366 -- start with an empty list
1367 x_res_tbl.DELETE;
1368
1369 -- Find out whether the Task has any Required Skills Attached.
1370 IF l_skills_flag = 'Y' THEN
1371 debug( fnd_log.level_statement, l_api_name, 'Resource Selection is based on Skills..finding out the skills');
1372 OPEN c_task_skills;
1373 FETCH c_task_skills INTO l_task_has_skill_id;
1374 CLOSE c_task_skills;
1375
1376 debug( fnd_log.level_statement, l_api_name, 'The Skill ID:' || l_task_has_skill_id);
1377 IF l_task_has_skill_id IS NULL THEN
1378 -- Task has no Skills attached. Turn off Skills Flag.
1379 debug( fnd_log.level_statement, l_api_name, 'Task has no skills attached..turning off Skills qualifiers');
1380 l_skills_flag := 'N';
1381 -- If none of the other Flags are set we have an error situation
1382 IF l_contracts_flag = 'N' AND l_ib_flag = 'N' AND l_territory_flag = 'N' AND NOT l_has_suggested_res THEN
1383 fnd_message.set_name('CSF', 'CSF_NO_TASK_SKILL_RES');
1384 fnd_msg_pub.ADD;
1385 RAISE fnd_api.g_exc_error;
1386 END IF;
1387 END IF;
1388 END IF;
1389
1390 -- Convert the given Task ID or the Qualifier Table to SR Task Record
1391 IF l_contracts_flag = 'Y' OR l_ib_flag = 'Y' OR l_territory_flag = 'Y' THEN
1392 debug( fnd_log.level_statement, l_api_name, 'The input resource qualifier table count:'||p_res_qualifier_tbl.COUNT);
1393 IF p_res_qualifier_tbl.COUNT > 0 THEN
1394 IF csf_util_pvt.g_timing_activated THEN
1395 csf_util_pvt.add_timer(106, 'convert territory qualifiers to record', 0, NULL);
1396 END IF;
1397 l_sr_task_rec := get_qualified_task_rec(p_res_qualifier_tbl);
1398 IF csf_util_pvt.g_timing_activated THEN
1399 csf_util_pvt.add_timer(106, 'convert territory qualifiers to record', 1, NULL);
1400 END IF;
1401 ELSE
1402 IF csf_util_pvt.g_timing_activated THEN
1403 csf_util_pvt.add_timer(107, 'get territory qualifiers for task', 0, NULL);
1404 END IF;
1405 l_sr_task_rec := get_qualified_task_rec(get_res_qualifier_table(p_task_id));
1406 IF csf_util_pvt.g_timing_activated THEN
1407 csf_util_pvt.add_timer(107, 'get territory qualifiers for task', 1, NULL);
1408 END IF;
1409 END IF;
1410 l_sr_task_rec.task_id := p_task_id;
1411 l_sr_task_rec.service_request_id := p_incident_id;
1412 END IF;
1413
1414 debug( fnd_log.level_statement, l_api_name, ' TASK_ID:' || l_sr_task_rec.task_id
1415 || ' SERVICE_REQUEST_ID:' || l_sr_task_rec.SERVICE_REQUEST_ID
1416 || ' PARTY_ID:' || l_sr_task_rec.PARTY_ID
1417 || ' COUNTRY:' || l_sr_task_rec.COUNTRY
1418 || ' PARTY_SITE_ID:' || l_sr_task_rec.PARTY_SITE_ID
1419 || ' CITY:' || l_sr_task_rec.CITY
1420 || ' POSTAL_CODE:' || l_sr_task_rec.POSTAL_CODE
1421 || ' STATE:' || l_sr_task_rec.STATE
1422 || ' AREA_CODE:' || l_sr_task_rec.AREA_CODE
1423 || ' COUNTY:' || l_sr_task_rec.COUNTY
1424 || ' COMP_NAME_RANGE:' || l_sr_task_rec.COMP_NAME_RANGE
1425 || ' PROVINCE:' || l_sr_task_rec.PROVINCE
1426 || ' NUM_OF_EMPLOYEES:' || l_sr_task_rec.NUM_OF_EMPLOYEES
1427 || ' TASK_TYPE_ID:' || l_sr_task_rec.TASK_TYPE_ID
1428 || ' TASK_STATUS_ID:' || l_sr_task_rec.TASK_STATUS_ID
1429 || ' TASK_PRIORITY_ID:' || l_sr_task_rec.TASK_PRIORITY_ID
1430 || ' INCIDENT_TYPE_ID:' || l_sr_task_rec.INCIDENT_TYPE_ID
1431 || ' INCIDENT_SEVERITY_ID:'||l_sr_task_rec.INCIDENT_SEVERITY_ID
1432 || ' INCIDENT_URGENCY_ID:'|| l_sr_task_rec.INCIDENT_URGENCY_ID
1433 || ' PROBLEM_CODE:' || l_sr_task_rec.PROBLEM_CODE
1434 || ' INCIDENT_STATUS_ID:' || l_sr_task_rec.INCIDENT_STATUS_ID
1435 || ' SUPPORT_SITE_ID:' || l_sr_task_rec.SUPPORT_SITE_ID
1436 || ' CUSTOMER_SITE_ID:' || l_sr_task_rec.CUSTOMER_SITE_ID
1437 || ' INVENTORY_ITEM_ID:' || l_sr_task_rec.INVENTORY_ITEM_ID
1438 || ' DAY_OF_WEEK:' || l_sr_task_rec.DAY_OF_WEEK
1439 || ' TIME_OF_DAY:' || l_sr_task_rec.TIME_OF_DAY
1440 || ' ORGANIZATION_ID:' || l_sr_task_rec.ORGANIZATION_ID
1441 );
1442 IF csf_util_pvt.g_timing_activated THEN
1443 csf_util_pvt.add_timer(105, 'get resources to schedule (init)', 1, NULL);
1444 END IF;
1445
1446 l_continue_search := TRUE;
1447
1448
1449 IF csr_scheduler_pub.get_sch_parameter_value('spEnforcePlanWindow') = 'NONE' THEN
1450 l_end_date := p_end + NVL(csr_scheduler_pub.get_sch_parameter_value('spPlanScope'), 5)/5;
1451 debug( fnd_log.level_statement, l_api_name, ' Enforce None; End Date:'|| to_char(l_end_date, 'DD-MON-YYYY HH24:MI:SS'));
1452 ELSE
1453 l_end_date := p_end;
1454 debug( fnd_log.level_statement, l_api_name, ' Enforce is Not None; End Date:'|| to_char(l_end_date, 'DD-MON-YYYY HH24:MI:SS'));
1455 END IF;
1456
1457 debug( fnd_log.level_statement, l_api_name, 'Resource Search Window Start:'||to_char(p_start, 'DD-MON-YYYY HH24:MI:SS')
1458 || 'Resource Search Window End:' ||to_char(l_end_date, 'DD-MON-YYYY HH24:MI:SS')
1459 );
1460
1461 -- Retrieve the Resources defined in Contracts / IB
1462 IF l_contracts_flag = 'Y' OR l_ib_flag = 'Y' THEN
1463 IF csf_util_pvt.g_timing_activated THEN
1464 csf_util_pvt.add_timer(108, 'Get contract/IB resources', 0, NULL);
1465 END IF;
1466
1467 IF l_contracts_flag = 'Y' THEN
1468 -- Added by lokumar for bug#7340932
1469 --business process id is used only when contracts are selected
1470 OPEN c_business_process;
1471 FETCH c_business_process INTO l_business_process_id;
1472 CLOSE c_business_process;
1473
1474 debug( fnd_log.level_statement, l_api_name, 'The Business Process ID used for fetching Contracts Pref Resources:' || l_business_process_id);
1475
1476 l_stic := l_stic + 1;
1477
1478 END IF;
1479
1480 IF l_ib_flag = 'Y' THEN
1481 l_stic := l_stic + 2;
1482 END IF;
1483
1484 jtf_assign_pub.get_assign_resources(
1485 p_api_version => 1.0
1486 , p_init_msg_list => fnd_api.g_false
1487 , p_commit => fnd_api.g_false
1488 , x_return_status => x_return_status
1489 , x_msg_count => x_msg_count
1490 , x_msg_data => x_msg_data
1491 , p_sr_task_rec => l_sr_task_rec
1492 , p_contracts_preferred_engineer => l_contracts_flag
1493 , p_ib_preferred_engineer => l_ib_flag
1494 , p_territory_flag => 'N'
1495 , p_effort_duration => p_duration
1496 , p_effort_uom => p_duration_uom
1497 , p_start_date => p_start
1498 , p_end_date => l_end_date
1499 , p_auto_select_flag => 'N'
1500 , p_calendar_flag => NVL(p_calendar_flag, 'N')
1501 , p_calendar_check => 'N'
1502 , p_calling_doc_id => l_sr_task_rec.service_request_id
1503 , p_calling_doc_type => g_assign_doc_type
1504 , p_business_process_id => l_business_process_id
1505 , x_assign_resources_tbl => l_contracts_ib_res_tbl
1506 );
1507
1508 IF x_return_status = fnd_api.g_ret_sts_unexp_error THEN
1509 RAISE fnd_api.g_exc_unexpected_error;
1510 END IF;
1511
1512 debug( fnd_log.level_statement, l_api_name, 'The Number of Resources found using Contracts/IB:' || l_contracts_ib_res_tbl.COUNT);
1513
1514 IF l_contracts_ib_res_tbl.COUNT = 0 THEN
1515 l_cont_ib_res_found := FALSE;
1516 END IF;
1517
1518 FOR i in 1..l_contracts_ib_res_tbl.COUNT
1519 LOOP
1520 debug( fnd_log.level_statement, l_api_name, 'Obtained C/IB resource:' || l_contracts_ib_res_tbl(i).resource_id || l_contracts_ib_res_tbl(i).resource_type );
1521 debug( fnd_log.level_statement, l_api_name, 'Resource Start:'||to_char(l_contracts_ib_res_tbl(i).start_date, 'DD-MON-YYYY HH24:MI:SS')
1522 || 'Resource End:' ||to_char(l_contracts_ib_res_tbl(i).end_date, 'DD-MON-YYYY HH24:MI:SS')
1523 );
1524 END LOOP;
1525
1526 -- Since JTF Assignment Manager doesnt return End Windows properly,
1527 -- setting them to the given Plan Window.
1528 set_generic_planwindow(l_contracts_ib_res_tbl, p_start, l_end_date);
1529
1530 IF csf_util_pvt.g_timing_activated THEN
1531 csf_util_pvt.add_timer(108, 'get contract/IB resources', 1, NULL);
1532 END IF;
1533 END IF;
1534
1535 -- Retrieve Resources from Territory
1536 IF l_territory_flag = 'Y' AND l_continue_search THEN
1537 IF csf_util_pvt.g_timing_activated THEN
1538 csf_util_pvt.add_timer(109, 'get territory resources', 0, NULL);
1539 END IF;
1540
1541 l_stic := l_stic + 4;
1542
1543
1544 jtf_assign_pub.get_assign_resources(
1545 p_api_version => 1.0
1546 , p_init_msg_list => fnd_api.g_false
1547 , p_commit => fnd_api.g_false
1548 , x_return_status => x_return_status
1549 , x_msg_count => x_msg_count
1550 , x_msg_data => x_msg_data
1551 , p_sr_task_rec => l_sr_task_rec
1552 , p_contracts_preferred_engineer => 'N'
1553 , p_ib_preferred_engineer => 'N'
1554 , p_territory_flag => 'Y'
1555 , p_effort_duration => p_duration
1556 , p_effort_uom => p_duration_uom
1557 , p_start_date => p_start
1558 , p_end_date => l_end_date
1559 , p_auto_select_flag => 'N'
1560 , p_calendar_flag => NVL(p_calendar_flag, 'N')
1561 , p_calendar_check => 'N'
1562 , p_calling_doc_id => l_sr_task_rec.service_request_id
1563 , p_calling_doc_type => g_assign_doc_type
1564 , x_assign_resources_tbl => l_territory_res_tbl
1565 );
1566
1567
1568 IF x_return_status = fnd_api.g_ret_sts_unexp_error THEN
1569 RAISE fnd_api.g_exc_unexpected_error;
1570 END IF;
1571
1572 debug( fnd_log.level_statement, l_api_name, 'The Number of Resources found using Territories:' || l_territory_res_tbl.COUNT);
1573
1574 IF l_territory_res_tbl.COUNT = 0 THEN
1575 l_terr_res_found := FALSE;
1576 END IF;
1577
1578 FOR i in 1..l_territory_res_tbl.COUNT
1579 LOOP
1580 debug( fnd_log.level_statement, l_api_name, 'Obtained Terr resource:' || l_territory_res_tbl(i).resource_id || l_territory_res_tbl(i).resource_type );
1581 debug( fnd_log.level_statement, l_api_name, 'Resource Start:'||to_char(l_territory_res_tbl(i).start_date, 'DD-MON-YYYY HH24:MI:SS')
1582 || 'Resource End:' ||to_char(l_territory_res_tbl(i).end_date, 'DD-MON-YYYY HH24:MI:SS')
1583 );
1584 END LOOP;
1585
1586
1587 -- Since JTF Assignment Manager doesnt return End Windows properly,
1588 -- setting them to the given Plan Window.
1589 set_generic_planwindow(l_territory_res_tbl, p_start, l_end_date);
1590
1591 IF csf_util_pvt.g_timing_activated THEN
1592 csf_util_pvt.add_timer(109, 'get territory resources', 1, NULL);
1593 END IF;
1594 END IF;
1595
1596 -- This is done for two cases: a) when res found in TQ/IB/Cont or b) when TQ/IB/Cont
1597 -- was not used as the resource selection criteria
1598 IF NOT l_terr_res_found AND NOT l_cont_ib_res_found
1599 THEN
1600 debug( fnd_log.level_statement, l_api_name, 'Search will not be continued');
1601 l_continue_search := FALSE;
1602 END IF;
1603
1604 -- Retrieve the Skilled Resources for the Task
1605 IF l_skills_flag = 'Y' AND l_continue_search THEN
1606 debug( fnd_log.level_statement, l_api_name, 'Retrieving Skilled Resources for the Task');
1607 l_stic := l_stic + 8;
1608 get_skilled_resources(
1609 p_task_id => l_task_has_skill_id
1610 , p_start => p_start
1611 , p_end => l_end_date
1612 , x_skilled_res_tbl => l_skilled_res_tbl
1613 );
1614 debug( fnd_log.level_statement, l_api_name, 'Retrieving Skilled Resources for the Task');
1615 IF l_skilled_res_tbl.COUNT = 0 THEN
1616 debug( fnd_log.level_statement, l_api_name, 'No Resources Found using Skills Qualifiers');
1617 l_continue_search := FALSE;
1618 END IF;
1619
1620 FOR i in 1..l_skilled_res_tbl.COUNT
1621 LOOP
1622 debug( fnd_log.level_statement, l_api_name, 'Obtained skills resource:' || l_skilled_res_tbl(i).resource_id || l_skilled_res_tbl(i).resource_type );
1623 END LOOP;
1624
1625 END IF;
1626
1627 debug( fnd_log.level_statement, l_api_name, 'l_stic value:' || l_stic);
1628
1629 -- Intersect the results obtained from the three Qualifiers.
1630 IF l_continue_search THEN
1631 IF l_stic > 0 AND l_stic <= 3 THEN --> Only Contracts / IB was chosen
1632 debug( fnd_log.level_statement, l_api_name, 'Only Contracts / IB was chosen');
1633 x_res_tbl := l_contracts_ib_res_tbl;
1634 ELSIF l_stic = 4 THEN --> Only Territory was chosen
1635 debug( fnd_log.level_statement, l_api_name, 'Only Territory was chosen');
1636 x_res_tbl := l_territory_res_tbl;
1637 ELSIF l_stic = 8 THEN --> Only Skills were chosen
1638 debug( fnd_log.level_statement, l_api_name, 'Only Skills were chosen');
1639 x_res_tbl := l_skilled_res_tbl;
1640 ELSIF l_stic <= 7 THEN --> Both Contracts/IB and Terr were chosen
1641 debug( fnd_log.level_statement, l_api_name, 'Both Contracts/IB and Terr were chosen');
1642 x_res_tbl := union_results(l_contracts_ib_res_tbl, l_territory_res_tbl);
1643 ELSIF l_stic <= 11 THEN --> Both Contracts/IB and Skills where chosen
1644 debug( fnd_log.level_statement, l_api_name, 'Both Contracts/IB and Skills where chosen');
1645 x_res_tbl := intersect_results(l_contracts_ib_res_tbl, l_skilled_res_tbl, p_start, l_end_date);
1646 ELSIF l_stic <= 12 THEN --> Both Terr and SKills were chosen
1647 debug( fnd_log.level_statement, l_api_name, 'Both Terr and SKills were chosen');
1648 x_res_tbl := intersect_results(l_territory_res_tbl, l_skilled_res_tbl, p_start, l_end_date);
1649 ELSIF l_stic <= 15 THEN --> All the Flags were chosen
1650 debug( fnd_log.level_statement, l_api_name, 'All the Flags were chosen');
1651 x_res_tbl := union_results(l_contracts_ib_res_tbl, l_territory_res_tbl);
1652 x_res_tbl := intersect_results(x_res_tbl, l_skilled_res_tbl, p_start, l_end_date);
1653 END IF;
1654 END IF;
1655
1656 -- Add the suggested resources at the end (if the resource is not already there)
1657 IF l_has_suggested_res THEN
1658 debug( fnd_log.level_statement, l_api_name, 'Adding the Suggested Resource');
1659 add_suggested_resources(
1660 p_res_tbl => x_res_tbl
1661 , p_suggested_res_id_tbl => p_suggested_res_id_tbl
1662 , p_suggested_res_type_tbl => p_suggested_res_type_tbl
1663 , p_start_date => p_start
1664 , p_end_date => l_end_date
1665 );
1666 END IF;
1667
1668 -- make sure there were results
1669 IF x_res_tbl.COUNT = 0 THEN
1670 debug( fnd_log.level_statement, l_api_name, 'No Resources Found; Raising Exception!');
1671 RAISE e_no_res;
1672 END IF;
1673
1674 IF p_scheduling_mode <> 'A' THEN
1675 debug( fnd_log.level_statement, l_api_name, 'Non-Assisted Mode; Sorting by distance');
1676 -- Sort the Resources by their distance to the Task.
1677 IF csf_util_pvt.g_timing_activated THEN
1678 csf_util_pvt.add_timer(113, 'sort resources list', 0, NULL);
1679 END IF;
1680
1681 IF x_res_tbl.COUNT > 1 AND NVL(p_sort_flag, 'Y') = 'Y' THEN
1682 x_res_tbl := sort_resource_by_distance(x_res_tbl, p_task_id, p_start, l_end_date);
1683 END IF;
1684
1685 FOR i in 1..x_res_tbl.COUNT
1686 LOOP
1687 debug( fnd_log.level_statement, l_api_name, 'After Sorting resource:' || x_res_tbl(i).resource_id || x_res_tbl(i).resource_type );
1688 END LOOP;
1689
1690 IF csf_util_pvt.g_timing_activated THEN
1691 csf_util_pvt.add_timer(113, 'sort resources list', 1, NULL);
1692 END IF;
1693
1694 END IF;
1695
1696
1697 -- The number of Resources are restricted from the Sorted List.
1698 IF csf_util_pvt.g_timing_activated THEN
1699 csf_util_pvt.add_timer(114, 'reduce sorted resources list', 0, NULL);
1700 END IF;
1701
1702 x_res_tbl := reduce_resource_list(x_res_tbl, p_start, l_end_date);
1703
1704 FOR i in 1..x_res_tbl.COUNT
1705 LOOP
1706 debug( fnd_log.level_statement, l_api_name, 'After Calendar Check:' || x_res_tbl(i).resource_id || x_res_tbl(i).resource_type );
1707 debug( fnd_log.level_statement, l_api_name, 'x_Resource Start:'||to_char(x_res_tbl(i).start_date, 'DD-MON-YYYY HH24:MI:SS')
1708 || 'x_Resource End:' ||to_char(x_res_tbl(i).end_date, 'DD-MON-YYYY HH24:MI:SS')
1709 );
1710 END LOOP;
1711
1712 IF csf_util_pvt.g_timing_activated THEN
1713 csf_util_pvt.add_timer(114, 'reduce sorted resources list', 1, NULL);
1714 END IF;
1715 EXCEPTION
1716 WHEN e_no_res THEN
1717 x_return_status := fnd_api.g_ret_sts_error;
1718 fnd_message.set_name('CSF', get_assign_error_msg(l_stic));
1719 fnd_msg_pub.ADD;
1720 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1721 WHEN fnd_api.g_exc_error THEN
1722 x_return_status := fnd_api.g_ret_sts_error;
1723 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1724 WHEN fnd_api.g_exc_unexpected_error THEN
1725 x_return_status := fnd_api.g_ret_sts_unexp_error;
1726 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1727 WHEN OTHERS THEN
1728 x_return_status := fnd_api.g_ret_sts_unexp_error;
1729 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
1730 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
1731 END IF;
1732 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1733 END get_resources_to_schedule;
1734
1735 /**
1736 * Gets the Qualified Resources for a Task in a format understood by Request Model.
1737 * <br>
1738 * In turn calls the GET_RESOURCES_TO_SCHEDULE which gets the Resources in JTF
1739 * Assignment Manager Format.
1740 */
1741 PROCEDURE get_resources_to_schedule(
1742 p_api_version IN NUMBER
1743 , p_init_msg_list IN VARCHAR2 DEFAULT NULL
1744 , x_return_status OUT NOCOPY VARCHAR2
1745 , x_msg_count OUT NOCOPY NUMBER
1746 , x_msg_data OUT NOCOPY VARCHAR2
1747 , p_task_id IN NUMBER
1748 , p_incident_id IN NUMBER
1749 , p_res_qualifier_tbl IN resource_qualifier_tbl_type
1750 , p_scheduling_mode IN VARCHAR2
1751 , p_start IN DATE
1752 , p_end IN DATE
1753 , p_duration IN NUMBER DEFAULT NULL
1754 , p_duration_uom IN VARCHAR2 DEFAULT NULL
1755 , p_contracts_flag IN VARCHAR2 DEFAULT NULL
1756 , p_ib_flag IN VARCHAR2 DEFAULT NULL
1757 , p_territory_flag IN VARCHAR2 DEFAULT NULL
1758 , p_skill_flag IN VARCHAR2 DEFAULT NULL
1759 , p_calendar_flag IN VARCHAR2 DEFAULT NULL
1760 , p_sort_flag IN VARCHAR2 DEFAULT NULL
1761 , p_suggested_res_id_tbl IN jtf_number_table DEFAULT NULL
1762 , p_suggested_res_type_tbl IN jtf_varchar2_table_100 DEFAULT NULL
1763 , x_res_tbl IN OUT NOCOPY csf_requests_pvt.resource_tbl_type
1764 ) IS
1765 l_api_name CONSTANT VARCHAR2(30) := 'GET_RESOURCES_TO_SCHEDULE(2)';
1766 l_api_version CONSTANT NUMBER := 1.0;
1767
1768 l_assign_resource_tbl jtf_assign_pub.assignresources_tbl_type;
1769 j PLS_INTEGER;
1770 k PLS_INTEGER;
1771 BEGIN
1772 IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
1773 RAISE fnd_api.g_exc_unexpected_error;
1774 END IF;
1775
1776 IF fnd_api.to_boolean(p_init_msg_list) THEN
1777 fnd_msg_pub.initialize;
1778 END IF;
1779
1780 x_return_status := fnd_api.g_ret_sts_success;
1781
1782
1783
1784
1785 get_resources_to_schedule(
1786 p_api_version => 1
1787 , p_init_msg_list => fnd_api.g_false
1788 , x_return_status => x_return_status
1789 , x_msg_count => x_msg_count
1790 , x_msg_data => x_msg_data
1791 , p_task_id => p_task_id
1792 , p_incident_id => p_incident_id
1793 , p_res_qualifier_tbl => p_res_qualifier_tbl
1794 , p_scheduling_mode => p_scheduling_mode
1795 , p_start => p_start
1796 , p_end => p_end
1797 , p_duration => p_duration
1798 , p_duration_uom => p_duration_uom
1799 , p_contracts_flag => p_contracts_flag
1800 , p_ib_flag => p_ib_flag
1801 , p_territory_flag => p_territory_flag
1802 , p_skill_flag => p_skill_flag
1803 , p_calendar_flag => p_calendar_flag
1804 , p_sort_flag => p_sort_flag
1805 , p_suggested_res_id_tbl => p_suggested_res_id_tbl
1806 , p_suggested_res_type_tbl => p_suggested_res_type_tbl
1807 , x_res_tbl => l_assign_resource_tbl
1808 );
1809
1810
1811 IF x_res_tbl IS NULL THEN
1812 x_res_tbl := csf_requests_pvt.resource_tbl_type();
1813 END IF;
1814
1815 --start with an empty table so that previous value are deleted
1816 x_res_tbl.delete;
1817
1818 -- if qualified resoucres are found, add them to the output list
1819 IF x_return_status = fnd_api.g_ret_sts_success AND l_assign_resource_tbl.COUNT > 0 THEN
1820
1821 j := l_assign_resource_tbl.FIRST;
1822 WHILE j IS NOT NULL LOOP
1823 x_res_tbl.EXTEND;
1824 k := x_res_tbl.LAST;
1825 x_res_tbl(k).resource_id := l_assign_resource_tbl(j).resource_id;
1826 x_res_tbl(k).resource_type := l_assign_resource_tbl(j).resource_type;
1827 x_res_tbl(k).planwin_start := l_assign_resource_tbl(j).start_date;
1828 x_res_tbl(k).planwin_end := l_assign_resource_tbl(j).end_date;
1829 x_res_tbl(k).territory_id := l_assign_resource_tbl(j).terr_id;
1830
1831 IF l_assign_resource_tbl(j).terr_rank = jtf_assign_pub.am_miss_num THEN
1832 x_res_tbl(k).territory_rank := NULL;
1833 ELSE
1834 x_res_tbl(k).territory_rank := l_assign_resource_tbl(j).terr_rank;
1835 END IF;
1836 IF l_assign_resource_tbl(j).preference_type = 'I' OR l_assign_resource_tbl(j).preference_type = 'C' THEN
1837 x_res_tbl(k).preferred_resources_flag := 'Y';
1838 ELSE
1839 x_res_tbl(k).preferred_resources_flag := 'N';
1840 END IF;
1841
1842 IF l_assign_resource_tbl(j).preference_type = 'C' THEN
1843 x_res_tbl(k).resource_source := 'CNT';
1844 ELSIF l_assign_resource_tbl(j).preference_type = 'I' THEN
1845 x_res_tbl(k).resource_source := 'IB';
1846 ELSIF l_assign_resource_tbl(j).preference_type = 'SK' THEN
1847 x_res_tbl(k).resource_source := 'SK';
1848 ELSIF l_assign_resource_tbl(j).terr_id IS NOT NULL AND l_assign_resource_tbl(j).terr_id <> -1 THEN
1849 x_res_tbl(k).resource_source := 'TER';
1850 ELSE
1851 x_res_tbl(k).resource_source := 'RS';
1852 END IF;
1853
1854 x_res_tbl(k).skill_level := l_assign_resource_tbl(j).skill_level;
1855
1856 j := l_assign_resource_tbl.NEXT(j);
1857 END LOOP;
1858 END IF;
1859
1860
1861 EXCEPTION
1862 WHEN fnd_api.g_exc_error THEN
1863 x_return_status := fnd_api.g_ret_sts_error;
1864 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1865 WHEN fnd_api.g_exc_unexpected_error THEN
1866 x_return_status := fnd_api.g_ret_sts_unexp_error;
1867 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1868 WHEN OTHERS THEN
1869 x_return_status := fnd_api.g_ret_sts_unexp_error;
1870 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
1871 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
1872 END IF;
1873 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
1874 END get_resources_to_schedule;
1875
1876 PROCEDURE get_resources_to_schedule(
1877 p_api_version IN NUMBER
1878 , p_init_msg_list IN VARCHAR2 DEFAULT NULL
1879 , x_return_status OUT NOCOPY VARCHAR2
1880 , x_msg_count OUT NOCOPY NUMBER
1881 , x_msg_data OUT NOCOPY VARCHAR2
1882 , p_task_id IN NUMBER
1883 , p_contracts_flag IN VARCHAR2 DEFAULT NULL
1884 , p_ib_flag IN VARCHAR2 DEFAULT NULL
1885 , p_territory_flag IN VARCHAR2 DEFAULT NULL
1886 , p_skill_flag IN VARCHAR2 DEFAULT NULL
1887 , x_res_tbl OUT NOCOPY csf_resource_tbl
1888 ) IS
1889 l_api_name CONSTANT VARCHAR2(30) := 'GET_RESOURCES_TO_SCHEDULE(3)';
1890 l_api_version CONSTANT NUMBER := 1.0;
1891
1892 l_res_qualifiers resource_qualifier_tbl_type;
1893 l_assign_resource_tbl jtf_assign_pub.assignresources_tbl_type;
1894 j PLS_INTEGER;
1895 k PLS_INTEGER;
1896 --
1897 CURSOR c_task_info IS
1898 SELECT source_object_id
1899 , planned_start_date
1900 , planned_end_date
1901 , planned_effort
1902 , planned_effort_uom
1903 FROM jtf_tasks_b t
1904 WHERE t.task_id = p_task_id;
1905 l_task_info c_task_info%ROWTYPE;
1906 --
1907 CURSOR c_resource_info IS
1908 SELECT /*+ CARDINALITY(tr, 1) */
1909 r.resource_name
1910 , t.name terr_name
1911 , tr.resource_index
1912 FROM jtf_rs_all_resources_vl r
1913 , jtf_terr_all t
1914 , TABLE( CAST( x_res_tbl AS csf_resource_tbl ) ) tr
1915 WHERE r.resource_id = tr.resource_id
1916 AND r.resource_type = tr.resource_type
1917 AND t.terr_id (+) = tr.terr_id;
1918 BEGIN
1919 IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
1920 RAISE fnd_api.g_exc_unexpected_error;
1921 END IF;
1922
1923 IF fnd_api.to_boolean(p_init_msg_list) THEN
1924 fnd_msg_pub.initialize;
1925 END IF;
1926
1927 x_return_status := fnd_api.g_ret_sts_success;
1928
1929 OPEN c_task_info;
1930 FETCH c_task_info INTO l_task_info;
1931 CLOSE c_task_info;
1932
1933 get_resources_to_schedule(
1934 p_api_version => 1
1935 , p_init_msg_list => fnd_api.g_false
1936 , x_return_status => x_return_status
1937 , x_msg_count => x_msg_count
1938 , x_msg_data => x_msg_data
1939 , p_task_id => p_task_id
1940 , p_incident_id => l_task_info.source_object_id
1941 , p_res_qualifier_tbl => l_res_qualifiers
1942 , p_scheduling_mode => 'X'
1943 , p_start => l_task_info.planned_start_date
1944 , p_end => l_task_info.planned_end_date
1945 , p_duration => l_task_info.planned_effort
1946 , p_duration_uom => l_task_info.planned_effort_uom
1947 , p_contracts_flag => p_contracts_flag
1948 , p_ib_flag => p_ib_flag
1949 , p_territory_flag => p_territory_flag
1950 , p_skill_flag => p_skill_flag
1951 , x_res_tbl => l_assign_resource_tbl
1952 );
1953
1954
1955
1956
1957 IF x_res_tbl IS NULL THEN
1958 x_res_tbl := csf_resource_tbl();
1959 END IF;
1960
1961 --start with an empty table so that previous value are deleted
1962 x_res_tbl.delete;
1963
1964 -- if qualified resoucres are found, add them to the output list
1965 IF x_return_status = fnd_api.g_ret_sts_success AND l_assign_resource_tbl.COUNT > 0 THEN
1966
1967 j := l_assign_resource_tbl.FIRST;
1968 WHILE j IS NOT NULL LOOP
1969 x_res_tbl.EXTEND;
1970 k := x_res_tbl.LAST;
1971 x_res_tbl(k) :=
1972 csf_resource(
1973 k
1974 , l_assign_resource_tbl(j).resource_id
1975 , l_assign_resource_tbl(j).resource_type
1976 , NULL
1977 , l_assign_resource_tbl(j).resource_source
1978 , l_assign_resource_tbl(j).terr_id
1979 , l_assign_resource_tbl(j).terr_name
1980 , l_assign_resource_tbl(j).terr_rank
1981 , 'N'
1982 , NULL
1983 , l_assign_resource_tbl(j).start_date
1984 , l_assign_resource_tbl(j).end_date
1985 );
1986
1987 IF l_assign_resource_tbl(j).terr_rank = jtf_assign_pub.am_miss_num THEN
1988 x_res_tbl(k).terr_rank := NULL;
1989 END IF;
1990
1991 IF l_assign_resource_tbl(j).preference_type = 'I' THEN
1992 x_res_tbl(k).resource_source := 'IB';
1993 x_res_tbl(k).preferred_resource_flag := 'Y';
1994 ELSIF l_assign_resource_tbl(j).preference_type = 'C' THEN
1995 x_res_tbl(k).resource_source := 'CNT';
1996 x_res_tbl(k).preferred_resource_flag := 'Y';
1997 ELSIF l_assign_resource_tbl(j).preference_type = 'SK' THEN
1998 x_res_tbl(k).resource_source := 'SK';
1999 ELSIF l_assign_resource_tbl(j).terr_id IS NOT NULL AND l_assign_resource_tbl(j).terr_id <> -1 THEN
2000 x_res_tbl(k).resource_source := 'TER';
2001 ELSE
2002 x_res_tbl(k).resource_source := 'RS';
2003 END IF;
2004
2005 j := l_assign_resource_tbl.NEXT(j);
2006 END LOOP;
2007
2008 FOR v_resource_info IN c_resource_info LOOP
2009 x_res_tbl(v_resource_info.resource_index).resource_name := v_resource_info.resource_name;
2010 x_res_tbl(v_resource_info.resource_index).terr_name := v_resource_info.terr_name;
2011 END LOOP;
2012 END IF;
2013 EXCEPTION
2014 WHEN fnd_api.g_exc_error THEN
2015 x_return_status := fnd_api.g_ret_sts_error;
2016 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2017 WHEN fnd_api.g_exc_unexpected_error THEN
2018 x_return_status := fnd_api.g_ret_sts_unexp_error;
2019 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2020 WHEN OTHERS THEN
2021 x_return_status := fnd_api.g_ret_sts_unexp_error;
2022 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
2023 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
2024 END IF;
2025 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2026 END get_resources_to_schedule;
2027
2028 FUNCTION get_resources_to_schedule_pvt(
2029 p_task_id IN NUMBER
2030 , p_contracts_flag IN VARCHAR2 DEFAULT NULL
2031 , p_ib_flag IN VARCHAR2 DEFAULT NULL
2032 , p_territory_flag IN VARCHAR2 DEFAULT NULL
2033 , p_skill_flag IN VARCHAR2 DEFAULT NULL
2034 ) RETURN csf_resource_tbl IS
2035 PRAGMA autonomous_transaction;
2036 --
2037 l_return_status VARCHAR2(1);
2038 l_msg_data VARCHAR2(2000);
2039 l_msg_count NUMBER;
2040 l_res_tbl csf_resource_tbl;
2041 BEGIN
2042 get_resources_to_schedule(
2043 p_api_version => 1.0
2044 , p_init_msg_list => fnd_api.g_true
2045 , x_return_status => l_return_status
2046 , x_msg_count => l_msg_count
2047 , x_msg_data => l_msg_data
2048 , p_task_id => p_task_id
2049 , p_contracts_flag => p_contracts_flag
2050 , p_ib_flag => p_ib_flag
2051 , p_territory_flag => p_territory_flag
2052 , p_skill_flag => p_skill_flag
2053 , x_res_tbl => l_res_tbl
2054 );
2055
2056 ROLLBACK;
2057
2058 RETURN l_res_tbl;
2059 END get_resources_to_schedule_pvt;
2060
2061 FUNCTION get_resources_to_schedule(
2062 p_task_id IN NUMBER
2063 , p_contracts_flag IN VARCHAR2 DEFAULT NULL
2064 , p_ib_flag IN VARCHAR2 DEFAULT NULL
2065 , p_territory_flag IN VARCHAR2 DEFAULT NULL
2066 , p_skill_flag IN VARCHAR2 DEFAULT NULL
2067 )
2068 RETURN csf_resource_tbl IS
2069 l_res_tbl csf_resource_tbl;
2070 BEGIN
2071 l_res_tbl :=
2072 get_resources_to_schedule_pvt(
2073 p_task_id => p_task_id
2074 , p_contracts_flag => csr_scheduler_pub.get_sch_parameter_value('spPickContractResources')
2075 , p_ib_flag => csr_scheduler_pub.get_sch_parameter_value('spPickIbResources')
2076 , p_territory_flag => csr_scheduler_pub.get_sch_parameter_value('spPickTerritoryResources')
2077 , p_skill_flag => csr_scheduler_pub.get_sch_parameter_value('spPickSkilledResources')
2078 );
2079
2080 RETURN l_res_tbl;
2081 END get_resources_to_schedule;
2082
2083
2084 /**
2085 * Returns the Resource Type Code corresponding to a Resource Category.
2086 * <br>
2087 * In sync with the code done in JTF_RS_ALL_RESOURCES_VL
2088 *
2089 * @param p_category Resource Category
2090 * @returns Resource Type Code (VARCHAR2).
2091 */
2092 FUNCTION rs_category_type(p_category VARCHAR2)
2093 RETURN VARCHAR2 IS
2094 BEGIN
2095 IF p_category = 'EMPLOYEE' THEN
2096 RETURN 'RS_EMPLOYEE';
2097 ELSIF p_category = 'PARTNER' THEN
2098 RETURN 'RS_PARTNER';
2099 ELSIF p_category = 'SUPPLIER_CONTACT' THEN
2100 RETURN 'RS_SUPPLIER';
2101 ELSIF p_category = 'PARTY' THEN
2102 RETURN 'RS_PARTY';
2103 ELSIF p_category = 'OTHER' THEN
2104 RETURN 'RS_OTHER';
2105 ELSE
2106 RETURN NULL;
2107 END IF;
2108 END rs_category_type;
2109
2110 /**
2111 * Returns the ID of the Resource tied to the given User (FND User).
2112 * <br>
2113 * If no User is passed in, then it will take the User who has logged in
2114 * (FND_GLOBAL.USER_ID).
2115 *
2116 * @param p_user_id Identifier to the User desired (Optional)
2117 * @returns Resource ID (NUMBER)
2118 */
2119 FUNCTION resource_id(p_user_id NUMBER DEFAULT NULL)
2120 RETURN NUMBER IS
2121 CURSOR c_resource IS
2122 SELECT resource_id
2123 FROM jtf_rs_resource_extns
2124 WHERE user_id = NVL(p_user_id, fnd_global.user_id);
2125 l_id NUMBER := NULL;
2126 BEGIN
2127 OPEN c_resource;
2128 FETCH c_resource INTO l_id;
2129 CLOSE c_resource;
2130
2131 RETURN l_id;
2132 END resource_id;
2133
2134 /**
2135 * Returns the Resource Type of the Resource tied to the given user. (FND User)
2136 * <br>
2137 * If no User is passed in, then it will take the User who has logged in
2138 * (FND_GLOBAL.USER_ID).
2139 *
2140 * @param p_user_id Identifier to the User desired (Optional)
2141 * @returns Resource Type (VARCHAR2)
2142 */
2143 FUNCTION resource_type(p_user_id NUMBER DEFAULT NULL)
2144 RETURN VARCHAR2 IS
2145 CURSOR c_resource_type IS
2146 SELECT category
2147 FROM jtf_rs_resource_extns
2148 WHERE user_id = NVL(p_user_id, fnd_global.user_id);
2149 l_type jtf_rs_resource_extns.category%TYPE;
2150 BEGIN
2151 OPEN c_resource_type;
2152 FETCH c_resource_type INTO l_type;
2153 CLOSE c_resource_type;
2154
2155 RETURN rs_category_type(l_type);
2156 END resource_type;
2157
2158 FUNCTION get_resource_from_cache(
2159 p_res_id NUMBER
2160 , p_res_type VARCHAR2
2161 , p_get_address BOOLEAN DEFAULT FALSE
2162 , p_date DATE DEFAULT NULL
2163 )
2164 RETURN resource_cache_rec_type IS
2165
2166 l_return_status VARCHAR2(1);
2167 l_msg_data VARCHAR2(2000);
2168 l_msg_count NUMBER;
2169 l_found BOOLEAN;
2170 l_res_cache_info resource_cache_rec_type;
2171
2172 CURSOR c_normal_resource IS
2173 SELECT resource_id
2174 , p_res_type resource_type
2175 , resource_name
2176 , resource_number
2177 FROM jtf_rs_resource_extns_vl
2178 WHERE resource_id = p_res_id;
2179
2180 CURSOR c_group_resource IS
2181 SELECT group_id resource_id
2182 , 'RS_GROUP' resource_type
2183 , group_name resource_name
2184 , group_number resource_number
2185 FROM jtf_rs_groups_vl
2186 WHERE group_id = p_res_id;
2187
2188 CURSOR c_team_resource IS
2189 SELECT team_id resource_id
2190 , 'RS_TEAM' resource_type
2191 , team_name resource_name
2192 , team_number resource_number
2193 FROM jtf_rs_teams_vl
2194 WHERE team_id = p_res_id;
2195
2196 l_resource c_normal_resource%ROWTYPE;
2197 BEGIN
2198 IF p_res_id IS NULL OR p_res_type IS NULL THEN
2199 RETURN NULL;
2200 END IF;
2201
2202 -- Check whether the Resource exists in the Cache
2203 l_found := FALSE;
2204 IF g_res_info_cache.EXISTS(p_res_id) THEN
2205 l_res_cache_info := g_res_info_cache(p_res_id);
2206 l_found := l_res_cache_info.resource_type = p_res_type;
2207 END IF;
2208
2209 IF NOT l_found THEN
2210 IF p_res_type = 'RS_GROUP' THEN
2211 OPEN c_group_resource;
2212 FETCH c_group_resource INTO l_resource;
2213 CLOSE c_group_resource;
2214 ELSIF p_res_type = 'RS_TEAM' THEN
2215 OPEN c_team_resource;
2216 FETCH c_team_resource INTO l_resource;
2217 CLOSE c_team_resource;
2218 ELSE
2219 OPEN c_normal_resource;
2220 FETCH c_normal_resource INTO l_resource;
2221 CLOSE c_normal_resource;
2222 END IF;
2223
2224 -- Populate the Resource Cache Record
2225 l_res_cache_info.resource_id := l_resource.resource_id;
2226 l_res_cache_info.resource_type := l_resource.resource_type;
2227 l_res_cache_info.resource_name := l_resource.resource_name;
2228 l_res_cache_info.resource_number := l_resource.resource_number;
2229 END IF;
2230
2231 IF p_get_address THEN
2232 -- Check the validity of the Address in the Cache for the date
2233 IF l_res_cache_info.address.party_site_id IS NULL
2234 OR TRUNC(p_date) < l_res_cache_info.address.start_date_active
2235 OR TRUNC(p_date) > NVL(l_res_cache_info.address.end_date_active, p_date + 1)
2236 THEN
2237 csf_resource_address_pvt.get_resource_address(
2238 p_api_version => 1.0
2239 , x_return_status => l_return_status
2240 , x_msg_count => l_msg_count
2241 , x_msg_data => l_msg_data
2242 , p_resource_id => p_res_id
2243 , p_resource_type => p_res_type
2244 , p_date => p_date
2245 , p_res_shift_add => g_res_add_prof
2246 , x_address_rec => l_res_cache_info.address
2247 );
2248
2249 IF l_return_status <> fnd_api.g_ret_sts_success THEN
2250 RETURN NULL;
2251 END IF;
2252
2253 l_found := FALSE;
2254 END IF;
2255 END IF;
2256
2257 -- Cache the Resource Information for future use.
2258 IF NOT l_found THEN
2259 g_res_info_cache(p_res_id) := l_res_cache_info;
2260 END IF;
2261
2262 RETURN l_res_cache_info;
2263 END get_resource_from_cache;
2264
2265 /**
2266 * Returns the Resource Name given the Resource ID and Type.
2267 *
2268 * @param p_res_id Resource ID
2269 * @param p_res_type Resource Type Code
2270 * @returns Resource Name (VARCHAR2)
2271 */
2272 FUNCTION get_resource_name(p_res_id NUMBER, p_res_type VARCHAR2)
2273 RETURN VARCHAR2 IS
2274 BEGIN
2275 RETURN get_resource_from_cache(p_res_id, p_res_type).resource_name;
2276 END get_resource_name;
2277
2278 /**
2279 * Returns the Complete Resource Information given the Resource ID and Type.
2280 * The returned record includes Resource Number and Resource Name.
2281 *
2282 * @param p_res_id Resource ID
2283 * @param p_res_type Resource Type Code
2284 * @returns Resource Information filled in RESOURCE_REC_TYPE
2285 */
2286 FUNCTION get_resource_info(p_res_id NUMBER, p_res_type VARCHAR2)
2287 RETURN resource_rec_type IS
2288 l_res_cache_info resource_cache_rec_type;
2289 l_res_info resource_rec_type;
2290 BEGIN
2291 l_res_cache_info := get_resource_from_cache(p_res_id, p_res_type);
2292
2293 l_res_info.resource_id := l_res_cache_info.resource_id;
2294 l_res_info.resource_type := l_res_cache_info.resource_type;
2295 l_res_info.resource_name := l_res_cache_info.resource_name;
2296 l_res_info.resource_number := l_res_cache_info.resource_number;
2297
2298 RETURN l_res_info;
2299 END get_resource_info;
2300
2301 /**
2302 * Returns the Address of the Party created for the Resource as of the
2303 * date passed.
2304 *
2305 * @param p_res_id Resource ID
2306 * @param p_res_type Resource Type Code
2307 * @param p_date Active Party Site for the given date
2308 *
2309 * @returns Party Address of the Resource
2310 */
2311 FUNCTION get_resource_party_address (
2312 p_res_id NUMBER
2313 , p_res_type VARCHAR2
2314 , p_date DATE
2315 , p_res_shift_add VARCHAR2 DEFAULT NULL
2316 )
2317 RETURN csf_resource_address_pvt.address_rec_type IS
2318 BEGIN
2319 G_RES_ADD_PROF := p_res_shift_add;
2320
2321 RETURN get_resource_from_cache(p_res_id, p_res_type, TRUE, p_date).address;
2322 END get_resource_party_address;
2323
2324 /**
2325 * Returns the Resource Type Name corresponding to the Resource Type Code
2326 *
2327 * @param p_res_type Resource Type Code
2328 * @returns Resource Type Name (VARCHAR2)
2329 */
2330 FUNCTION get_resource_type_name(p_res_type VARCHAR2)
2331 RETURN VARCHAR2 IS
2332 i PLS_INTEGER;
2333
2334 CURSOR c_resource_type_names IS
2335 SELECT o.object_code code, o.name
2336 FROM jtf_object_usages u
2337 , jtf_objects_tl o
2338 WHERE u.object_user_code = 'RESOURCE_TYPES'
2339 AND o.object_code = u.object_code
2340 AND o.language = userenv('LANG');
2341 BEGIN
2342 IF g_res_type_name_tbl IS NULL THEN
2343 g_res_type_name_tbl := res_type_name_tbl_type();
2344 FOR v_resource_type_name IN c_resource_type_names LOOP
2345 g_res_type_name_tbl.extend();
2346 i := g_res_type_name_tbl.LAST;
2347 g_res_type_name_tbl(i).resource_type_code := v_resource_type_name.code;
2348 g_res_type_name_tbl(i).resource_type_name := v_resource_type_name.name;
2349 END LOOP;
2350 END IF;
2351
2352 FOR i IN 1..g_res_type_name_tbl.COUNT LOOP
2353 IF g_res_type_name_tbl(i).resource_type_code = p_res_type THEN
2354 RETURN g_res_type_name_tbl(i).resource_type_name;
2355 END IF;
2356 END LOOP;
2357 RETURN p_res_type;
2358 END get_resource_type_name;
2359
2360 /**
2361 * Converts the given Time from Resource Timezone to Server Timezone
2362 * or vice versa.
2363 * <br>
2364 * By default, the given date is assumed to be in Resource Timezone and the
2365 * date returned is Server Timezone. Set p_server_to_resource parameter as
2366 * 'T' (FND_API.G_TRUE) to make it return the other way round.
2367 * <br>
2368 * Note that the API doesnt support RS_TEAM or RS_GROUP resources.
2369 *
2370 * @param p_api_version API Version (1.0)
2371 * @param p_init_msg_list Initialize Message List
2372 * @param x_return_status Return Status of the Procedure.
2373 * @param x_msg_count Number of Messages in the Stack.
2374 * @param x_msg_data Stack of Error Messages.
2375 * @param p_resource_id Resource ID
2376 * @param p_resource_type Resource Type
2377 * @param p_datetime Date to be converted
2378 * @param p_server_to_resource Server to Resource Timezone
2379 */
2380 PROCEDURE convert_timezone(
2381 p_api_version IN NUMBER
2382 , p_init_msg_list IN VARCHAR2
2383 , x_return_status OUT NOCOPY VARCHAR2
2384 , x_msg_count OUT NOCOPY NUMBER
2385 , x_msg_data OUT NOCOPY VARCHAR2
2386 , p_resource_id IN NUMBER
2387 , p_resource_type IN VARCHAR2
2388 , x_datetime IN OUT NOCOPY DATE
2389 , p_server_to_resource IN VARCHAR2
2390 ) IS
2391 l_api_name CONSTANT VARCHAR2(30) := 'CONVERT_TIMEZONE';
2392 l_api_version CONSTANT NUMBER := 1.0;
2393 l_source_tz_id NUMBER;
2394 l_dest_tz_id NUMBER;
2395 l_temp_tz_id NUMBER;
2396 CURSOR c_resource IS
2397 SELECT time_zone
2398 FROM jtf_rs_resource_extns
2399 WHERE resource_id = p_resource_id
2400 AND p_resource_type NOT IN('RS_GROUP', 'RS_TEAM');
2401 BEGIN
2402 -- Standard call to check for call compatibility
2403 IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, 'CSF_TASKS_PUB') THEN
2404 RAISE fnd_api.g_exc_unexpected_error;
2405 END IF;
2406
2407 -- Initialize message list if p_init_msg_list is set to TRUE
2408 IF fnd_api.to_boolean(p_init_msg_list) THEN
2409 fnd_msg_pub.initialize;
2410 END IF;
2411
2412 -- Initialize API return status to success
2413 x_return_status := fnd_api.g_ret_sts_success;
2414
2415 -- Start actual processing
2416 fnd_profile.get('SERVER_TIMEZONE_ID', l_dest_tz_id);
2417
2418 OPEN c_resource;
2419 FETCH c_resource INTO l_source_tz_id;
2420 CLOSE c_resource;
2421
2422 -- Reverse conversion when requested
2423 IF fnd_api.to_boolean(p_server_to_resource) THEN
2424 l_temp_tz_id := l_source_tz_id;
2425 l_source_tz_id := l_dest_tz_id;
2426 l_dest_tz_id := l_source_tz_id;
2427 END IF;
2428
2429 -- Only try conversion when source and destination timezones are found
2430 IF l_source_tz_id IS NOT NULL AND l_dest_tz_id IS NOT NULL THEN
2431 hz_timezone_pub.get_time(
2432 p_api_version => 1.0
2433 , p_init_msg_list => fnd_api.g_false
2434 , p_source_tz_id => l_source_tz_id
2435 , p_dest_tz_id => l_dest_tz_id
2436 , p_source_day_time => x_datetime
2437 , x_dest_day_time => x_datetime
2438 , x_return_status => x_return_status
2439 , x_msg_count => x_msg_count
2440 , x_msg_data => x_msg_data
2441 );
2442 END IF;
2443
2444 EXCEPTION
2445 WHEN fnd_api.g_exc_error THEN
2446 x_return_status := fnd_api.g_ret_sts_error;
2447 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2448 WHEN fnd_api.g_exc_unexpected_error THEN
2449 x_return_status := fnd_api.g_ret_sts_unexp_error;
2450 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2451 WHEN OTHERS THEN
2452 x_return_status := fnd_api.g_ret_sts_unexp_error;
2453 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
2454 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
2455 END IF;
2456 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2457 END convert_timezone;
2458
2459 /**
2460 * Gets the Shift Definitions of the given Resource between the two given Dates.
2461 *
2462 * CSF has its own "Get Resource Shifts" API in addition to JTF providing it is
2463 * because CSF is still calling JTF Calendar API rather than JTF Calendar 24 API.
2464 * Going forward, we should be calling JTF_CALENDAR24_PUB rather than
2465 * JTF_CALENDAR_PUB.
2466 * Because of this the following Shift Definition is returned as two Shifts.
2467 * <br>
2468 * Shift Construct #101: Start = 1-JAN-2005 18:00:00 to 2-JAN-2005 07:00:00
2469 * is returned as
2470 * Shift Record #1
2471 * Shift Construct = 101
2472 * Shift Date = 1-JAN-2005
2473 * Start Time = 18:00
2474 * End Time = 23:59
2475 *
2476 * Shift Record #2
2477 * Shift Construct = 101
2478 * Shift Date = 2-JAN-2005
2479 * Start Time = 00:00
2480 * End Time = 07:00
2481 * <br>
2482 * Note that Shift Record#1 and Shift Record#2 are adjacent in the returned
2483 * Shifts Table. Morever both has the same Shift Construct ID and the difference
2484 * between End Time of the first record and the start time of the second is
2485 * One Minute (1/1440 days).
2486 *
2487 * This feature is being used by this API to merge those shifts in a single
2488 * record structure.
2489 *
2490 * @param p_api_version API Version (1.0)
2491 * @param p_init_msg_list Initialize Message List
2492 * @param x_return_status Return Status of the Procedure.
2493 * @param x_msg_count Number of Messages in the Stack.
2494 * @param x_msg_data Stack of Error Messages.
2495 * @param p_resource_id Resource Identifier for whom Shifts are required.
2496 * @param p_resource_type Resource Type of the above Resource.
2497 * @param p_start_date Start of the Window between which Shifts are required.
2498 * @param p_end_date End of the Window between which Shifts are required.
2499 * @param x_shifts Shift Definitions
2500 */
2501 PROCEDURE get_resource_shifts(
2502 p_api_version IN NUMBER
2503 , p_init_msg_list IN VARCHAR2
2504 , x_return_status OUT NOCOPY VARCHAR2
2505 , x_msg_count OUT NOCOPY NUMBER
2506 , x_msg_data OUT NOCOPY VARCHAR2
2507 , p_resource_id IN NUMBER
2508 , p_resource_type IN VARCHAR2
2509 , p_start_date IN DATE
2510 , p_end_date IN DATE
2511 , p_shift_type IN VARCHAR2 DEFAULT NULL
2512 , x_shifts OUT NOCOPY shift_tbl_type
2513 ) IS
2514 l_api_name CONSTANT VARCHAR2(30) := 'GET_RESOURCE_SHIFTS';
2515 l_api_version CONSTANT NUMBER := 1.0;
2516
2517 l_multiday_shifts jtf_calendar_pub.shift_tbl_type;
2518 l_time DATE;
2519 l_shift_starttime DATE;
2520 l_shift_endtime DATE;
2521 i PLS_INTEGER; -- Iterator for JTF's Shift Table
2522 j PLS_INTEGER; -- Iterator for CSF's Shift Table
2523
2524 BEGIN
2525 IF NOT fnd_api.compatible_api_call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
2526 RAISE fnd_api.g_exc_unexpected_error;
2527 END IF;
2528
2529 IF fnd_api.to_boolean(p_init_msg_list) THEN
2530 fnd_msg_pub.initialize;
2531 END IF;
2532
2533 x_return_status := fnd_api.g_ret_sts_success;
2534
2535 jtf_calendar_pub.get_resource_shifts(
2536 p_api_version => 1.0
2537 , p_resource_id => p_resource_id
2538 , p_resource_type => p_resource_type
2539 , p_start_date => p_start_date
2540 , p_end_date => p_end_date
2541 , x_return_status => x_return_status
2542 , x_msg_count => x_msg_count
2543 , x_msg_data => x_msg_data
2544 , x_shift => l_multiday_shifts
2545 );
2546
2547 IF x_return_status <> fnd_api.g_ret_sts_success OR l_multiday_shifts.COUNT = 0 THEN
2548 IF x_return_status = fnd_api.g_ret_sts_unexp_error THEN
2549 RAISE fnd_api.g_exc_unexpected_error;
2550 END IF;
2551 RAISE fnd_api.g_exc_error;
2552 END IF;
2553
2554 i := l_multiday_shifts.FIRST;
2555 j := 0;
2556 WHILE i IS NOT NULL LOOP
2557 l_time := to_date(l_multiday_shifts(i).start_time, 'HH24:MI');
2558 l_shift_starttime := l_multiday_shifts(i).shift_date + (l_time - trunc(l_time));
2559 l_time := to_date(l_multiday_shifts(i).end_time, 'HH24:MI');
2560 l_shift_endtime := l_multiday_shifts(i).shift_date + (l_time - trunc(l_time));
2561
2562
2563
2564 IF (l_multiday_shifts(i).availability_type = p_shift_type OR P_SHIFT_TYPE IS NULL) THEN
2565 -- Check whether the previous shift is same as the current one with a Minute Difference
2566 IF ( x_shifts.EXISTS(j)
2567 AND x_shifts(j).shift_construct_id = l_multiday_shifts(i).shift_construct_id
2568 AND (x_shifts(j).end_datetime + 1/1440) = l_shift_starttime )
2569 THEN
2570 -- Its the same shift but crossing the 24 Hour Boundary. Merge them.
2571 x_shifts(j).end_datetime := l_shift_endtime;
2572 ELSE
2573 IF l_shift_endtime > p_start_date AND l_shift_starttime < p_end_date THEN
2574 j := j+1;
2575 x_shifts(j).shift_construct_id := l_multiday_shifts(i).shift_construct_id;
2576 x_shifts(j).availability_type := l_multiday_shifts(i).availability_type;
2577 x_shifts(j).start_datetime := l_shift_starttime;
2578 x_shifts(j).end_datetime := l_shift_endtime;
2579 END IF;
2580 END IF;
2581 END IF;
2582
2583 i := l_multiday_shifts.NEXT(i);
2584 END LOOP;
2585
2586 EXCEPTION
2587 WHEN fnd_api.g_exc_error THEN
2588 x_return_status := fnd_api.g_ret_sts_error;
2589 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2590 WHEN fnd_api.g_exc_unexpected_error THEN
2591 x_return_status := fnd_api.g_ret_sts_unexp_error;
2592 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2593 WHEN OTHERS THEN
2594 x_return_status := fnd_api.g_ret_sts_unexp_error;
2595 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
2596 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
2597 END IF;
2598 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2599 END get_resource_shifts;
2600
2601 PROCEDURE get_location(
2602 x_return_status OUT NOCOPY VARCHAR2
2603 , x_msg_count OUT NOCOPY NUMBER
2604 , x_msg_data OUT NOCOPY VARCHAR2
2605 , p_resource_id IN NUMBER
2606 , p_resource_type IN VARCHAR2
2607 , p_date IN DATE DEFAULT SYSDATE
2608 , x_creation_date OUT NOCOPY DATE
2609 , x_feed_time OUT NOCOPY DATE
2610 , x_status_code OUT NOCOPY VARCHAR2
2611 , x_latitude OUT NOCOPY NUMBER
2612 , x_longitude OUT NOCOPY NUMBER
2613 , x_speed OUT NOCOPY NUMBER
2614 , x_direction OUT NOCOPY VARCHAR2
2615 , x_parked_time OUT NOCOPY NUMBER
2616 , x_address OUT NOCOPY VARCHAR2
2617 , x_device_tag OUT NOCOPY VARCHAR2
2618 , x_status_code_meaning OUT NOCOPY VARCHAR2
2619 ) IS
2620 l_address csf_resource_address_pvt.address_rec_type;
2621 l_geometry MDSYS.SDO_GEOMETRY;
2622 l_res_lat NUMBER;
2623 l_res_lon NUMBER;
2624 l_valid_geo VARCHAR2(5);
2625 l_mapping_count PLS_INTEGER := 0;
2626 --
2627 CURSOR c_status_lookup IS
2628 SELECT NVL(meaning, 'AT_HOME')
2629 FROM fnd_lookups
2630 WHERE lookup_type = 'CSF_GPS_DEVICE_STATUSES'
2631 AND lookup_code = 'AT_HOME';
2632 CURSOR c_device_res_map_exists IS
2633 SELECT count(*)
2634 FROM csf_gps_device_assignments a
2635 WHERE a.resource_id = p_resource_id
2636 AND a.resource_type = p_resource_type
2637 AND NVL(p_date, SYSDATE) BETWEEN a.start_date_active AND NVL(a.end_date_active, SYSDATE + 1);
2638 BEGIN
2639 x_return_status := fnd_api.g_ret_sts_success;
2640
2641 OPEN c_device_res_map_exists;
2642 FETCH c_device_res_map_exists INTO l_mapping_count;
2643 CLOSE c_device_res_map_exists;
2644
2645 IF p_date > SYSDATE OR NVL(csf_gps_pub.is_gps_enabled, 'N') <> 'Y' OR l_mapping_count = 0 THEN
2646 l_address :=
2647 get_resource_party_address(
2648 p_res_id => p_resource_id
2649 , p_res_type => p_resource_type
2650 , p_date => p_date
2651 );
2652
2653 -- This is wrong. It should follow the Country specific Formatting rules
2654 x_address := l_address.street || ', ' || l_address.city || ', ' || l_address.state || ', ' || l_address.postal_code || ', ' || l_address.country;
2655 x_status_code := 'AT_HOME';
2656 x_device_tag :=
2657 csf_gps_pub.get_gps_label(
2658 p_resource_id => p_resource_id
2659 , p_resource_type => p_resource_type
2660 , p_date => p_date
2661 );
2662 OPEN c_status_lookup;
2663 FETCH c_status_lookup INTO x_status_code_meaning;
2664 CLOSE c_status_lookup;
2665
2666 -- Fetch the Geometry corresponding to the Address
2667 IF l_address.geometry IS NOT NULL THEN
2668 csf_locus_pub.verify_locus(
2669 p_api_version => 1.0
2670 , p_locus => l_address.geometry
2671 , x_msg_count => x_msg_count
2672 , x_msg_data => x_msg_data
2673 , x_return_status => x_return_status
2674 , x_result => l_valid_geo
2675 );
2676
2677 IF l_valid_geo = 'TRUE' THEN
2678 IF l_address.geometry.sdo_elem_info IS NOT NULL
2679 AND l_address.geometry.sdo_ordinates IS NOT NULL
2680 THEN
2681 x_longitude := ROUND(l_address.geometry.sdo_ordinates(1), 8);
2682 x_latitude := ROUND(l_address.geometry.sdo_ordinates(2), 8);
2683 ELSIF l_address.geometry.sdo_point IS NOT NULL
2684 THEN
2685 x_longitude := ROUND(l_address.geometry.sdo_point.x, 8);
2686 x_latitude := ROUND(l_address.geometry.sdo_point.y, 8);
2687 ELSE
2688 x_longitude := -9999;
2689 x_latitude := -9999;
2690 END IF;
2691 ELSE
2692 x_longitude := -9999;
2693 x_latitude := -9999;
2694 END IF;
2695 ELSE
2696 x_longitude := -9999;
2697 x_latitude := -9999;
2698 END IF;
2699 x_status_code_meaning := NULL;
2700 ELSE
2701 csf_gps_pub.get_location(
2702 p_resource_id => p_resource_id
2703 , p_resource_type => p_resource_type
2704 , p_date => p_date
2705 , x_feed_time => x_feed_time
2706 , x_status_code => x_status_code
2707 , x_latitude => x_latitude
2708 , x_longitude => x_longitude
2709 , x_speed => x_speed
2710 , x_direction => x_direction
2711 , x_parked_time => x_parked_time
2712 , x_address => x_address
2713 , x_creation_date => x_creation_date
2714 , x_device_tag => x_device_tag
2715 , x_status_code_meaning => x_status_code_meaning
2716 );
2717 END IF;
2718 EXCEPTION
2719 WHEN OTHERS THEN
2720 x_return_status := fnd_api.g_ret_sts_unexp_error;
2721 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
2722 fnd_msg_pub.add_exc_msg(g_pkg_name, 'GET_LOCATION');
2723 END IF;
2724 fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
2725 END get_location;
2726
2727 PROCEDURE get_location(
2728 x_return_status OUT NOCOPY VARCHAR2
2729 , x_msg_count OUT NOCOPY NUMBER
2730 , x_msg_data OUT NOCOPY VARCHAR2
2731 , p_resource_id IN NUMBER
2732 , p_resource_type IN VARCHAR2
2733 , p_date IN DATE DEFAULT SYSDATE
2734 , x_latitude OUT NOCOPY NUMBER
2735 , x_longitude OUT NOCOPY NUMBER
2736 , x_address OUT NOCOPY VARCHAR2
2737 , x_status_meaning OUT NOCOPY VARCHAR2
2738 , x_device_tag OUT NOCOPY VARCHAR2
2739 ) IS
2740 l_feed_time csf_gps_location_feeds.vendor_feed_time%TYPE;
2741 l_status_code csf_gps_location_feeds.status%TYPE;
2742 l_speed csf_gps_location_feeds.speed%TYPE;
2743 l_direction csf_gps_location_feeds.direction%TYPE;
2744 l_parked_time csf_gps_location_feeds.parked_time%TYPE;
2745 l_creation_date csf_gps_location_feeds.creation_date%TYPE;
2746 BEGIN
2747 get_location(
2748 x_msg_count => x_msg_count
2749 , x_msg_data => x_msg_data
2750 , x_return_status => x_return_status
2751 , p_resource_id => p_resource_id
2752 , p_resource_type => p_resource_type
2753 , p_date => p_date
2754 , x_feed_time => l_feed_time
2755 , x_status_code => l_status_code
2756 , x_latitude => x_latitude
2757 , x_longitude => x_longitude
2758 , x_speed => l_speed
2759 , x_direction => l_direction
2760 , x_parked_time => l_parked_time
2761 , x_address => x_address
2762 , x_creation_date => l_creation_date
2763 , x_device_tag => x_device_tag
2764 , x_status_code_meaning => x_status_meaning
2765 );
2766 END get_location;
2767
2768 FUNCTION get_location (
2769 p_resource_id IN NUMBER
2770 , p_resource_type IN VARCHAR2
2771 , p_date IN DATE DEFAULT SYSDATE
2772 ) RETURN MDSYS.SDO_POINT_TYPE IS
2773 l_return_status VARCHAR2(1);
2774 l_msg_data VARCHAR2(2000);
2775 l_msg_count NUMBER;
2776 l_feed_time csf_gps_location_feeds.vendor_feed_time%TYPE;
2777 l_status_code csf_gps_location_feeds.status%TYPE;
2778 l_latitude csf_gps_location_feeds.latitude%TYPE;
2779 l_longitude csf_gps_location_feeds.longitude%TYPE;
2780 l_speed csf_gps_location_feeds.speed%TYPE;
2781 l_direction csf_gps_location_feeds.direction%TYPE;
2782 l_parked_time csf_gps_location_feeds.parked_time%TYPE;
2783 l_address csf_gps_location_feeds.address%TYPE;
2784 l_creation_date csf_gps_location_feeds.creation_date%TYPE;
2785 l_device_tag csf_gps_devices.device_tag%TYPE;
2786 l_status_code_meaning fnd_lookups.meaning%TYPE;
2787 BEGIN
2788 get_location(
2789 x_msg_count => l_msg_count
2790 , x_msg_data => l_msg_data
2791 , x_return_status => l_return_status
2792 , p_resource_id => p_resource_id
2793 , p_resource_type => p_resource_type
2794 , p_date => p_date
2795 , x_feed_time => l_feed_time
2796 , x_status_code => l_status_code
2797 , x_latitude => l_latitude
2798 , x_longitude => l_longitude
2799 , x_speed => l_speed
2800 , x_direction => l_direction
2801 , x_parked_time => l_parked_time
2802 , x_address => l_address
2803 , x_creation_date => l_creation_date
2804 , x_device_tag => l_device_tag
2805 , x_status_code_meaning => l_status_code_meaning
2806 );
2807 RETURN MDSYS.SDO_POINT_TYPE(l_longitude, l_latitude, 0);
2808 END get_location;
2809
2810 FUNCTION get_location_attributes(
2811 p_resource_id IN NUMBER
2812 , p_resource_type IN VARCHAR2
2813 , p_date IN DATE DEFAULT SYSDATE
2814 )
2815 RETURN VARCHAR2 IS
2816 l_return_status VARCHAR2(1);
2817 l_msg_data VARCHAR2(2000);
2818 l_msg_count NUMBER;
2819 l_feed_time csf_gps_location_feeds.vendor_feed_time%TYPE;
2820 l_status_code csf_gps_location_feeds.status%TYPE;
2821 l_latitude csf_gps_location_feeds.latitude%TYPE;
2822 l_longitude csf_gps_location_feeds.longitude%TYPE;
2823 l_speed csf_gps_location_feeds.speed%TYPE;
2824 l_direction csf_gps_location_feeds.direction%TYPE;
2825 l_parked_time csf_gps_location_feeds.parked_time%TYPE;
2826 l_address csf_gps_location_feeds.address%TYPE;
2827 l_creation_date csf_gps_location_feeds.creation_date%TYPE;
2828 l_device_tag csf_gps_devices.device_tag%TYPE;
2829 l_status_code_meaning fnd_lookups.meaning%TYPE;
2830 BEGIN
2831 get_location(
2832 x_msg_count => l_msg_count
2833 , x_msg_data => l_msg_data
2834 , x_return_status => l_return_status
2835 , p_resource_id => p_resource_id
2836 , p_resource_type => p_resource_type
2837 , p_date => p_date
2838 , x_feed_time => l_feed_time
2839 , x_status_code => l_status_code
2840 , x_latitude => l_latitude
2841 , x_longitude => l_longitude
2842 , x_speed => l_speed
2843 , x_direction => l_direction
2844 , x_parked_time => l_parked_time
2845 , x_address => l_address
2846 , x_creation_date => l_creation_date
2847 , x_device_tag => l_device_tag
2848 , x_status_code_meaning => l_status_code_meaning
2849 );
2850
2851 RETURN l_feed_time || '@@'
2852 || l_status_code || '@@'
2853 || l_latitude || '@@'
2854 || l_longitude || '@@'
2855 || l_speed || '@@'
2856 || l_direction || '@@'
2857 || l_parked_time || '@@'
2858 || l_address || '@@'
2859 || l_creation_date || '@@'
2860 || l_device_tag || '@@'
2861 || l_status_code_meaning || '@@' ||'END';
2862 END get_location_attributes;
2863
2864 FUNCTION geo_distance(p_lon1 NUMBER, p_lat1 NUMBER, p_lon2 NUMBER, p_lat2 NUMBER)
2865 RETURN NUMBER IS
2866 l_north NUMBER;
2867 l_east NUMBER;
2868 BEGIN
2869 l_north := ( (p_lat2*g_pi/180.0) - (p_lat1*g_pi/180.0) ) * g_earth_radius;
2870 l_east := ( ( (p_lon2*g_pi/180.0) -(p_lon1*g_pi/180.0) ) * COS(p_lat2* g_pi/180.0) )
2871 * g_earth_radius;
2872 RETURN SQRT ( (l_north * l_north) + (l_east * l_east) );
2873 END geo_distance;
2874
2875 FUNCTION get_third_party_role(
2876 p_resource_id IN NUMBER
2877 , p_resource_type IN VARCHAR2
2878 ) RETURN VARCHAR2 IS
2879
2880 CURSOR c_roles IS
2881 SELECT jrb.role_code
2882 , jrr.role_resource_type
2883 FROM jtf_rs_role_relations jrr
2884 , jtf_rs_roles_b jrb
2885 WHERE jrr.role_id = jrb.role_id
2886 AND jrr.role_resource_id = p_resource_id
2887 AND jrb.role_type_code = 'CSF_THIRD_PARTY'
2888 AND jrr.role_resource_type = p_resource_type
2889 AND ( jrr.start_date_active IS NULL or trunc(jrr.start_date_active) <= sysdate )
2890 AND ( jrr.end_date_active IS NULL or trunc(jrr.end_date_active) >= sysdate )
2891 AND NVL( jrr.delete_flag, 'N') = 'N'
2892 ORDER BY 1;
2893
2894 l_role VARCHAR2(30) := NULL;
2895 l_type VARCHAR2(30) := NULL;
2896
2897 BEGIN
2898 IF ( p_resource_id IS NOT NULL and p_resource_type IS NOT NULL ) THEN
2899 OPEN c_roles;
2900 LOOP
2901 FETCH c_roles INTO l_role, l_type;
2902 EXIT WHEN c_roles%NOTFOUND;
2903 -- A Group Resource with TPS is eligible for third party scheduling
2904 -- Any other type of resource with TPS is considered as Internal Resource
2905 IF l_role = 'CSF_THIRD_PARTY_SERVICE_PROVID' AND l_type = 'RS_GROUP'
2906 THEN
2907 RETURN l_role;
2908 END IF;
2909 IF l_role = 'CSF_THIRD_PARTY_TECHNICIAN'
2910 THEN
2911 RETURN l_role;
2912 END IF;
2913 END LOOP;
2914 RETURN l_role;
2915 END IF;
2916 RETURN NULL;
2917 END get_third_party_role;
2918
2919 BEGIN
2920 init_assign_errors;
2921 END csf_resource_pub;