DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_FLEX_WORKFLOW_APIS

Source


1 PACKAGE BODY fnd_flex_workflow_apis AS
2 /* $Header: AFFFWKAB.pls 120.1.12010000.1 2008/07/25 14:15:00 appldev ship $ */
3 
4 --
5 -- Global variables, initalized in package body init section.
6 --
7 g_debug_fnd_flex_workflow_apis BOOLEAN := FALSE;
8 
9 chr_newline        VARCHAR2(8);
10 complete           VARCHAR2(30);
11 error              VARCHAR2(30);
12 complete_no_result VARCHAR2(30);
13 complete_error     VARCHAR2(30);
14 complete_true      VARCHAR2(30);
15 complete_false     VARCHAR2(30);
16 complete_failure   VARCHAR2(30);
17 complete_success   VARCHAR2(30);
18 
19 -- ==================================================
20 -- CACHING
21 -- ==================================================
22 g_cache_return_code VARCHAR2(30);
23 g_cache_key         VARCHAR2(2000);
24 g_cache_value       fnd_plsql_cache.generic_cache_value_type;
25 
26 -- --------------------------------------------------
27 -- uqs : Unique Qualifier to Segment Cache.
28 -- --------------------------------------------------
29 uqs_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
30 uqs_cache_storage         fnd_plsql_cache.generic_cache_values_type;
31 
32 -- --------------------------------------------------
33 -- gsn : Get Segment Number Cache.
34 -- --------------------------------------------------
35 gsn_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
36 gsn_cache_storage         fnd_plsql_cache.generic_cache_values_type;
37 
38 -- ----------------------------------------
39 -- idc : CCID Cache.
40 --
41 -- Primary Key For IDC : <application_short_name> || NEWLINE ||
42 --        <id_flex_code> || NEWLINE || <id_flex_num> || NEWLINE || <ccid>
43 --
44 -- Combination : <seg1> || NEWLINE || ... || NEWLINE || <segn> || NEWLINE
45 --
46 -- ----------------------------------------
47 idc_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
48 idc_cache_storage         fnd_plsql_cache.generic_cache_values_type;
49 
50 TYPE idc_last_record_type IS RECORD
51   (primary_key              VARCHAR2(32000) := NULL,
52    encoded_error_message    VARCHAR2(32000),
53    segment_count            NUMBER,
54    segment_values           fnd_plsql_cache.cache_varchar2_varray_type);
55 
56 idc_last_record      idc_last_record_type;
57 
58 -- ----------------------------------------
59 -- ccc : Code Combination Cache.
60 --
61 -- Primary Key For CCC
62 -- <keyval_mode> || NEWLINE || <application_short_name> || NEWLINE ||
63 -- <id_flex_code> || NEWLINE || <id_flex_num> || NEWLINE ||
64 -- <concat_segments> || <allow_nulls> || NEWLINE || <allow_orphans>
65 --
66 -- ----------------------------------------
67 ccc_cache_controller      fnd_plsql_cache.cache_1to1_controller_type;
68 ccc_cache_storage         fnd_plsql_cache.generic_cache_values_type;
69 
70 TYPE ccc_last_record_type IS RECORD
71   (primary_key               VARCHAR2(32000) := NULL,
72    encoded_error_message     VARCHAR2(32000),
73    combination_id            NUMBER,
74    concatenated_values       VARCHAR2(32000),
75    concatenated_ids          VARCHAR2(32000),
76    concatenated_descriptions VARCHAR2(32000),
77    new_combination           BOOLEAN);
78 
79 ccc_last_record      ccc_last_record_type;
80 
81 FUNCTION idc_validate_ccid(p_application_short_name IN VARCHAR2,
82 			   p_id_flex_code           IN VARCHAR2,
83 			   p_id_flex_num            IN NUMBER,
84 			   p_ccid                   IN NUMBER)
85   RETURN BOOLEAN
86   IS
87      l_bool            BOOLEAN;
88      l_vc2             VARCHAR2(32000);
89      l_pos1            NUMBER;
90      l_pos2            NUMBER;
91 BEGIN
92    g_cache_key := (p_application_short_name || '.' ||
93 		   p_id_flex_code || '.' ||
94 		   p_id_flex_num || '.' ||
95 		   p_ccid);
96 
97    fnd_plsql_cache.generic_1to1_get_value(idc_cache_controller,
98 					  idc_cache_storage,
99 					  g_cache_key,
100 					  g_cache_value,
101 					  g_cache_return_code);
102 
103    IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
104       IF (g_cache_value.varchar2_1 IS NULL) THEN
105 	 --
106 	 -- No error message.
107 	 --
108 	 g_cache_return_code := fnd_plsql_cache.CACHE_VALID;
109        ELSE
110 	 g_cache_return_code := fnd_plsql_cache.CACHE_INVALID;
111       END IF;
112    END IF;
113 
114    IF (g_cache_return_code = fnd_plsql_cache.CACHE_VALID) THEN
115       GOTO return_true;
116     ELSIF (g_cache_return_code = fnd_plsql_cache.CACHE_INVALID) THEN
117       GOTO return_false;
118    END IF;
119 
120    --
121    -- Either not found or expired. Let's validate.
122    --
123    l_bool := fnd_flex_keyval.validate_ccid(p_application_short_name,
124 					   p_id_flex_code,
125 					   p_id_flex_num,
126 					   p_ccid,
127 					   'ALL', NULL, NULL,
128 					   'IGNORE',NULL,NULL,NULL,NULL);
129 
130    IF (l_bool) THEN
131       l_vc2 := NULL;
132       FOR i IN 1..Nvl(fnd_flex_keyval.segment_count, 0) LOOP
133 	 l_vc2 := l_vc2 || fnd_flex_keyval.segment_value(i) || chr_newline;
134       END LOOP;
135 
136       fnd_plsql_cache.generic_cache_new_value
137 	(x_value      => g_cache_value,
138 	 p_varchar2_1 => NULL,
139 	 p_number_1   => Nvl(fnd_flex_keyval.segment_count, 0),
140 	 p_varchar2_2 => l_vc2);
141 
142       fnd_plsql_cache.generic_1to1_put_value(idc_cache_controller,
143 					     idc_cache_storage,
144 					     g_cache_key,
145 					     g_cache_value);
146       GOTO return_true;
147     ELSE
148       fnd_plsql_cache.generic_cache_new_value
149 	(x_value      => g_cache_value,
150 	 p_varchar2_1 => Nvl(fnd_flex_keyval.encoded_error_message,
151 			     'FND-FLEX'),
152 	 p_number_1   => 0,
153 	 p_varchar2_2 => NULL);
154 
155       fnd_plsql_cache.generic_1to1_put_value(idc_cache_controller,
156 					     idc_cache_storage,
157 					     g_cache_key,
158 					     g_cache_value);
159       GOTO return_false;
160    END IF;
161 
162    <<return_true>>
163      IF ((g_cache_return_code = fnd_plsql_cache.CACHE_VALID) AND
164 	 (g_cache_key = idc_last_record.primary_key)) THEN
165 	RETURN(TRUE);
166      END IF;
167 
168      idc_last_record.primary_key           := g_cache_key;
169      idc_last_record.encoded_error_message := NULL;
170      idc_last_record.segment_count         := g_cache_value.number_1;
171 
172      l_vc2 := g_cache_value.varchar2_2;
173      l_pos1 := 1;
174      l_pos2 := Instr(l_vc2, chr_newline, l_pos1, 1);
175      FOR i IN 1..idc_last_record.segment_count LOOP
176 	idc_last_record.segment_values(i) := Substr(l_vc2, l_pos1, l_pos2 - l_pos1);
177 	l_pos1 := l_pos2 + Length(chr_newline);
178 	l_pos2 := Instr(l_vc2, chr_newline, l_pos1, 1);
179      END LOOP;
180      RETURN(TRUE);
181 
182    <<return_false>>
183      IF ((g_cache_return_code = fnd_plsql_cache.CACHE_INVALID) AND
184 	 (g_cache_key = idc_last_record.primary_key)) THEN
185         fnd_message.set_encoded(idc_last_record.encoded_error_message);
186 	RETURN(FALSE);
187      END IF;
188 
189      idc_last_record.primary_key           := g_cache_key;
190      idc_last_record.encoded_error_message := g_cache_value.varchar2_1;
191      idc_last_record.segment_count         := 0;
192 
193      fnd_message.set_encoded(idc_last_record.encoded_error_message);
194 
195      RETURN(FALSE);
196 
197      --
198      -- Let the exceptions propagate to caller.
199      --
200 END idc_validate_ccid;
201 
202 FUNCTION idc_segment_count
203   RETURN NUMBER
204   IS
205 BEGIN
206    RETURN(idc_last_record.segment_count);
207 END idc_segment_count;
208 
209 FUNCTION idc_segment_value(segnum IN NUMBER)
210   RETURN VARCHAR2
211   IS
212 BEGIN
213    IF ((segnum >= 1) AND (segnum <= idc_last_record.segment_count)) THEN
214       RETURN(idc_last_record.segment_values(segnum));
215    END IF;
216    RETURN(NULL);
217 END idc_segment_value;
218 
219 FUNCTION ccc_validate_segs(p_operation              IN VARCHAR2,
220 			   p_application_short_name IN VARCHAR2,
221 			   p_id_flex_code           IN VARCHAR2,
222 			   p_id_flex_num            IN NUMBER,
223 			   p_concat_segments        IN VARCHAR2,
224 			   p_validation_date        IN DATE,
225 			   p_allow_nulls            IN BOOLEAN,
226 			   p_allow_orphans          IN BOOLEAN)
227   RETURN BOOLEAN
228   IS
229      l_bool            BOOLEAN;
230 BEGIN
231    g_cache_key := (p_operation || '.' ||
232 		   p_application_short_name || '.' ||
233 		   p_id_flex_code || '.' ||
234 		   p_id_flex_num || '.' ||
235 		   p_concat_segments || '.');
236 
237    IF (p_allow_nulls) THEN
238       g_cache_key := g_cache_key || 'Y' || '.';
239     ELSE
240       g_cache_key := g_cache_key || 'N' || '.';
241    END IF;
242 
243    IF (p_allow_orphans) THEN
244       g_cache_key := g_cache_key || 'Y' || '.';
245     ELSE
246       g_cache_key := g_cache_key || 'N' || '.';
247    END IF;
248 
249    IF (p_validation_date IS NOT NULL) THEN
250       g_cache_key := g_cache_key ||
251         To_char(p_validation_date, 'YYYY/MM/DD') || '.';
252    END IF;
253 
254    fnd_plsql_cache.generic_1to1_get_value(ccc_cache_controller,
255 					  ccc_cache_storage,
256 					  g_cache_key,
257 					  g_cache_value,
258 					  g_cache_return_code);
259 
260    IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
261       IF (g_cache_value.varchar2_1 IS NULL) THEN
262 	 --
263 	 -- No error message.
264 	 --
265 	 g_cache_return_code := fnd_plsql_cache.CACHE_VALID;
266        ELSE
267 	 g_cache_return_code := fnd_plsql_cache.CACHE_INVALID;
268       END IF;
269    END IF;
270 
271    IF (g_cache_return_code = fnd_plsql_cache.CACHE_VALID) THEN
272       GOTO return_true;
273     ELSIF (g_cache_return_code = fnd_plsql_cache.CACHE_INVALID) THEN
274       GOTO return_false;
275    END IF;
276 
277    --
278    -- Either not found or expired. Let's validate.
279    --
280    l_bool := fnd_flex_keyval.validate_segs(p_operation,
281 					   p_application_short_name,
282 					   p_id_flex_code,
283 					   p_id_flex_num,
284 					   p_concat_segments,
285 					   'V',
286 					   p_validation_date,
287 					   'ALL', NULL, NULL, NULL, NULL,
288 					   p_allow_nulls,
289 					   p_allow_orphans, NULL, NULL, NULL);
290 
291 
292    IF (l_bool) THEN
293       fnd_plsql_cache.generic_cache_new_value
294 	(x_value      => g_cache_value,
295 	 p_varchar2_1 => NULL,
296 	 p_number_1   => fnd_flex_keyval.combination_id,
297 	 p_varchar2_2 => fnd_flex_keyval.concatenated_values,
298 	 p_varchar2_3 => fnd_flex_keyval.concatenated_ids,
299 	 p_varchar2_4 => fnd_flex_keyval.concatenated_descriptions,
300 	 p_boolean_1  => fnd_flex_keyval.new_combination);
301 
302       fnd_plsql_cache.generic_1to1_put_value(ccc_cache_controller,
303 					     ccc_cache_storage,
304 					     g_cache_key,
305 					     g_cache_value);
306       GOTO return_true;
307     ELSE
308       fnd_plsql_cache.generic_cache_new_value
309 	(x_value      => g_cache_value,
310 	 p_varchar2_1 => Nvl(fnd_flex_keyval.encoded_error_message,
311 			     'FND-FLEX'),
312 	 p_number_1   => NULL,
313 	 p_varchar2_2 => NULL,
314 	 p_varchar2_3 => NULL,
315 	 p_varchar2_4 => NULL,
316 	 p_boolean_1  => NULL);
317 
318       fnd_plsql_cache.generic_1to1_put_value(ccc_cache_controller,
319 					     ccc_cache_storage,
320 					     g_cache_key,
321 					     g_cache_value);
322       GOTO return_false;
323    END IF;
324 
325    <<return_true>>
326      IF ((g_cache_return_code = fnd_plsql_cache.CACHE_VALID) AND
327 	 (g_cache_key = ccc_last_record.primary_key)) THEN
328 	RETURN(TRUE);
329      END IF;
330 
331      ccc_last_record.primary_key               := g_cache_key;
332      ccc_last_record.encoded_error_message     := NULL;
333      ccc_last_record.combination_id            := g_cache_value.number_1;
334      ccc_last_record.concatenated_values       := g_cache_value.varchar2_2;
335      ccc_last_record.concatenated_ids          := g_cache_value.varchar2_3;
336      ccc_last_record.concatenated_descriptions := g_cache_value.varchar2_4;
337      ccc_last_record.new_combination           := g_cache_value.boolean_1;
338      RETURN(TRUE);
339 
340    <<return_false>>
341      IF ((g_cache_return_code = fnd_plsql_cache.CACHE_INVALID) AND
342 	 (g_cache_key = ccc_last_record.primary_key)) THEN
343 	RETURN(FALSE);
344      END IF;
345 
346      ccc_last_record.primary_key               := g_cache_key;
347      ccc_last_record.encoded_error_message     := g_cache_value.varchar2_1;
348      ccc_last_record.combination_id            := NULL;
349      ccc_last_record.concatenated_values       := NULL;
350      ccc_last_record.concatenated_ids          := NULL;
351      ccc_last_record.concatenated_descriptions := NULL;
352      ccc_last_record.new_combination           := NULL;
353      RETURN(FALSE);
354 
355      --
356      -- Let the exceptions propagate to caller.
357      --
358 END ccc_validate_segs;
359 
360 -- ======================================================================
361 -- DEBUG
362 -- ======================================================================
363 PROCEDURE dbms_debug(p_debug IN VARCHAR2)
364   IS
365      i INTEGER;
366      m INTEGER;
367      c INTEGER := 80;
368 BEGIN
369    m := Ceil(Length(p_debug)/c);
370    FOR i IN 1..m LOOP
371       execute immediate ('begin dbms' ||
372 			 '_output' ||
373 			 '.put_line(''' ||
374 			 REPLACE(Substr(p_debug, 1+c*(i-1), c), '''', '''''')||
375 					'''); end;');
376    END LOOP;
377 EXCEPTION
378    WHEN OTHERS THEN
379       NULL;
380 END dbms_debug;
381 
382 PROCEDURE debug(p_debug IN VARCHAR2)
383   IS
384      l_vc2       VARCHAR2(32000) := p_debug || chr_newline;
385      l_line_size NUMBER := 75;
386      l_pos       NUMBER;
387 BEGIN
388    IF (g_debug_fnd_flex_workflow_apis) THEN
389       WHILE (Nvl(Length(l_vc2),0) > 0) LOOP
390 	 l_pos := Instr(l_vc2, chr_newline, 1, 1);
391 	 IF (l_pos >= l_line_size) THEN
392 	    l_pos := l_line_size;
393 	 END IF;
394 	 dbms_debug(Rtrim(Substr(l_vc2, 1, l_pos), chr_newline));
395 	 l_vc2 := Substr(l_vc2, l_pos + 1);
396       END LOOP;
397    END IF;
398 EXCEPTION
399    WHEN OTHERS THEN
400       NULL;
401 END debug;
402 
403 PROCEDURE report_wf_error(p_func_name IN VARCHAR2)
404   IS
405 BEGIN
406    IF (g_debug_fnd_flex_workflow_apis) THEN
407       debug('Account Generator failed in ' || p_func_name ||
408 	    ' with following error.' || chr_newline ||
409 	    'ERROR_NAME    : ' || wf_core.error_name || chr_newline ||
410 	    'ERROR_MESSAGE : ' || wf_core.error_message || chr_newline ||
411 	    'ERROR_STACK   : ' || wf_core.error_stack || chr_newline ||
412 	    'SQLERRM       : ' || Sqlerrm || chr_newline ||
413 	    'DBMS_ERROR_STACK:' || chr_newline ||
414 	    dbms_utility.format_error_stack() || chr_newline ||
415 	    'DBMS_CALL_STACK:' || chr_newline ||
416 	    dbms_utility.format_call_stack());
417    END IF;
418 EXCEPTION
419    WHEN OTHERS THEN
420       NULL;
421 END report_wf_error;
422 
423 -- ======================================================================
424 -- bool_to_char
425 --
426 -- A utility function to convert boolean values to char to print in
427 -- debug statements
428 --
429 FUNCTION bool_to_char(value IN BOOLEAN)
430   RETURN VARCHAR2
431   IS
432 BEGIN
433    IF (value) THEN
434       RETURN 'TRUE';
435     ELSIF (NOT value) THEN
436       RETURN 'FALSE';
437     ELSE
438       RETURN 'NULL';
439    END IF;
440 END bool_to_char;
441 
442 -- ======================================================================
443 FUNCTION char_to_bool(value IN VARCHAR2)
444   RETURN BOOLEAN
445   IS
446 BEGIN
447    IF (value IN ('TRUE', 'Y', 'YES')) THEN
448       RETURN TRUE;
449     ELSIF (value IN ('FALSE', 'N', 'NO')) THEN
450       RETURN FALSE;
451     ELSIF (value IS NULL) THEN
452       RETURN NULL;
453     ELSIF (value = 'NULL') THEN
454       RETURN NULL;
455     ELSE
456       RETURN FALSE;
457    END IF;
458 END char_to_bool;
459 
460 -- ======================================================================
461 -- This function returns the index of the segment identified by
462 -- p_segment_identifier_type/p_segment_identifier.
463 -- (e.g. : QUALIFIER/GL_ACCOUNT, SEGMENT/COMPANY)
464 --
465 FUNCTION segment_to_index(p_application_id          IN NUMBER,
466 			  p_id_flex_code            IN VARCHAR2,
467 			  p_id_flex_num             IN NUMBER,
468 			  p_segment_identifier_type IN VARCHAR2,
469 			  p_segment_identifier      IN VARCHAR2,
470 			  x_segment_index           OUT nocopy NUMBER)
471   RETURN BOOLEAN
472   IS
473      l_segment_name  fnd_id_flex_segments.segment_name%TYPE;
474      l_segment_index NUMBER;
475      l_segment_num   NUMBER;
476 BEGIN
477    --
478    -- Debug
479    --
480    IF (g_debug_fnd_flex_workflow_apis) THEN
481       debug('START FND_FLEX_WORKFLOW_APIS.SEGMENT_TO_INDEX');
482       debug('APPLICATION_ID = ' || To_char(p_application_id));
483       debug('CODE = ' || p_id_flex_code);
484       debug('NUM = ' || To_char(p_id_flex_num));
485       debug('SEGMENT IDENTIFIER = ' || p_segment_identifier_type || '/' || p_segment_identifier);
486    END IF;
487 
488    --
489    -- If the segment is identified by a qualifier, then get the
490    -- corresponding segment name. We have to extend this to
491    -- handle non unique qualifier names
492    --
493    IF (p_segment_identifier_type = 'QUALIFIER') THEN
494       BEGIN
495 	 --
496 	 -- Get the segment name, using qualifier name.
497 	 --
498 	 g_cache_key := (p_application_id || '.' || p_id_flex_code || '.' ||
499 			 p_id_flex_num || '.' || p_segment_identifier);
500 	 fnd_plsql_cache.generic_1to1_get_value(uqs_cache_controller,
501 						uqs_cache_storage,
502 						g_cache_key,
503 						g_cache_value,
504 						g_cache_return_code);
505 	 IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
506 	    l_segment_name := g_cache_value.varchar2_1;
507 	  ELSE
508 	    SELECT s.segment_name
509 	      INTO l_segment_name
510 	      FROM fnd_id_flex_segments s,
511 	      fnd_segment_attribute_values sav,
512 	      fnd_segment_attribute_types sat
513 	      WHERE s.application_id = p_application_id
514 	      AND s.id_flex_code = p_id_flex_code
515 	      AND s.id_flex_num = p_id_flex_num
516 	      AND s.enabled_flag = 'Y'
517 	      AND s.application_column_name = sav.application_column_name
518 	      AND sav.application_id = p_application_id
519 	      AND sav.id_flex_code = p_id_flex_code
520 	      AND sav.id_flex_num = p_id_flex_num
521 	      AND sav.attribute_value = 'Y'
522 	      AND sav.segment_attribute_type = sat.segment_attribute_type
523 	      AND sat.application_id = p_application_id
524 	      AND sat.id_flex_code = p_id_flex_code
525 	      AND sat.segment_attribute_type = p_segment_identifier;
526 
527 	    fnd_plsql_cache.generic_cache_new_value
528 	      (x_value      => g_cache_value,
529 	       p_varchar2_1 => l_segment_name);
530 
531 	    fnd_plsql_cache.generic_1to1_put_value(uqs_cache_controller,
532 						   uqs_cache_storage,
533 						   g_cache_key,
534 						   g_cache_value);
535 	 END IF;
536       EXCEPTION
537 	 WHEN TOO_MANY_ROWS THEN
538 	    fnd_message.set_name('FND', 'FLEXWK-USE UNIQUE QUALIFIER');
539 	    fnd_message.set_token('QUAL', p_segment_identifier);
540 	    RETURN FALSE;
541 	 WHEN OTHERS THEN
542 	    fnd_message.set_name('FND', 'FLEXWK-NO SEG MATCHING QUAL');
543 	    fnd_message.set_token('QUAL', p_segment_identifier);
544 	    fnd_message.set_token('NUM', TO_CHAR(p_id_flex_num));
545 	    fnd_message.set_token('CODE', p_id_flex_code);
546 	    RETURN FALSE;
547       END;
548     ELSE
549       l_segment_name := p_segment_identifier;
550    END IF;
551 
552    --
553    -- Get the sequence number for the segment name.
554    --
555    BEGIN
556       --
557       -- Get the user specified segment number
558       --
559       g_cache_key := (p_application_id || '.' || p_id_flex_code || '.' ||
560 		      p_id_flex_num || '.' || l_segment_name);
561       fnd_plsql_cache.generic_1to1_get_value(gsn_cache_controller,
562 					     gsn_cache_storage,
563 					     g_cache_key,
564 					     g_cache_value,
565 					     g_cache_return_code);
566 
567       IF (g_cache_return_code = fnd_plsql_cache.CACHE_FOUND) THEN
568 	 l_segment_num := g_cache_value.number_1;
569 	 l_segment_index := g_cache_value.number_2;
570        ELSE
571 	 SELECT segment_num
572 	   INTO l_segment_num
573 	   FROM fnd_id_flex_segments
574 	   WHERE application_id = p_application_id
575 	   AND id_flex_code = p_id_flex_code
576 	   AND id_flex_num = p_id_flex_num
577 	   AND segment_name = l_segment_name
578 	   AND enabled_flag = 'Y';
579 
580 	 --
581 	 -- The above value gives the relative order of the
582 	 -- segments. Convert it into the segment index.
583 	 --
584 	 SELECT count(segment_num)
585 	   INTO l_segment_index
586 	   FROM fnd_id_flex_segments
587 	   WHERE application_id = p_application_id
588 	   AND id_flex_code = p_id_flex_code
589 	   AND id_flex_num = p_id_flex_num
590 	   AND enabled_flag = 'Y'
591 	   AND segment_num <= l_segment_num;
592 
593 	 fnd_plsql_cache.generic_cache_new_value
594 	   (x_value    => g_cache_value,
595 	    p_number_1 => l_segment_num,
596 	    p_number_2 => l_segment_index);
597 
598 	 fnd_plsql_cache.generic_1to1_put_value(gsn_cache_controller,
599 						gsn_cache_storage,
600 						g_cache_key,
601 						g_cache_value);
602       END IF;
603 
604    EXCEPTION
605       WHEN OTHERS THEN
606 	 fnd_message.set_name('FND', 'FLEXWK-CANNOT FIND SEG');
607 	 fnd_message.set_token('SEG', l_segment_name);
608 	 fnd_message.set_token('NUM', TO_CHAR(p_id_flex_num));
609 	 fnd_message.set_token('CODE', p_id_flex_code);
610 	 RETURN FALSE;
611    END;
612 
613    IF (g_debug_fnd_flex_workflow_apis) THEN
614       debug('SEGMENT NAME/INDEX = ' || l_segment_name || '/' || l_segment_index);
615    END IF;
616 
617    x_segment_index := l_segment_index;
618    RETURN TRUE;
619 END segment_to_index;
620 
621 -- ======================================================================
622 -- START_GENERATION
623 --
624 --   Starts the flexfield workflow process.
625 --
626 -- Activity Attributes:
627 --
628 -- Result:<None>
629 --
630 PROCEDURE start_generation(itemtype IN  VARCHAR2,
631 			   itemkey  IN  VARCHAR2,
632 			   actid    IN  NUMBER,
633 			   funcmode IN  VARCHAR2,
634 			   result   OUT nocopy VARCHAR2)
635   IS
636 BEGIN
637    IF (funcmode = 'RUN') THEN
638       --
639       -- Debug
640       --
641       IF (g_debug_fnd_flex_workflow_apis) THEN
642 	 debug('START FND_FLEX_WORKFLOW_APIS.START_GENERATION');
643       END IF;
644 
645       result := complete_no_result;
646       RETURN;
647 
648     ELSIF (funcmode = 'CANCEL') THEN
649       result := complete;
650       RETURN;
651 
652     ELSE
653       result := '';
654       RETURN;
655 
656    END IF;
657 EXCEPTION
658    WHEN OTHERS THEN
659       wf_core.context('FND_FLEX_WORKFLOW_APIS', 'START_PROCESS',
660 		      itemtype, itemkey, TO_CHAR(actid), funcmode);
661       report_wf_error('FND_FLEX_WORKFLOW_APIS.START_GENERATION');
662       RAISE;
663 END start_generation;
664 
665 -- ======================================================================
666 -- ASSIGN_TO_SEGMENT
667 --
668 --   This function is used to assign a value to a key flexfield
669 --   segment identified by either the segment name or a
670 --   flexfield qualifier.
671 --
672 -- Activity Attributes:
673 --   SEGMENT_IDENTIFIER     {SEGMENT|QUALIFIER}
674 --   SEGMENT                {varchar2(30)}
675 --   VALUE                  {varchar2(240)}
676 --   REPLACE_CURRENT_VALUE  {TRUE|FALSE}
677 --
678 -- Result:<None>
679 --
680 PROCEDURE assign_to_segment(itemtype IN  VARCHAR2,
681 			    itemkey  IN  VARCHAR2,
682 			    actid    IN  NUMBER,
683 			    funcmode IN  VARCHAR2,
684 			    result   OUT nocopy VARCHAR2)
685   IS
686      l_key_flex        fnd_flex_workflow.key_flex_type;
687      l_segment_id_type VARCHAR2(30);
688      l_segment_id      VARCHAR2(30);
689      l_segment_index   NUMBER;
690      l_segment_value   VARCHAR2(240);
691      l_replace_value   BOOLEAN;
692 BEGIN
693    IF (funcmode = 'RUN') THEN
694       --
695       -- Debug
696       --
697       IF (g_debug_fnd_flex_workflow_apis) THEN
698 	 debug('START FND_FLEX_WORKFLOW_APIS.ASSIGN_TO_SEGMENT');
699       END IF;
700 
701       --
702       -- Get the key flex.
703       --
704       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
705 
706       --
707       -- Get all the function activity attributes
708       --
709       l_segment_id_type := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
710 							 'SEGMENT_IDENTIFIER');
711       l_segment_id := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
712 						    'SEGMENT');
713       l_segment_value := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
714 						     'VALUE');
715       l_replace_value := char_to_bool(wf_engine.GetActivityAttrText
716 				      (itemtype, itemkey, actid,
717 				       'REPLACE_CURRENT_VALUE'));
718 
719       --
720       -- Debug
721       --
722       IF (g_debug_fnd_flex_workflow_apis) THEN
723 	 debug('SEGMENT_IDENTIFIER = ' || l_segment_id_type);
724 	 debug('SEGMENT = ' || l_segment_id);
725 	 debug('VALUE = ' || l_segment_value);
726 	 debug('REPLACE_CURRENT_VALUE = ' || bool_to_char(l_replace_value));
727       END IF;
728 
729       --
730       -- Get the segment index.
731       --
732       IF (NOT segment_to_index(l_key_flex.application_id,
733 			       l_key_flex.id_flex_code,
734 			       l_key_flex.id_flex_num,
735 			       l_segment_id_type, l_segment_id,
736 			       l_segment_index)) THEN
737 	 GOTO return_error;
738       END IF;
739 
740       --
741       -- If the replace flag is true or the current value is NULL then
742       -- replace the current value, else don't touch it.
743       --
744       IF ((l_replace_value) OR
745 	  (wf_engine.GetItemAttrText(itemtype, itemkey,
746 				     'FND_FLEX_SEGMENT' || TO_CHAR(l_segment_index)) IS NULL)) THEN
747 	 wf_engine.SetItemAttrText(itemtype, itemkey,
748 				   'FND_FLEX_SEGMENT' || TO_CHAR(l_segment_index),
749 				   l_segment_value);
750 
751 	 --
752 	 -- Debug
753 	 --
754 	 IF (g_debug_fnd_flex_workflow_apis) THEN
755 	    debug('VALUE ASSIGNED IS ' || l_segment_value);
756 	 END IF;
757        ELSE
758 	 --
759 	 -- Debug
760 	 --
761 	 IF (g_debug_fnd_flex_workflow_apis) THEN
762 	    debug('VALUE NOT ASSIGNED');
763 	 END IF;
764       END IF;
765 
766       result := complete_no_result;
767       GOTO return_success;
768 
769     ELSIF (funcmode = 'CANCEL') THEN
770       result := complete;
771       GOTO return_success;
772 
773     ELSE
774       result := '';
775       GOTO return_success;
776 
777    END IF;
778 
779    <<return_success>>
780      RETURN;
781 
782    <<return_error>>
783      --
784      -- Fatal error abort!
785      --
786      wf_engine.SetItemAttrText(itemtype, itemkey,
787 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
788      result := error || 'ASSIGN_TO_SEGMENT';
789      RETURN;
790 
791 EXCEPTION
792    WHEN OTHERS THEN
793       wf_core.context('FND_FLEX_WORKFLOW_APIS', 'ASSIGN_TO_SEGMENT',
794 		      itemtype, itemkey, TO_CHAR(actid), funcmode);
795 
796       report_wf_error('FND_FLEX_WORKFLOW_APIS.ASSIGN_TO_SEGMENT');
797       RAISE;
798 END assign_to_segment;
799 
800 -- ======================================================================
801 -- GET_VALUE_FROM_COMBINATION
802 --
803 --  This procdure returns the value for a specified segment from a given
804 --  code combination. The segment can be identified by either the
805 --  segment name or flexfield qualifier.
806 --
807 -- Activity Attributes:
808 --   SEGMENT_IDENTIFIER     {SEGMENT|QUALIFIER}
809 --   SEGMENT                {varchar2(30)}
810 --   CODE_COMBINATION_ID    {number}
811 --   RETURN_VALUE_ATTRIBUTE {varchar2(240)}
812 --
813 -- Result:<None>
814 --
815 PROCEDURE get_value_from_combination(itemtype IN  VARCHAR2,
816 				     itemkey  IN  VARCHAR2,
817 				     actid    IN  NUMBER,
818 				     funcmode IN  VARCHAR2,
819 				     result   OUT nocopy VARCHAR2)
820   IS
821      l_key_flex        fnd_flex_workflow.key_flex_type;
822      l_segment_id_type VARCHAR2(30);
823      l_segment_id      VARCHAR2(30);
824      l_segment_index   NUMBER;
825      l_ccid            NUMBER;
826      l_result_attr     VARCHAR2(240);
827 BEGIN
828    IF (funcmode = 'RUN') THEN
829       --
830       -- Debug
831       --
832       IF (g_debug_fnd_flex_workflow_apis) THEN
833 	 debug('START FND_FLEX_WORKFLOW_APIS.GET_VALUE_FROM_COMBINATION');
834       END IF;
835 
836       --
837       -- Get the key flex.
838       --
839       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
840 
841       --
842       -- Get all the function activity attributes
843       --
844       l_segment_id_type := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
845 							 'SEGMENT_IDENTIFIER');
846       l_segment_id := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
847 						    'SEGMENT');
848       l_ccid := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
849 						'CODE_COMBINATION_ID');
850       l_result_attr := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
851 						     'RETURN_VALUE_ATTRIBUTE');
852 
853       --
854       -- Debug
855       --
856       IF (g_debug_fnd_flex_workflow_apis) THEN
857 	 debug('SEGMENT_IDENTIFIER = ' || l_segment_id_type);
858 	 debug('SEGMENT = ' || l_segment_id);
859 	 debug('CCID = ' || TO_CHAR(l_ccid));
860 	 debug('RETURN_VALUE_ATTRIBUTE = ' || l_result_attr);
861       END IF;
862 
863       --
864       -- Get the segment index.
865       --
866       IF (NOT segment_to_index(l_key_flex.application_id,
867 			       l_key_flex.id_flex_code,
868 			       l_key_flex.id_flex_num,
869 			       l_segment_id_type,
870 			       l_segment_id,
871 			       l_segment_index)) THEN
872 	 GOTO return_error;
873       END IF;
874 
875       --
876       -- Use the IDC cache to get the segment values for this ccid.
877       --
878       IF (NOT idc_validate_ccid(l_key_flex.application_short_name,
879 				l_key_flex.id_flex_code,
880 				l_key_flex.id_flex_num,
881 				l_ccid)) THEN
882 	 GOTO return_error;
883       END IF;
884 
885       --
886       -- Return the value that was asked for.
887       --
888       wf_engine.SetItemAttrText(itemtype, itemkey, l_result_attr,
889 				idc_segment_value(l_segment_index));
890 
891       --
892       -- Debug
893       --
894       IF (g_debug_fnd_flex_workflow_apis) THEN
895 	 debug('VALUE ASSIGNED IS ' || idc_segment_value(l_segment_index));
896       END IF;
897 
898       result := complete_no_result;
899       GOTO return_success;
900 
901     ELSIF (funcmode = 'CANCEL') THEN
902       result := complete;
903       GOTO return_success;
904 
905     ELSE
906       result := '';
907       GOTO return_success;
908 
909    END IF;
910 
911    <<return_success>>
912      RETURN;
913 
914    <<return_error>>
915      --
916      -- Fatal error abort!
917      --
918      wf_engine.SetItemAttrText(itemtype, itemkey,
919 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
920      result := error || 'GET_VALUE_FROM_COMBINATION';
921      RETURN;
922 
923 EXCEPTION
924    WHEN OTHERS THEN
925       wf_core.context('FND_FLEX_WORKFLOW_APIS',
926 		      'GET_VALUE_FROM_COMBINATION', itemtype, itemkey,
927 		      TO_CHAR(actid), funcmode);
928       report_wf_error('FND_FLEX_WORKFLOW_APIS.GET_VALUE_FROM_COMBINATION');
929       RAISE;
930 END get_value_from_combination;
931 
932 -- ======================================================================
933 -- GET_VALUE_FROM_COMBINATION2
934 --
935 -- This procedure copied/pasted from get_value_from_combination.
936 -- It is provided to get values from a different structure combination.
937 -- Note: Not from a different flexfield.
938 -- See bug845445.
939 -- This procdure returns the value for a specified segment from a given
940 -- code combination. The segment can be identified by either the
941 -- segment name or flexfield qualifier.
942 --
943 -- Activity Attributes:
944 --   STRUCTURE_NUMBER       {number}
945 --   SEGMENT_IDENTIFIER     {SEGMENT|QUALIFIER}
946 --   SEGMENT                {varchar2(30)}
947 --   CODE_COMBINATION_ID    {number}
948 --   RETURN_VALUE_ATTRIBUTE {varchar2(240)}
949 --
950 -- Result:<None>
951 --
952 PROCEDURE get_value_from_combination2(itemtype IN  VARCHAR2,
953 				      itemkey  IN  VARCHAR2,
954 				      actid    IN  NUMBER,
955 				      funcmode IN  VARCHAR2,
956 				      result   OUT nocopy VARCHAR2)
957   IS
958      l_key_flex             fnd_flex_workflow.key_flex_type;
959      l_source_id_flex_num   NUMBER;
960      l_segment_id_type      VARCHAR2(30);
961      l_segment_id           VARCHAR2(30);
962      l_source_segment_index NUMBER;
963      l_ccid                 NUMBER;
964      l_result_attr          VARCHAR2(240);
965 BEGIN
966    IF (funcmode = 'RUN') THEN
967       --
968       -- Debug
969       --
970       IF (g_debug_fnd_flex_workflow_apis) THEN
971 	 debug('START FND_FLEX_WORKFLOW_APIS.GET_VALUE_FROM_COMBINATION2');
972       END IF;
973 
974       --
975       -- Get the original key flex.
976       --
977       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
978 
979       --
980       -- Get all the function activity attributes
981       --
982       l_source_id_flex_num := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
983 							      'STRUCTURE_NUMBER');
984       l_segment_id_type := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
985 						       'SEGMENT_IDENTIFIER');
986       l_segment_id := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
987 						  'SEGMENT');
988       l_ccid := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
989 						'CODE_COMBINATION_ID');
990       l_result_attr := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
991 						     'RETURN_VALUE_ATTRIBUTE');
992 
993       --
994       -- Debug
995       --
996       IF (g_debug_fnd_flex_workflow_apis) THEN
997 	 debug('SOURCE NUM = ' || TO_CHAR(l_source_id_flex_num));
998 	 debug('SEGMENT_IDENTIFIER = ' || l_segment_id_type);
999 	 debug('SEGMENT = ' || l_segment_id);
1000 	 debug('CCID = ' || TO_CHAR(l_ccid));
1001 	 debug('RETURN_VALUE_ATTRIBUTE = ' || l_result_attr);
1002       END IF;
1003 
1004       --
1005       -- Get the source segment index.
1006       --
1007       IF (NOT segment_to_index(l_key_flex.application_id,
1008 			       l_key_flex.id_flex_code,
1009 			       l_source_id_flex_num,
1010 			       l_segment_id_type,
1011 			       l_segment_id,
1012 			       l_source_segment_index)) THEN
1013 	 GOTO return_error;
1014       END IF;
1015 
1016       --
1017       -- Use the IDC cache to get the segment values for this ccid.
1018       --
1019       IF (NOT idc_validate_ccid(l_key_flex.application_short_name,
1020 				l_key_flex.id_flex_code,
1021 				l_source_id_flex_num,
1022 				l_ccid)) THEN
1023 	 GOTO return_error;
1024       END IF;
1025 
1026       --
1027       -- Return the value that was asked for.
1028       --
1029       wf_engine.SetItemAttrText(itemtype, itemkey, l_result_attr,
1030 				idc_segment_value(l_source_segment_index));
1031 
1032       --
1033       -- Debug
1034       --
1035       IF (g_debug_fnd_flex_workflow_apis) THEN
1036 	 debug('VALUE ASSIGNED IS ' || idc_segment_value(l_source_segment_index));
1037       END IF;
1038 
1039       result := complete_no_result;
1040       GOTO return_success;
1041 
1042     ELSIF (funcmode = 'CANCEL') THEN
1043       result := complete;
1044       GOTO return_success;
1045 
1046     ELSE
1047       result := '';
1048       GOTO return_success;
1049 
1050    END IF;
1051 
1052    <<return_success>>
1053      RETURN;
1054 
1055    <<return_error>>
1056      --
1057      -- Fatal error abort!
1058      --
1059      wf_engine.SetItemAttrText(itemtype, itemkey,
1060 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
1061      result := error || 'GET_VALUE_FROM_COMBINATION2';
1062      RETURN;
1063 
1064 EXCEPTION
1065    WHEN OTHERS THEN
1066       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1067 		      'GET_VALUE_FROM_COMBINATION2', itemtype, itemkey,
1068 		      TO_CHAR(actid), funcmode);
1069       report_wf_error('FND_FLEX_WORKFLOW_APIS.GET_VALUE_FROM_COMBINATION2');
1070       RAISE;
1071 END get_value_from_combination2;
1072 
1073 -- ======================================================================
1074 -- COPY_FROM_COMBINATION
1075 --
1076 --   This procedure copies values from a specified combination.
1077 --
1078 -- Activity Attributes:
1079 --   CODE_COMBINATION_ID    {number}
1080 --   REPLACE_CURRENT_VALUE  {TRUE|FALSE}
1081 --
1082 -- Result:<None>
1083 --
1084 PROCEDURE copy_from_combination(itemtype IN  VARCHAR2,
1085 				itemkey  IN  VARCHAR2,
1086 				actid    IN  NUMBER,
1087 				funcmode IN  VARCHAR2,
1088 				result   OUT nocopy VARCHAR2)
1089   IS
1090      l_key_flex      fnd_flex_workflow.key_flex_type;
1091 
1092      l_ccid          NUMBER;
1093      l_nsegments     NUMBER;
1094      l_replace_value BOOLEAN;
1095 BEGIN
1096    IF (funcmode = 'RUN') THEN
1097       --
1098       -- Debug
1099       --
1100       IF (g_debug_fnd_flex_workflow_apis) THEN
1101 	 debug('START FND_FLEX_WORKFLOW_APIS.COPY_FROM_COMBINATION');
1102       END IF;
1103 
1104       --
1105       -- Get the key flex.
1106       --
1107       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
1108 
1109       --
1110       -- Get all the function activity attributes
1111       --
1112       l_ccid := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
1113 						'CODE_COMBINATION_ID');
1114       l_replace_value := char_to_bool(wf_engine.GetActivityAttrText
1115 				      (itemtype, itemkey, actid,
1116 				       'REPLACE_CURRENT_VALUE'));
1117       --
1118       -- Debug
1119       --
1120       IF (g_debug_fnd_flex_workflow_apis) THEN
1121 	 debug('CCID = ' || TO_CHAR(l_ccid));
1122 	 debug('REPLACE_CURRENT_VALUE = ' || bool_to_char(l_replace_value));
1123       END IF;
1124 
1125       --
1126       -- Use the IDC cache to get the segment values for this ccid.
1127       --
1128       IF (NOT idc_validate_ccid(l_key_flex.application_short_name,
1129 				l_key_flex.id_flex_code,
1130 				l_key_flex.id_flex_num,
1131 				l_ccid)) THEN
1132 	 GOTO return_error;
1133       END IF;
1134 
1135       --
1136       -- Now assign them to the segment attributes
1137       -- after checking the replace flag.
1138       --
1139       l_nsegments := idc_segment_count();
1140       FOR i IN 1..l_nsegments LOOP
1141 	 IF (l_replace_value OR
1142 	     (wf_engine.GetItemAttrText(itemtype, itemkey,
1143 					'FND_FLEX_SEGMENT' || TO_CHAR(i)) IS NULL)) THEN
1144 	    wf_engine.SetItemAttrText(itemtype, itemkey,
1145 				      'FND_FLEX_SEGMENT' || TO_CHAR(i),
1146 				      idc_segment_value(i));
1147 	    --
1148 	    -- Debug
1149 	    --
1150 	    IF (g_debug_fnd_flex_workflow_apis) THEN
1151 	       debug('VALUE ASSIGNED TO SEGMENT ' || TO_CHAR(i) || ' IS ' ||
1152 		     idc_segment_value(i));
1153 	    END IF;
1154 	 END IF;
1155       END LOOP;
1156 
1157       result := complete_no_result;
1158       GOTO return_success;
1159 
1160     ELSIF (funcmode = 'CANCEL') THEN
1161       result := complete;
1162       GOTO return_success;
1163 
1164     ELSE
1165       result := '';
1166       GOTO return_success;
1167 
1168    END IF;
1169 
1170    <<return_success>>
1171      RETURN;
1172 
1173    <<return_error>>
1174      --
1175      -- Fatal error abort!
1176      --
1177      wf_engine.SetItemAttrText(itemtype, itemkey,
1178 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
1179      result := error || 'COPY_FROM_COMBINATION';
1180      RETURN;
1181 
1182 EXCEPTION
1183    WHEN OTHERS THEN
1184       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1185 		      'COPY_FROM_COMBINATION', itemtype, itemkey,
1186 		      TO_CHAR(actid), funcmode);
1187       report_wf_error('FND_FLEX_WORKFLOW_APIS.COPY_FROM_COMBINATION');
1188       RAISE;
1189 END copy_from_combination;
1190 
1191 -- ======================================================================
1192 -- COPY_SEGMENT_FROM_COMBINATION
1193 --
1194 --   This procedure copies a given segment value from a
1195 --   specified combination.
1196 --
1197 -- Activity Attributes:
1198 --   CODE_COMBINATION_ID    {number}
1199 --   SEGMENT_IDENTIFIER     {SEGMENT|QUALIFIER}
1200 --   SEGMENT                {varchar2(30)}
1201 --   REPLACE_CURRENT_VALUE  {TRUE|FALSE}
1202 --
1203 -- Result:<None>
1204 --
1205 PROCEDURE copy_segment_from_combination(itemtype IN  VARCHAR2,
1206 					itemkey  IN  VARCHAR2,
1207 					actid    IN  NUMBER,
1208 					funcmode IN  VARCHAR2,
1209 					result   OUT nocopy VARCHAR2)
1210   IS
1211      l_key_flex        fnd_flex_workflow.key_flex_type;
1212      l_ccid            NUMBER;
1213      l_segment_id_type VARCHAR2(30);
1214      l_segment_id      VARCHAR2(30);
1215      l_segment_index   NUMBER;
1216      l_replace_value   BOOLEAN;
1217 BEGIN
1218    IF (funcmode = 'RUN') THEN
1219       --
1220       -- Debug
1221       --
1222       IF (g_debug_fnd_flex_workflow_apis) THEN
1223 	 debug('START FND_FLEX_WORKFLOW_APIS.COPY_SEGMENT_FROM_COMBINATION');
1224       END IF;
1225 
1226       --
1227       -- Get the key flex.
1228       --
1229       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
1230 
1231       --
1232       -- Get all the function activity attributes
1233       --
1234       l_segment_id_type := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
1235 						       'SEGMENT_IDENTIFIER');
1236       l_segment_id := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
1237 						  'SEGMENT');
1238       l_ccid := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
1239 						'CODE_COMBINATION_ID');
1240       l_replace_value := char_to_bool(wf_engine.GetActivityAttrText
1241 				      (itemtype, itemkey, actid,
1242 				       'REPLACE_CURRENT_VALUE'));
1243 
1244       --
1245       -- Debug
1246       --
1247       IF (g_debug_fnd_flex_workflow_apis) THEN
1248 	 debug('SEGMENT_IDENTIFIER = ' || l_segment_id_type);
1249 	 debug('SEGMENT = ' || l_segment_id);
1250 	 debug('CCID = ' || TO_CHAR(l_ccid));
1251 	 debug('REPLACE_CURRENT_VALUE = ' || bool_to_char(l_replace_value));
1252       END IF;
1253 
1254       --
1255       -- Get the segment index.
1256       --
1257       IF (NOT segment_to_index(l_key_flex.application_id,
1258 			       l_key_flex.id_flex_code,
1259 			       l_key_flex.id_flex_num,
1260 			       l_segment_id_type,
1261 			       l_segment_id,
1262 			       l_segment_index)) THEN
1263 	 GOTO return_error;
1264       END IF;
1265 
1266       --
1267       -- Use the IDC cache to get the segment values for this ccid.
1268       --
1269       IF (NOT idc_validate_ccid(l_key_flex.application_short_name,
1270 				l_key_flex.id_flex_code,
1271 				l_key_flex.id_flex_num,
1272 				l_ccid)) THEN
1273 	 GOTO return_error;
1274       END IF;
1275 
1276       --
1277       -- now assign the required value to the segment
1278       -- attribute after checking the replace segment flag.
1279       --
1280       IF (l_replace_value OR
1281 	  (wf_engine.GetItemAttrText(itemtype, itemkey,
1282 				     'FND_FLEX_SEGMENT' || TO_CHAR(l_segment_index))
1283 	   IS NULL)) THEN
1284 	 wf_engine.SetItemAttrText(itemtype, itemkey,
1285 				   'FND_FLEX_SEGMENT' || TO_CHAR(l_segment_index),
1286 				   idc_segment_value(l_segment_index));
1287 	 --
1288 	 -- Debug
1289 	 --
1290 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1291 	    debug('VALUE ASSIGNED : ' || idc_segment_value(l_segment_index));
1292 	 END IF;
1293        ELSE
1294 	 --
1295 	 -- Debug
1296 	 --
1297 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1298 	    debug('VALUE NOT ASSIGNED');
1299 	 END IF;
1300       END IF;
1301 
1302       result := complete_no_result;
1303       GOTO return_success;
1304 
1305     ELSIF (funcmode = 'CANCEL') THEN
1306       result := complete;
1307       GOTO return_success;
1308 
1309     ELSE
1310       result := '';
1311       GOTO return_success;
1312 
1313    END IF;
1314 
1315    <<return_success>>
1316      RETURN;
1317 
1318    <<return_error>>
1319      --
1320      -- Fatal error abort!
1321      --
1322      wf_engine.SetItemAttrText(itemtype, itemkey,
1323 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
1324      result := error || 'COPY_SEGMENT_FROM_COMBINATION';
1325      RETURN;
1326 
1327 EXCEPTION
1328    WHEN OTHERS THEN
1329       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1330 		      'COPY_SEGMENT_FROM_COMBINATION', itemtype, itemkey,
1331 		      TO_CHAR(actid), funcmode);
1332       report_wf_error('FND_FLEX_WORKFLOW_APIS.COPY_SEGMENT_FROM_COMBINATION');
1333       RAISE;
1334 END copy_segment_from_combination;
1335 
1336 -- ======================================================================
1337 -- COPY_SEGMENT_FROM_COMBINATION2
1338 --
1339 --  This procedure copied/pasted from copy_segment_from_combination.
1340 --  It is provided to copy values from a different structure combination.
1341 --  Note: Not from a different flexfield.
1342 --  See bug845445.
1343 --
1344 --   This procedure copies a given segment value from a
1345 --   specified combination.
1346 --
1347 -- Activity Attributes:
1348 --   STRUCTURE_NUMBER       {number}
1349 --   CODE_COMBINATION_ID    {number}
1350 --   SEGMENT_IDENTIFIER     {SEGMENT|QUALIFIER}
1351 --   SEGMENT                {varchar2(30)}
1352 --   REPLACE_CURRENT_VALUE  {TRUE|FALSE}
1353 --
1354 -- Result:<None>
1355 --
1356 PROCEDURE copy_segment_from_combination2(itemtype IN  VARCHAR2,
1357 					 itemkey  IN  VARCHAR2,
1358 					 actid    IN  NUMBER,
1359 					 funcmode IN  VARCHAR2,
1360 					 result   OUT nocopy VARCHAR2)
1361   IS
1362      l_key_flex                  fnd_flex_workflow.key_flex_type;
1363      l_source_id_flex_num        NUMBER;
1364      l_destination_id_flex_num   NUMBER;
1365      l_ccid                      NUMBER;
1366      l_segment_id_type           VARCHAR2(30);
1367      l_segment_id                VARCHAR2(30);
1368      l_source_segment_index      NUMBER;
1369      l_destination_segment_index NUMBER;
1370      l_replace_value             BOOLEAN;
1371 BEGIN
1372    IF (funcmode = 'RUN') THEN
1373       --
1374       -- Debug
1375       --
1376       IF (g_debug_fnd_flex_workflow_apis) THEN
1377 	 debug('START FND_FLEX_WORKFLOW_APIS.COPY_SEGMENT_FROM_COMBINATION2');
1378       END IF;
1379 
1380       --
1381       -- Get the original key flex.
1382       --
1383       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
1384 
1385       --
1386       -- Get all the function activity attributes
1387       --
1388       l_source_id_flex_num := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
1389 							      'STRUCTURE_NUMBER');
1390       l_segment_id_type := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
1391 							 'SEGMENT_IDENTIFIER');
1392       l_segment_id := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
1393 						    'SEGMENT');
1394       l_ccid := wf_engine.GetActivityAttrNumber(itemtype, itemkey, actid,
1395 						'CODE_COMBINATION_ID');
1396       l_replace_value := char_to_bool(wf_engine.GetActivityAttrText
1397 				      (itemtype, itemkey, actid,
1398 				       'REPLACE_CURRENT_VALUE'));
1399 
1400       l_destination_id_flex_num := l_key_flex.id_flex_num;
1401 
1402       --
1403       -- Debug
1404       --
1405       IF (g_debug_fnd_flex_workflow_apis) THEN
1406 	 debug('SOURCE NUM = ' || To_char(l_source_id_flex_num));
1407 	 debug('DEST NUM = ' || To_char(l_destination_id_flex_num));
1408 	 debug('SEGMENT_IDENTIFIER = ' || l_segment_id_type);
1409 	 debug('SEGMENT = ' || l_segment_id);
1410 	 debug('CCID = ' || TO_CHAR(l_ccid));
1411 	 debug('REPLACE_CURRENT_VALUE = ' || bool_to_char(l_replace_value));
1412       END IF;
1413 
1414       --
1415       -- Get the source segment index.
1416       --
1417       IF (NOT segment_to_index(l_key_flex.application_id,
1418 			       l_key_flex.id_flex_code,
1419 			       l_source_id_flex_num,
1420 			       l_segment_id_type,
1421 			       l_segment_id,
1422 			       l_source_segment_index)) THEN
1423 	 GOTO return_error;
1424       END IF;
1425 
1426       --
1427       -- Get the destination segment index.
1428       --
1429       IF (NOT segment_to_index(l_key_flex.application_id,
1430 			       l_key_flex.id_flex_code,
1431 			       l_destination_id_flex_num,
1432 			       l_segment_id_type,
1433 			       l_segment_id,
1434 			       l_destination_segment_index)) THEN
1435 	 GOTO return_error;
1436       END IF;
1437 
1438       --
1439       -- Use the IDC cache to get the source segment values for this ccid.
1440       --
1441       IF (NOT idc_validate_ccid(l_key_flex.application_short_name,
1442 				l_key_flex.id_flex_code,
1443 				l_source_id_flex_num,
1444 				l_ccid)) THEN
1445 	 GOTO return_error;
1446       END IF;
1447 
1448       --
1449       -- Now assign the required value to the destination segment
1450       -- attribute after checking the replace segment flag.
1451       --
1452       IF (l_replace_value OR
1453 	  (wf_engine.GetItemAttrText(itemtype, itemkey,
1454 				     'FND_FLEX_SEGMENT' || TO_CHAR(l_destination_segment_index))
1455 	   IS NULL)) THEN
1456 	 wf_engine.SetItemAttrText(itemtype, itemkey,
1457 				   'FND_FLEX_SEGMENT' || TO_CHAR(l_destination_segment_index),
1458 				   idc_segment_value(l_source_segment_index));
1459 	 --
1460 	 -- Debug
1461 	 --
1462 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1463 	    debug('VALUE ASSIGNED : ' || idc_segment_value(l_source_segment_index));
1464 	 END IF;
1465        ELSE
1466 	 --
1467 	 -- Debug
1468 	 --
1469 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1470 	    debug('VALUE NOT ASSIGNED');
1471 	 END IF;
1472       END IF;
1473 
1474       result := complete_no_result;
1475       GOTO return_success;
1476 
1477     ELSIF (funcmode = 'CANCEL') THEN
1478       result := complete;
1479       GOTO return_success;
1480 
1481     ELSE
1482       result := '';
1483       GOTO return_success;
1484 
1485    END IF;
1486 
1487    <<return_success>>
1488      RETURN;
1489 
1490    <<return_error>>
1491      --
1492      -- Fatal error abort!
1493      --
1494      wf_engine.SetItemAttrText(itemtype, itemkey,
1495 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
1496      result := error || 'COPY_SEGMENT_FROM_COMBINATION2';
1497      RETURN;
1498 
1499 EXCEPTION
1500    WHEN OTHERS THEN
1501       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1502 		      'COPY_SEGMENT_FROM_COMBINATION2', itemtype, itemkey,
1503 		      TO_CHAR(actid), funcmode);
1504       report_wf_error('FND_FLEX_WORKFLOW_APIS.COPY_SEGMENT_FROM_COMBINATION2');
1505       RAISE;
1506 END copy_segment_from_combination2;
1507 
1508 -- ======================================================================
1509 -- IS_COMBINATION_COMPLETE
1510 --
1511 --   This procedure checks to see if all the segments in the combination
1512 --   have been assigned a value. If the attribute CHECK_ONLY_FOR_REQUIRED
1513 --   is set to TRUE, only required segments need to have values.
1514 --
1515 -- Activity Attributes:
1516 --   CHECK_ONLY_FOR_REQUIRED   {TRUE|FALSE}
1517 --
1518 -- Result:
1519 --   TRUE
1520 --   FALSE
1521 --
1522 PROCEDURE is_combination_complete(itemtype IN  VARCHAR2,
1523 				  itemkey  IN  VARCHAR2,
1524 				  actid    IN  NUMBER,
1525 				  funcmode IN  VARCHAR2,
1526 				  result   OUT nocopy VARCHAR2)
1527   IS
1528      l_key_flex        fnd_flex_workflow.key_flex_type;
1529      l_non_required_ok BOOLEAN;
1530      l_segment_index   NUMBER;
1531 
1532      CURSOR cur(p_application_id IN NUMBER,
1533 		p_id_flex_code   IN VARCHAR2,
1534 		p_id_flex_num    IN NUMBER) IS
1535 	SELECT required_flag
1536 	  FROM fnd_id_flex_segments
1537 	  WHERE application_id = p_application_id
1538 	  AND id_flex_code = p_id_flex_code
1539 	  AND id_flex_num = p_id_flex_num
1540 	  AND enabled_flag = 'Y'
1541           ORDER BY segment_num;
1542 BEGIN
1543    IF (funcmode = 'RUN') THEN
1544       --
1545       -- Debug
1546       --
1547       IF (g_debug_fnd_flex_workflow_apis) THEN
1548 	 debug('START FND_FLEX_WORKFLOW_APIS.IS_COMBINATION_COMPLETE');
1549       END IF;
1550 
1551       --
1552       -- Get the key flex.
1553       --
1554       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
1555 
1556       --
1557       -- Get all the function activity attributes
1558       --
1559       l_non_required_ok := char_to_bool(wf_engine.GetActivityAttrText
1560 					(itemtype, itemkey, actid,
1561 					 'CHECK_ONLY_FOR_REQUIRED'));
1562 
1563       IF (g_debug_fnd_flex_workflow_apis) THEN
1564 	 debug('CHECK_ONLY_FOR_REQUIRED = ' || bool_to_char(l_non_required_ok));
1565       END IF;
1566 
1567       --
1568       -- Loop through all the segments and check if all of them have values.
1569       --
1570       l_segment_index := 0;
1571       FOR cur_rec IN cur(l_key_flex.application_id,
1572 			 l_key_flex.id_flex_code,
1573 			 l_key_flex.id_flex_num) LOOP
1574 	 l_segment_index := l_segment_index + 1;
1575 	 IF ((wf_engine.GetItemAttrText(itemtype, itemkey,
1576 					'FND_FLEX_SEGMENT' || TO_CHAR(l_segment_index)) IS NULL) AND
1577 	     ((cur_rec.required_flag = 'Y') OR
1578 	      (NOT l_non_required_ok))) THEN
1579 	    --
1580 	    -- Debug
1581 	    --
1582 	    IF (g_debug_fnd_flex_workflow_apis) THEN
1583 	       debug('COMBINATION NOT COMPLETE');
1584 	    END IF;
1585 	    result := complete_false;
1586 	    GOTO return_success;
1587 	 END IF;
1588       END LOOP;
1589 
1590       --
1591       -- Debug
1592       --
1593       IF (g_debug_fnd_flex_workflow_apis) THEN
1594 	 debug('COMBINATION COMPLETE');
1595       END IF;
1596 
1597       result := complete_true;
1598       GOTO return_success;
1599 
1600     ELSIF (funcmode = 'CANCEL') THEN
1601       result := complete;
1602       GOTO return_success;
1603 
1604     ELSE
1605       result := '';
1606       GOTO return_success;
1607 
1608    END IF;
1609 
1610    <<return_success>>
1611      RETURN;
1612 
1613    <<return_error>>
1614      --
1615      -- Fatal error abort!
1616      --
1617      wf_engine.SetItemAttrText(itemtype, itemkey,
1618 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
1619      result := error || 'IS_COMBINATION_COMPLETE';
1620      RETURN;
1621 
1622 EXCEPTION
1623    WHEN OTHERS THEN
1624       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1625 		      'IS_COMBINATION_COMPLETE', itemtype, itemkey,
1626 		      TO_CHAR(actid), funcmode);
1627       report_wf_error('FND_FLEX_WORKFLOW_APIS.IS_COMBINATION_COMPLETE');
1628       RAISE;
1629 END is_combination_complete;
1630 
1631 -- ======================================================================
1632 -- VALIDATE_COMBINATION
1633 --
1634 --   This procedure validates the combination to generate the code
1635 --   combination id, concatenated segment values, concatenated ids
1636 --   and descriptions.
1637 --
1638 -- Activity Attributes:
1639 --   DYNAMIC_INSERTS_ALLOWED  {TRUE|FALSE}
1640 --   VALIDATION_TYPE          {GENERATE_CCID|VALIDATE_VALUES}
1641 --   CHECK_EXPIRATION         {Y|N}
1642 --   VALIDATION_DATE          {date}
1643 --
1644 -- Result:<None>
1645 --
1646 PROCEDURE validate_combination(itemtype IN  VARCHAR2,
1647 			       itemkey  IN  VARCHAR2,
1648 			       actid    IN  NUMBER,
1649 			       funcmode IN  VARCHAR2,
1650 			       result   OUT nocopy VARCHAR2)
1651   IS
1652      l_key_flex          fnd_flex_workflow.key_flex_type;
1653 
1654      l_insert_if_new     BOOLEAN;
1655      l_dinserts_ok       BOOLEAN;
1656      l_validation_type   VARCHAR2(100);
1657      l_check_expiration  VARCHAR2(1);
1658      l_validation_date   DATE;
1659 
1660      l_segment_array     FND_FLEX_EXT.SegmentArray;
1661      l_concat_segs       VARCHAR2(2000);
1662      l_delimiter         VARCHAR2(10);
1663 
1664      l_keyval_mode       VARCHAR2(100);
1665      l_keyval_status     BOOLEAN;
1666      l_allow_nulls       BOOLEAN;
1667      l_allow_orphans     BOOLEAN;
1668 BEGIN
1669    IF (funcmode = 'RUN') THEN
1670       --
1671       -- Debug
1672       --
1673       IF (g_debug_fnd_flex_workflow_apis) THEN
1674 	 debug('START FND_FLEX_WORKFLOW_APIS.VALIDATE_COMBINATION');
1675       END IF;
1676 
1677       --
1678       -- Get the key flex.
1679       --
1680       fnd_flex_workflow.get_key_flex(itemtype, itemkey, l_key_flex);
1681 
1682       --
1683       -- Get the item attributes
1684       --
1685       l_insert_if_new := char_to_bool(wf_engine.GetItemAttrText
1686 				      (itemtype, itemkey,
1687 				       'FND_FLEX_INSERT'));
1688       --
1689       -- Get all the function activity attributes
1690       --
1691       l_dinserts_ok := char_to_bool(wf_engine.GetActivityAttrText
1692 				    (itemtype, itemkey, actid,
1693 				     'DYNAMIC_INSERTS_ALLOWED'));
1694       l_validation_type := wf_engine.GetActivityAttrText(itemtype, itemkey, actid,
1695 							 'VALIDATION_TYPE');
1696       l_check_expiration := Nvl(wf_engine.GetActivityAttrText
1697 				(itemtype, itemkey, actid,
1698 				 'CHECK_EXPIRATION',TRUE), 'Y');
1699 
1700       --
1701       -- If no date is specified then default it to Sysdate.
1702       -- IF check_expiration is turned off then set validation_date
1703       -- to NULL, this will turn off the vdate check in SSV engine.
1704       --
1705       IF (l_check_expiration = 'Y') THEN
1706 	 l_validation_date := Nvl(wf_engine.GetActivityAttrDate
1707 				  (itemtype, itemkey, actid,
1708 				   'VALIDATION_DATE',TRUE), Sysdate);
1709        ELSE
1710 	 l_validation_date := NULL;
1711       END IF;
1712 
1713       --
1714       -- Debug
1715       --
1716       IF (g_debug_fnd_flex_workflow_apis) THEN
1717 	 debug('INSERT IF NEW COMBINATION = ' || bool_to_char(l_insert_if_new));
1718 	 debug('DYNAMIC_INSERTS_ALLOWED = ' || bool_to_char(l_dinserts_ok));
1719 	 debug('VALIDATION_TYPE = ' || l_validation_type);
1720 	 debug('CHECK EXPIRATION = ' || l_check_expiration);
1721 	 debug('VALIDATION DATE = ' || To_char(l_validation_date,
1722 					       'YYYY/MM/DD HH24:MI:SS'));
1723       END IF;
1724 
1725       --
1726       -- Populate the segment array with the segment values
1727       --
1728       FOR i IN 1..l_key_flex.numof_segments LOOP
1729 	 l_segment_array(i) :=
1730 	   wf_engine.GetItemAttrText(itemtype, itemkey,
1731 				     'FND_FLEX_SEGMENT' || TO_CHAR(i));
1732 	 --
1733 	 -- Debug
1734 	 --
1735 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1736 	    debug('FND_FLEX_SEGMENT' || TO_CHAR(i) || ' IS ' ||
1737 		  l_segment_array(i));
1738 	 END IF;
1739       END LOOP;
1740 
1741       --
1742       -- Use the FND_FLEX_EXT pacakge to concatenate the segments
1743       --
1744       l_delimiter := fnd_flex_ext.get_delimiter(l_key_flex.application_short_name,
1745 						l_key_flex.id_flex_code,
1746 						l_key_flex.id_flex_num);
1747       IF (l_delimiter = NULL) THEN
1748 	 GOTO return_error;
1749       END IF;
1750       l_concat_segs := fnd_flex_ext.concatenate_segments(l_key_flex.numof_segments,
1751 							 l_segment_array,
1752 							 l_delimiter);
1753 
1754       --
1755       -- Debug
1756       --
1757       IF (g_debug_fnd_flex_workflow_apis) THEN
1758 	 debug('CONCATENATED SEGMENTS TO BE VALIDATED IS ' || l_concat_segs);
1759       END IF;
1760 
1761       --
1762       -- Use the CCC Cache package to validate the combination
1763       --
1764       IF (l_validation_type = 'VALIDATE_VALUES') THEN
1765 	 l_keyval_mode := 'CHECK_SEGMENTS';
1766 	 l_allow_nulls := TRUE;
1767 	 l_allow_orphans := TRUE;
1768        ELSIF (l_validation_type = 'GENERATE_CCID') THEN
1769 	 IF (NOT l_dinserts_ok) THEN
1770 	    l_keyval_mode := 'FIND_COMBINATION';
1771 	  ELSE
1772 	    IF (l_insert_if_new) THEN
1773 	       l_keyval_mode := 'CREATE_COMBINATION';
1774 	     ELSE
1775 	       l_keyval_mode := 'CHECK_COMBINATION';
1776 	    END IF;
1777 	 END IF;
1778 	 l_allow_nulls := FALSE;
1779 	 l_allow_orphans := FALSE;
1780       END IF;
1781 
1782       l_keyval_status := ccc_validate_segs(l_keyval_mode,
1783 					   l_key_flex.application_short_name,
1784 					   l_key_flex.id_flex_code,
1785 					   l_key_flex.id_flex_num,
1786 					   l_concat_segs,
1787 					   l_validation_date,
1788 					   l_allow_nulls,
1789 					   l_allow_orphans);
1790 
1791       IF (NOT l_keyval_status) THEN
1792 	 --
1793 	 -- Debug
1794 	 --
1795 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1796 	    debug('VALIDATION FAILED');
1797 	 END IF;
1798 
1799 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_STATUS',
1800 				   'INVALID');
1801 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_MESSAGE',
1802 				   ccc_last_record.encoded_error_message);
1803 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_CCID',
1804 				   '0');
1805 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_SEGMENTS',
1806 				   l_concat_segs);
1807 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_DATA',
1808 				   '');
1809 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_DESCRIPTIONS',
1810 				   '');
1811 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_NEW',
1812 				   'N');
1813 
1814 	 result := complete_no_result;
1815 	 GOTO return_success;
1816 
1817        ELSE
1818 	 --
1819 	 -- Debug
1820 	 --
1821 	 IF (g_debug_fnd_flex_workflow_apis) THEN
1822 	    debug('VALIDATION SUCCEEDED');
1823 	    debug('CCID IS ' || TO_CHAR(ccc_last_record.combination_id));
1824 	 END IF;
1825 
1826 	 wf_engine.SetItemAttrText
1827 	   (itemtype, itemkey, 'FND_FLEX_STATUS', 'VALID');
1828 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_CCID',
1829 				   To_char(ccc_last_record.combination_id));
1830 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_SEGMENTS',
1831 				   ccc_last_record.concatenated_values);
1832 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_DATA',
1833 				   ccc_last_record.concatenated_ids);
1834 	 wf_engine.SetItemAttrText(itemtype, itemkey, 'FND_FLEX_DESCRIPTIONS',
1835 				   ccc_last_record.concatenated_descriptions);
1836 	 IF (l_keyval_mode = 'CREATE_COMBINATION' AND
1837 	     ccc_last_record.new_combination) THEN
1838 	    wf_engine.SetItemAttrText
1839 	      (itemtype, itemkey, 'FND_FLEX_NEW', 'Y');
1840 	  ELSE
1841 	    wf_engine.SetItemAttrText
1842 	      (itemtype, itemkey, 'FND_FLEX_NEW', 'N');
1843 	 END IF;
1844 
1845 	 result := complete_no_result;
1846 	 GOTO return_success;
1847       END IF;
1848 
1849     ELSIF (funcmode = 'CANCEL') THEN
1850       result := complete;
1851       GOTO return_success;
1852 
1853     ELSE
1854       result := '';
1855       GOTO return_success;
1856 
1857    END IF;
1858 
1859    <<return_success>>
1860      RETURN;
1861 
1862    <<return_error>>
1863      --
1864      -- Fatal error abort!
1865      --
1866      wf_engine.SetItemAttrText(itemtype, itemkey,
1867 			       'FND_FLEX_MESSAGE', fnd_message.get_encoded);
1868      result := error || 'VALIDATE_COMBINATION';
1869      RETURN;
1870 
1871 EXCEPTION
1872    WHEN OTHERS THEN
1873       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1874 		      'VALIDATE_COMBINATION', itemtype, itemkey,
1875 		      TO_CHAR(actid), funcmode);
1876       report_wf_error('FND_FLEX_WORKFLOW_APIS.VALIDATE_COMBINATION');
1877       RAISE;
1878 END validate_combination;
1879 
1880 -- ======================================================================
1881 -- ABORT_GENERATION
1882 --
1883 --   This process is used to abort the combination generation process.
1884 --   An error message can be passed to this function which can be displayed
1885 --   from the calling form or program.
1886 --   This process terminates the top level process and returns
1887 --   a result of FAILURE.
1888 --
1889 -- Activity Attribute:
1890 --   ERROR_MESSAGE    {varchar2(2000)}
1891 --
1892 -- Result:
1893 --   FAILURE
1894 --
1895 PROCEDURE abort_generation(itemtype IN  VARCHAR2,
1896 			   itemkey  IN  VARCHAR2,
1897 			   actid    IN  NUMBER,
1898 			   funcmode IN  VARCHAR2,
1899 			   result   OUT nocopy VARCHAR2)
1900   IS
1901      l_errmsg VARCHAR2(2000) DEFAULT '';
1902 BEGIN
1903    IF (funcmode = 'RUN') THEN
1904       --
1905       -- Debug
1906       --
1907       IF (g_debug_fnd_flex_workflow_apis) THEN
1908 	 debug('START FND_FLEX_WORKFLOW_APIS.ABORT_GENERATION');
1909       END IF;
1910 
1911       --
1912       -- Get the function activity attribute
1913       --
1914       l_errmsg := wf_engine.GetActivityAttrText(itemtype, itemkey,
1915 						actid, 'ERROR_MESSAGE');
1916 
1917       --
1918       -- Save the error message passed in.
1919       --
1920       wf_engine.SetItemAttrText(itemtype, itemkey,
1921 				'FND_FLEX_MESSAGE', l_errmsg);
1922 
1923       result := complete_failure;
1924       GOTO return_success;
1925 
1926     ELSIF (funcmode = 'CANCEL') THEN
1927       result := complete;
1928       GOTO return_success;
1929 
1930     ELSE
1931       result := '';
1932       GOTO return_success;
1933 
1934    END IF;
1935 
1936    <<return_success>>
1937      RETURN;
1938 
1939 EXCEPTION
1940    WHEN OTHERS THEN
1941       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1942 		      'END_IN_FAILURE', itemtype, itemkey,
1943 		      TO_CHAR(actid), funcmode);
1944       report_wf_error('FND_FLEX_WORKFLOW_APIS.ABORT_GENERATION');
1945       RAISE;
1946 END abort_generation;
1947 
1948 -- ======================================================================
1949 -- END_GENERATION
1950 --
1951 --   This procedure marks the ending of the code combination generation
1952 --   process without any errors.
1953 --
1954 -- Activity Attribute:
1955 --
1956 -- Result:
1957 --   SUCCESS
1958 --
1959 PROCEDURE end_generation(itemtype IN  VARCHAR2,
1960 			 itemkey  IN  VARCHAR2,
1961 			 actid    IN  NUMBER,
1962 			 funcmode IN  VARCHAR2,
1963 			 result   OUT nocopy VARCHAR2)
1964   IS
1965 BEGIN
1966    IF (funcmode = 'RUN') THEN
1967       --
1968       -- Debug
1969       --
1970       IF (g_debug_fnd_flex_workflow_apis) THEN
1971 	 debug('START FND_FLEX_WORKFLOW_APIS.END_GENERATION');
1972       END IF;
1973 
1974       result := complete_success;
1975       GOTO return_success;
1976 
1977     ELSIF (funcmode = 'CANCEL') THEN
1978       result := complete;
1979       GOTO return_success;
1980 
1981     ELSE
1982       result := '';
1983       GOTO return_success;
1984 
1985    END IF;
1986 
1987    <<return_success>>
1988      RETURN;
1989 
1990 EXCEPTION
1991    WHEN OTHERS THEN
1992       wf_core.context('FND_FLEX_WORKFLOW_APIS',
1993 		      'END_IN_SUCCESS', itemtype, itemkey,
1994 		      TO_CHAR(actid), funcmode);
1995       report_wf_error('FND_FLEX_WORKFLOW_APIS.END_GENERATION');
1996       RAISE;
1997 END end_generation;
1998 
1999 -- ======================================================================
2000 -- Set the debug mode on
2001 --
2002 PROCEDURE debug_on IS
2003 BEGIN
2004    execute immediate ('begin dbms' ||
2005 		      '_output' ||
2006 		      '.enable(1000000); end;');
2007    g_debug_fnd_flex_workflow_apis := TRUE;
2008 END debug_on;
2009 
2010 --
2011 -- Set the debug mode off
2012 --
2013 PROCEDURE debug_off IS
2014 BEGIN
2015    g_debug_fnd_flex_workflow_apis := FALSE;
2016 END debug_off;
2017 
2018 BEGIN
2019    chr_newline        := fnd_global.newline;
2020    complete           := wf_engine.eng_completed;
2021    error              := wf_engine.eng_error || ':';
2022    complete_no_result := wf_engine.eng_completed || ':' || wf_engine.eng_null;
2023    complete_error     := wf_engine.eng_completed || ':' || wf_engine.eng_error;
2024    complete_true      := wf_engine.eng_completed || ':' || 'TRUE';
2025    complete_false     := wf_engine.eng_completed || ':' || 'FALSE';
2026    complete_failure   := wf_engine.eng_completed || ':' || 'FAILURE';
2027    complete_success   := wf_engine.eng_completed || ':' || 'SUCCESS';
2028 
2029 
2030    fnd_plsql_cache.generic_1to1_init('WKA.UQS',
2031 				     uqs_cache_controller,
2032 				     uqs_cache_storage);
2033 
2034    fnd_plsql_cache.generic_1to1_init('WKA.GSN',
2035 				     gsn_cache_controller,
2036 				     gsn_cache_storage);
2037 
2038    fnd_plsql_cache.generic_1to1_init('WKA.IDC',
2039 				     idc_cache_controller,
2040 				     idc_cache_storage);
2041 
2042    fnd_plsql_cache.generic_1to1_init('WKA.CCC',
2043 				     ccc_cache_controller,
2044 				     ccc_cache_storage);
2045 
2046    idc_last_record.segment_values := fnd_plsql_cache.cache_varchar2_varray_type();
2047    idc_last_record.segment_values.EXTEND(fnd_plsql_cache.CACHE_MAX_NUMOF_KEYS);
2048 END fnd_flex_workflow_apis;