DBA Data[Home] [Help]

PACKAGE BODY: APPS.AMW_VIOLATION_PUB

Source


1 package body AMW_VIOLATION_PUB as
2 /* $Header: amwvpubb.pls 120.9 2008/02/18 09:23:59 ptulasi ship $ */
3 
4 
5 l_curr_log_level number := FND_LOG.G_CURRENT_RUNTIME_LEVEL;
6 l_log_stmt_level number := FND_LOG.LEVEL_STATEMENT;
7 g_menu_id_list G_NUMBER_TABLE;
8 g_function_id_list G_NUMBER_TABLE;
9 g_menu_function_id_list G_NUMBER_TABLE;
10 
11 -- ===============================================================
12 -- Private Function name
13 --          get_User_Id
14 --
15 -- Purpose
16 --          This function takes user_name as input and returns user_id
17 -- Params
18 --          p_user_name          := user_name
19 -- Return
20 -- Notes
21 -- History
22 --          18.02.2008 ptulasi: Created for bug 6715425
23 --
24 -- ===============================================================
25 Function get_User_Id (
26     p_user_name     IN  VARCHAR2
27 ) return NUMBER IS
28 p_user_id NUMBER;
29 BEGIN
30 
31     SELECT user_id INTO p_user_id  FROM fnd_user WHERE user_name = p_user_name;
32     RETURN p_user_id;
33 END get_User_Id;
34 
35 -- ===============================================================
36 -- Private Function name
37 --          PROCESS_MENU_TREE_DOWN_FOR_MN
38 --
39 -- Purpose
40 --          Plow through the menu tree to find all the functions in it.
41 -- Params
42 --          p_menu_id           := menu_id
43 -- Return
44 -- Notes
45 -- History
46 --          07.05.2007 psomanat: Created for bug 6010908
47 --
48 -- ===============================================================
49 FUNCTION PROCESS_MENU_TREE_DOWN_FOR_MN( p_menu_id IN number )
50 RETURN boolean IS
51     L_API_NAME                  CONSTANT VARCHAR2(30) := 'PROCESS_MENU_TREE_DOWN_FOR_MN';
52     L_API_VERSION_NUMBER        CONSTANT NUMBER		  := 1.0;
53 
54     TYPE NUMBER_TABLE_TYPE IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
55     TYPE MENULIST_TYPE IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
56     TYPE MNESCURTYP IS REF CURSOR;
57 
58     get_mnes_c MNESCURTYP;
59     l_mnes_dynamic_sql   VARCHAR2(200)  :=
60         'SELECT MENU_ID,FUNCTION_ID, SUB_MENU_ID '
61       ||'  FROM '||G_AMW_MENU_ENTRIES
62       ||' WHERE menu_id  = :1 ';
63 
64 
65     tbl_func_id NUMBER_TABLE_TYPE;
66     tbl_submnu_id NUMBER_TABLE_TYPE;
67     tbl_menu_id NUMBER_TABLE_TYPE;
68 
69     menulist  MENULIST_TYPE;
70     menulist_cur PLS_INTEGER;
71     menulist_size PLS_INTEGER;
72     last_index PLS_INTEGER;
73     c_max_menu_entries CONSTANT PLS_INTEGER := 10000;
74     l_sub_menu_id NUMBER;
75 
76 
77 
78 BEGIN
79     -- Initialize menulist working list to parent menu
80     menulist_cur := 0;
81     menulist_size := 1;
82     menulist(0) := p_menu_id;
83 
84     -- Continue processing until reach the end of list
85     WHILE (menulist_cur < menulist_size)
86     LOOP
87         -- Check if recursion limit exceeded
88         IF (menulist_cur > c_max_menu_entries) THEN
89             /* If the function were accessible from this menu, then we should */
90             /* have found it before getting to this point, so we are confident */
91             /* that the function is not on this menu. */
92             RETURN false;
93         END IF;
94 
95         l_sub_menu_id := menulist(menulist_cur);
96 
97         IF g_menu_id_list.EXISTS(l_sub_menu_id) THEN
98              menulist_cur := menulist_cur + 1;
99         ELSE
100             IF l_sub_menu_id IS NOT NULL THEN
101                 g_menu_id_list(l_sub_menu_id):=l_sub_menu_id;
102 
103             END IF;
104 
105             OPEN get_mnes_c FOR l_mnes_dynamic_sql USING l_sub_menu_id;
106             FETCH get_mnes_c BULK COLLECT INTO tbl_menu_id,tbl_func_id, tbl_submnu_id;
107             CLOSE get_mnes_c;
108 
109             -- See if we found any rows. If not set last_index to zero.
110             BEGIN
111                 IF((tbl_menu_id.FIRST IS NULL) OR (tbl_menu_id.FIRST <> 1)) THEN
112                     last_index := 0;
113                 ELSE
114                     IF (tbl_menu_id.FIRST IS NOT NULL) THEN
115                         last_index := tbl_menu_id.LAST;
116                     ELSE
117                         last_index := 0;
118                     END IF;
119                 END IF;
120             EXCEPTION
121                 WHEN others THEN
122                     last_index := 0;
123             END;
124 
125             -- Process each of the child entries fetched
126             FOR i IN 1 .. last_index LOOP
127 
128                 -- If this is a submenu, then add it to the end of the
129                 -- working list for processing.
130                 IF (tbl_submnu_id(i) IS NOT NULL) THEN
131                     menulist(menulist_size) := tbl_submnu_id(i);
132                     menulist_size := menulist_size + 1;
133                 ELSE
134                     IF NOT(g_function_id_list.EXISTS(tbl_func_id(i))) THEN
135                         g_function_id_list(tbl_func_id(i)):=tbl_func_id(i);
136                         g_menu_function_id_list(g_menu_function_id_list.count+1):=tbl_func_id(i);
137                     END IF;
138                 END IF;
139             END LOOP;  -- For loop processing child entries
140 
141             -- Advance to next menu on working list
142             menulist_cur := menulist_cur + 1;
143         END IF;
144     END LOOP;
145     -- We couldn't find the function anywhere, so it's not available
146     RETURN true;
147 END PROCESS_MENU_TREE_DOWN_FOR_MN;
148 
149 
150 -- ===============================================================
151 -- Function name
152 --          Check_Resp_Violations
153 --
154 -- Purpose
155 --          check for OICM SOD constriants that will be violated
156 --          if the user is assigned the additional responsibility
157 -- Params
158 --          p_user_id            := input fnd user_id
159 --          p_responsibility_id  := input fnd responsibility_id
160 -- Return
161 --          'N'                  := if no SOD violation found.
162 --          'Y'                  := if SOD violation exists.
163 --                                  The SOD violation should NOT be restricted to
164 --                                  only the new responsiblity.
165 --                                  If the existing responsibilities have any violations,
166 --                                  the function should return 'Y' as well.
167 --
168 -- History
169 -- 		  	07/13/2005    tsho     Create
170 --          08/03/2005    tsho     Consider User Waivers
171 --          08/22/2005    tsho     Consider only prevent(PR) constraint objective
172 -- ===============================================================
173 Function Check_Resp_Violations (
174     p_user_id               IN  NUMBER,
175     p_responsibility_id     IN  NUMBER
176 ) return VARCHAR2
177 IS
178 L_API_NAME                  CONSTANT VARCHAR2(30) := 'Has_Violation_Due_To_Resp';
179 L_API_VERSION_NUMBER        CONSTANT NUMBER		  := 1.0;
180 
181 -- return result
182 has_violation VARCHAR2(10);
183 
184 -- find all valid preventive constraints
185 CURSOR c_all_valid_constraints IS
186       SELECT constraint_rev_id, type_code
187         FROM amw_constraints_b
188        WHERE start_date <= sysdate AND (end_date IS NULL OR end_date >= sysdate)
189        AND objective_code = 'PR';
190 
191 
192 l_all_valid_constraints c_all_valid_constraints%ROWTYPE;
193 
194 -- find the number of constraint entries(incompatible functions) by specified constraint_rev_id
195 l_constraint_entries_count NUMBER;
196 l_func_access_count NUMBER;
197 l_group_access_count NUMBER;
198 l_resp_access_count NUMBER;
199 
200 
201 CURSOR c_constraint_entries_count (l_constraint_rev_id IN NUMBER) IS
202       SELECT count(*)
203         FROM amw_constraint_entries
204 	   WHERE constraint_rev_id=l_constraint_rev_id;
205 
206 TYPE refCurTyp IS REF CURSOR;
207 func_acess_count_c refCurTyp;
208 group_acess_count_c refCurTyp;
209 new_violation_count_c refCurTyp;
210 resp_acess_count_c refCurTyp;
211 
212 l_vio_new_resp_sql VARCHAR2(32767);
213 
214 l_func_sql VARCHAR2(32767);
215 -- in amw.e, we don't consider UMX integration and role/resp hierarchy structure
216 l_func_id_sql   VARCHAR2(32767)  :=
217     'select distinct function_id from ( '
218   ||'  select rcd.function_id '
219   ||'  from amw_role_constraint_denorm rcd '
220   ||'      ,'||G_AMW_USER_ROLES||' ur '
221   ||'      ,'||G_AMW_user||' u '
222   ||'  where rcd.constraint_rev_id = :1 '
223   ||'    and u.user_id = :2 '
224   ||'    and u.user_name = ur.user_name '
225   ||'    and ur.role_name = rcd.role_name '
226   ||'    and ur.role_orig_system = ''UMX'' '
227   ||'  UNION ALL '
228   ||'  select rcd.function_id '
229   ||'  from amw_role_constraint_denorm rcd '
230   ||'      ,'||G_AMW_USER_ROLES||' ur '
231   ||'      ,'||G_AMW_user||' u '
232   ||'  where rcd.constraint_rev_id = :3 '
233   ||'    and u.user_id = :4 '
234   ||'    and u.user_name = ur.user_name '
235   ||'    and ur.role_orig_system_id = rcd.responsibility_id '
236   ||'    and ur.role_orig_system = ''FND_RESP'' '
237   ||'  UNION ALL '
238   ||'  select rcd.function_id '
239   ||'  from amw_role_constraint_denorm rcd '
240   ||'      ,'||G_AMW_GRANTS||' gra '
241   ||'      ,'||G_AMW_USER||' u '
242   ||'  where rcd.constraint_rev_id = :5 '
243   ||'    and u.user_id = :6 '
244   ||'    and u.user_name = gra.grantee_key '
245   ||'    and gra.grantee_type = ''USER'' '
246   ||'    and gra.menu_id = rcd.menu_id '
247   ||'    and gra.instance_type = ''GLOBAL'' '
248   ||'    and gra.object_id = -1 '
249   ||'  UNION ALL '
250   ||'  select rcd.function_id '
251   ||'  from amw_role_constraint_denorm rcd '
252   ||'      ,'||G_AMW_GRANTS||' gra '
253   ||'  where rcd.constraint_rev_id = :7 '
254   ||'    and gra.grantee_key = ''GLOBAL'' '
255   ||'    and gra.grantee_type = ''GLOBAL'' '
256   ||'    and gra.menu_id = rcd.menu_id '
257   ||'    and gra.instance_type = ''GLOBAL'' '
258   ||'    and gra.object_id = -1 '
259   ||'  UNION ALL '
260   ||'  select rcd.function_id '
261   ||'  from amw_role_constraint_denorm rcd '
262   ||'  where rcd.constraint_rev_id = :8 '
263   ||'    and rcd.responsibility_id = :9 '
264   ||') ';
265 
266 l_func_dynamic_sql   VARCHAR2(32767)  :=
267     'select count(function_id) from ( '
268     || l_func_id_sql
269     || ') ';
270 
271 l_func_set_id_sql   VARCHAR2(2500)  :=
272     'select distinct group_code from ( '
273   ||'  select rcd.group_code '
274   ||'  from amw_role_constraint_denorm rcd '
275   ||'      ,'||G_AMW_USER_ROLES||' ur '
276   ||'      ,'||G_AMW_user||' u '
277   ||'  where rcd.constraint_rev_id = :1 '
278   ||'    and u.user_id = :2 '
279   ||'    and u.user_name = ur.user_name '
280   ||'    and ur.role_name = rcd.role_name '
281   ||'    and ur.role_orig_system = ''UMX'' '
282   ||'  UNION ALL '
283   ||'  select rcd.group_code '
284   ||'  from amw_role_constraint_denorm rcd '
285   ||'      ,'||G_AMW_USER_ROLES||' ur '
286   ||'      ,'||G_AMW_user||' u '
287   ||'  where rcd.constraint_rev_id = :3 '
288   ||'    and u.user_id = :4 '
289   ||'    and u.user_name = ur.user_name '
290   ||'    and ur.role_orig_system_id = rcd.responsibility_id '
291   ||'    and ur.role_orig_system = ''FND_RESP'' '
292   ||'  UNION ALL '
293   ||'  select rcd.group_code '
294   ||'  from amw_role_constraint_denorm rcd '
295   ||'      ,'||G_AMW_GRANTS||' gra '
296   ||'      ,'||G_AMW_USER||' u '
297   ||'  where rcd.constraint_rev_id = :5 '
298   ||'    and u.user_id = :6 '
299   ||'    and u.user_name = gra.grantee_key '
300   ||'    and gra.grantee_type = ''USER'' '
301   ||'    and gra.menu_id = rcd.menu_id '
302   ||'    and gra.instance_type = ''GLOBAL'' '
303   ||'    and gra.object_id = -1 '
304   ||'  UNION ALL '
305   ||'  select rcd.group_code '
306   ||'  from amw_role_constraint_denorm rcd '
307   ||'      ,'||G_AMW_GRANTS||' gra '
308   ||'  where rcd.constraint_rev_id = :7 '
309   ||'    and gra.grantee_key = ''GLOBAL'' '
310   ||'    and gra.grantee_type = ''GLOBAL'' '
311   ||'    and gra.menu_id = rcd.menu_id '
312   ||'    and gra.instance_type = ''GLOBAL'' '
313   ||'    and gra.object_id = -1 '
314   ||'  UNION ALL '
315   ||'  select rcd.group_code '
316   ||'  from amw_role_constraint_denorm rcd '
317   ||'  where rcd.constraint_rev_id = :8 '
318   ||'  and rcd.responsibility_id = :9 '
319   ||') ';
320 
321   l_func_set_dynamic_sql   VARCHAR2(2500)  :=
322     'select count(group_code) from ( '
323     || l_func_set_id_sql
324     ||' ) ';
325 
326 
327  l_resp_sql VARCHAR2(32767);
328 
329 
330 -- all of roles including the existing ones and the newly assigned ones
331 l_resp_all_sql   VARCHAR2(32767)  :=
332   '  select ur.role_orig_system_id '
333   ||'  from '
334   || G_AMW_USER_ROLES||' ur '
335   ||'      ,'||G_AMW_user||' u '
336   ||'      ,amw_constraint_entries cst '
337   ||'  where  u.user_id = :1 '
338   ||'    and  cst.constraint_rev_id = :2 '
339   ||'    and u.user_name = ur.user_name '
340   ||'    and ur.role_orig_system_id = cst.function_id '
341   ||'    and ur.role_orig_system = ''FND_RESP'' '
342   ||'  UNION '
343   ||'  select cst.function_id as orig_system_id '
344   ||'  from  amw_constraint_entries cst '
345   ||'  where  cst.constraint_rev_id = :3 '
346   ||'  and cst.function_id = :4 ';
347 
348 
349 l_resp_dynamic_sql  VARCHAR2(32767) :=
350 ' select count(role_orig_system_id) from ( '
351 || l_resp_all_sql
352 ||')';
353 
354 
355 l_resp_set_all_sql   VARCHAR2(32767)  :=
356   '  select cst.group_code '
357   ||'  from '
358   || G_AMW_USER_ROLES||' ur '
359   ||'      ,'||G_AMW_user||' u '
360   ||'      ,amw_constraint_entries cst '
361   ||'  where  u.user_id = :1 '
362   ||'    and  cst.constraint_rev_id = :2 '
363   ||'    and u.user_name = ur.user_name '
364   ||'    and ur.role_orig_system_id = cst.function_id '
365   ||'    and ur.role_orig_system = ''FND_RESP'' '
366   ||'  UNION '
367   ||'  select cst.group_code '
368   ||'  from   amw_constraint_entries cst '
369   ||'  where  cst.constraint_rev_id = :3 '
370   ||'  and cst.function_id = :4 ';
371 
372   l_resp_set_dynamic_sql   VARCHAR2(32767) :=
373   ' select count(group_code) from ( '
374 || l_resp_set_all_sql
375 ||')';
376 
377 
378 -- get valid user waiver
379 l_valid_user_waiver_count NUMBER;
380 CURSOR c_valid_user_waivers (l_constraint_rev_id IN NUMBER, l_user_id IN NUMBER) IS
381     SELECT count(*)
382       FROM amw_constraint_waivers_vl
383      WHERE constraint_rev_id = l_constraint_rev_id
384        AND object_type = 'USER'
385        AND PK1 = l_user_id
386        AND start_date <= sysdate AND (end_date >= sysdate or end_date is null);
387 
388        l_cst_new_violation_sql   VARCHAR2(5000) ;
389 
390 BEGIN
391 
392     IF( l_log_stmt_level >= l_curr_log_level ) THEN
393     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Check_Resp_Violations Start');
394     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','p_user_id             = '|| p_user_id );
395     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','p_responsibility_id   = '|| p_responsibility_id);
396 	END IF;
397 
398   -- default to 'N', which means user doesn't have violations
399   has_violation := 'N';
400   l_valid_user_waiver_count := 0;
401 
402   IF (p_user_id IS NOT NULL AND p_responsibility_id IS NOT NULL) THEN
403     -- check all valid constraints
404     OPEN c_all_valid_constraints;
405     LOOP
406      FETCH c_all_valid_constraints INTO l_all_valid_constraints;
407      EXIT WHEN c_all_valid_constraints%NOTFOUND;
408 
409      -- check if this user is waived (due to User Waiver) from this constraint
410      OPEN c_valid_user_waivers(l_all_valid_constraints.constraint_rev_id, p_user_id);
411      FETCH c_valid_user_waivers INTO l_valid_user_waiver_count;
412      CLOSE c_valid_user_waivers;
413 
414     IF l_valid_user_waiver_count <= 0 THEN
415 
416       IF 'ALL' = l_all_valid_constraints.type_code THEN
417 
418         -- find the number of constraint entries(incompatible functions) by specified constraint_rev_id
419         OPEN c_constraint_entries_count (l_all_valid_constraints.constraint_rev_id);
420         FETCH c_constraint_entries_count INTO l_constraint_entries_count;
421         CLOSE c_constraint_entries_count;
422 
423         OPEN func_acess_count_c FOR l_func_dynamic_sql USING
424               l_all_valid_constraints.constraint_rev_id,
425               p_user_id,
426               l_all_valid_constraints.constraint_rev_id,
427               p_user_id,
428               l_all_valid_constraints.constraint_rev_id,
429               p_user_id,
430               l_all_valid_constraints.constraint_rev_id,
431               l_all_valid_constraints.constraint_rev_id,
432               p_responsibility_id;
433         FETCH func_acess_count_c INTO l_func_access_count;
434         CLOSE func_acess_count_c;
435 
436         -- in ALL type: if user can access to all entries of this constraint,
437         -- he violates this constraint
438         IF l_func_access_count = l_constraint_entries_count THEN
439 
440             -- Check to see if the fuction enteries in the constraint is same
441             -- as the functions the user can access due to the assigning of
442             -- this role
443             l_func_sql :='select count(function_id)'
444                         ||'from ('
445                         ||'select function_id from ( '
446                         ||   l_func_id_sql
447                         ||') '
448                         ||' MINUS '
449                         ||' select FUNCTION_ID from amw_constraint_entries where constraint_rev_id = :10'
450                         ||')';
451 
452 
453 
454             OPEN func_acess_count_c FOR l_func_sql USING
455                 l_all_valid_constraints.constraint_rev_id,
456                 p_user_id,
457                 l_all_valid_constraints.constraint_rev_id,
458                 p_user_id,
459                 l_all_valid_constraints.constraint_rev_id,
460                 p_user_id,
461                 l_all_valid_constraints.constraint_rev_id,
462                 l_all_valid_constraints.constraint_rev_id,
463                 p_responsibility_id,
464                 l_all_valid_constraints.constraint_rev_id;
465             FETCH func_acess_count_c INTO l_func_access_count;
466             CLOSE func_acess_count_c;
467 
468             IF l_func_access_count = 0 THEN
469            	    -- once he violates at least one constraint, break the loop and inform FALSE to the caller
470                	FND_FILE.put_line(fnd_file.log, '------------ fail on constraint - ALL = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
471                	has_violation := 'Y';
472                	return has_violation;
473            	END IF;
474         END IF;
475       ELSIF 'ME' = l_all_valid_constraints.type_code THEN
476 
477         -- find the number of distinct constraint entries this user can access
478         OPEN func_acess_count_c FOR l_func_dynamic_sql USING
479               l_all_valid_constraints.constraint_rev_id,
480               p_user_id,
481               l_all_valid_constraints.constraint_rev_id,
482               p_user_id,
483               l_all_valid_constraints.constraint_rev_id,
484               p_user_id,
485               l_all_valid_constraints.constraint_rev_id,
486               l_all_valid_constraints.constraint_rev_id,
487               p_responsibility_id;
488         FETCH func_acess_count_c INTO l_func_access_count;
489         CLOSE func_acess_count_c;
490 
491         -- in ME type: if user can access at least two entries of this constraint,
492         -- he violates this constraint
493         IF l_func_access_count >= 2 THEN
494             -- once he violates at least one constraint, break the loop and inform FALSE to the caller
495             FND_FILE.put_line(fnd_file.log,'------------ fail on constraint - ME = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
496             has_violation := 'Y';
497             return has_violation;
498         END IF;
499       ELSIF 'SET' = l_all_valid_constraints.type_code THEN
500 
501         -- find the number of distinct constraint entries this user can access
502         OPEN group_acess_count_c FOR l_func_set_dynamic_sql USING
503               l_all_valid_constraints.constraint_rev_id,
504               p_user_id,
505               l_all_valid_constraints.constraint_rev_id,
506               p_user_id,
507               l_all_valid_constraints.constraint_rev_id,
508               p_user_id,
509               l_all_valid_constraints.constraint_rev_id,
510               l_all_valid_constraints.constraint_rev_id,
511               p_responsibility_id;
512         FETCH group_acess_count_c INTO l_group_access_count;
513         CLOSE group_acess_count_c;
514 
515         -- in SET type: if user can access at least two distinct groups(set) of this constraint,
516         -- he violates this constraint
517         IF l_group_access_count >= 2 THEN
518             -- once he violates at least one constraint, break the loop and inform FALSE to the caller
519             -- FND_FILE.put_line(fnd_file.log,'------------ fail on constraint - SET = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
520             has_violation := 'Y';
521             return has_violation;
522         END IF;
523      ELSIF 'RESPALL' = l_all_valid_constraints.type_code THEN
524         -- find the number of constraint entries(incompatible functions) by specified constraint_rev_id
525         OPEN c_constraint_entries_count (l_all_valid_constraints.constraint_rev_id);
526         FETCH c_constraint_entries_count INTO l_constraint_entries_count;
527         CLOSE c_constraint_entries_count;
528 
529             OPEN resp_acess_count_c FOR l_resp_dynamic_sql USING
530             p_user_id,
531             l_all_valid_constraints.constraint_rev_id,
532             l_all_valid_constraints.constraint_rev_id,
533              p_responsibility_id;
534             FETCH resp_acess_count_c INTO l_resp_access_count;
535             CLOSE resp_acess_count_c;
536 
537             -- in ALL type: if user can access to all entries of this constraint,
538             -- he violates this constraint
539             IF l_resp_access_count = l_constraint_entries_count THEN
540 
541             -- Check to see if the fuction enteries in the constraint is same
542             -- as the functions the user can access due to the assigning of
543             -- this role
544 
545             l_resp_sql := 'select count(distinct role_orig_system_id)'
546              ||' from ('
547              ||  l_resp_all_sql
548              ||' MINUS '
549              ||' select FUNCTION_ID from amw_constraint_entries where constraint_rev_id = :5'
550              ||')';
551 
552 
553                 OPEN resp_acess_count_c FOR l_resp_sql USING
554                 p_user_id,
555                 l_all_valid_constraints.constraint_rev_id,
556                 l_all_valid_constraints.constraint_rev_id,
557                 p_responsibility_id,
558                 l_all_valid_constraints.constraint_rev_id;
559                 FETCH resp_acess_count_c INTO l_resp_access_count;
560                 CLOSE resp_acess_count_c;
561 
562                 IF l_resp_access_count = 0 THEN
563                  -- once he violates at least one constraint, break the loop and inform FALSE to the caller
564                     FND_FILE.put_line(fnd_file.log, '----fail on constraint - ALL = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
565                     has_violation := 'Y';
566                     return has_violation;
567                 END IF;
568             END IF;
569 
570         ELSIF 'RESPME' = l_all_valid_constraints.type_code THEN
571 
572 
573                 -- find the number of distinct constraint entries this user can access
574                 OPEN resp_acess_count_c FOR l_resp_dynamic_sql USING
575                 p_user_id,
576                 l_all_valid_constraints.constraint_rev_id,
577                 l_all_valid_constraints.constraint_rev_id,
578                 p_responsibility_id;
579                 FETCH resp_acess_count_c INTO l_resp_access_count;
580                 CLOSE resp_acess_count_c;
581 
582 
583                 IF( l_log_stmt_level >= l_curr_log_level ) THEN
584     	           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','l_resp_access_count = '|| l_resp_access_count );
585                 END IF;
586 
587                 -- in ME type: if user can access at least two entries of this constraint,
588                 -- he violates this constraint
589                 IF l_resp_access_count >= 2 THEN
590                     -- once he violates at least one constraint, break the loop and inform FALSE to the caller
591                     FND_FILE.put_line(fnd_file.log,'------------ fail on constraint - ME = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
592                     has_violation := 'Y';
593 
594                     IF( l_log_stmt_level >= l_curr_log_level ) THEN
595     	               FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','has_violation = '|| has_violation );
596     	               FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Check_Resp_Violations End');
597                     END IF;
598 
599                     return has_violation;
600                 END IF;
601 
602       ELSIF 'RESPSET' = l_all_valid_constraints.type_code THEN
603 
604 
605               -- find the number of distinct constraint entries this user can access
606 
607                 OPEN resp_acess_count_c FOR l_resp_set_dynamic_sql USING
608                 p_user_id,
609                 l_all_valid_constraints.constraint_rev_id,
610                 l_all_valid_constraints.constraint_rev_id,
611                 p_responsibility_id;
612                 FETCH resp_acess_count_c INTO l_resp_access_count;
613                 CLOSE resp_acess_count_c;
614 
615                 -- in SET type: if user can access at least two distinct groups(set) of this constraint,
616                 -- he violates this constraint
617                 IF l_resp_access_count >= 2 THEN
618                     -- once he violates at least one constraint, break the loop and inform FALSE to the caller
619                     FND_FILE.put_line(fnd_file.log,'------------ fail on constraint - SET = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
620                     has_violation := 'Y';
621                     return has_violation;
622                 END IF;
623       ELSE
624         -- other constraint types
625         NULL;
626       END IF; -- end of if: constraint type_code
627 
628      END IF; -- end of if: l_valid_user_waiver_count <= 0
629 
630     END LOOP; --end of loop: c_all_valid_constraints
631     CLOSE c_all_valid_constraints;
632 
633   END IF; -- end of if: p_user_id IS NOT NULL AND p_responsibility_id IS NOT NULL
634 
635     IF( l_log_stmt_level >= l_curr_log_level ) THEN
636     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Last has_violation = '|| has_violation );
637     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Check_Resp_Violations End');
638 	END IF;
639 
640   return has_violation;
641 
642 EXCEPTION
643     WHEN OTHERS THEN
644     IF( l_log_stmt_level >= l_curr_log_level ) THEN
645     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
646     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Check_Resp_Violations End');
647 	END IF;
648 	RAISE;
649 
650 END Check_Resp_Violations;
651 
652 
653 
654 -- ===============================================================
655 -- Function name
656 --          User_Resp_Violation_Details
657 --
658 -- Purpose
659 --          check for OICM SOD constriants that will be violated
660 --          if the user is assigned the additional responsibility
661 -- Params
662 --          p_user_id            := input fnd user_id
663 --          p_responsibility_id  := input fnd responsibility_id
664 -- Return
665 --          'N'                            := if no SOD violation found.
666 --          'ConstraintName:Resp_name1;Resp_name2;...'    := if SOD violation exists.
667 --                                            The SOD violation should NOT be restricted to
668 --                                            only the new responsiblity.
669 --                                            If the existing responsibilities have any violations,
670 --                                            the function should return 'Y' as well.
671 --
672 -- History
673 -- 		  	08/01/2005    tsho     Create
674 --          08/03/2005    tsho     Consider User Waivers
675 --          08/22/2005    tsho     Consider only prevent(PR) constraint objective
676 -- ===============================================================
677 Function User_Resp_Violation_Details (
678     p_user_id               IN  NUMBER,
679     p_responsibility_id     IN  NUMBER
680 ) return VARCHAR2
681 IS
682 
683 L_API_NAME                  CONSTANT VARCHAR2(30) := 'Violation_Detail_Due_To_Resp';
684 L_API_VERSION_NUMBER        CONSTANT NUMBER		  := 1.0;
685 
686 -- return result
687 has_violation VARCHAR2(32767);
688 l_violat_existing_resp VARCHAR2(10000);
689 l_violat_existing_role VARCHAR2(10000);
690 l_violat_existing_menu VARCHAR2(10000);
691 l_violat_new_resp VARCHAR2(10000);
692 l_violat_new_func VARCHAR2(10000);
693 
694 l_resp_access_count NUMBER;
695 
696 l_new_func_table JTF_VARCHAR2_TABLE_400;
697 
698 -- 05.23.2006 dliao: consider only Prevent Constraint Objective
699 CURSOR c_all_valid_constraints IS
700       SELECT constraint_rev_id, type_code, constraint_name
701         FROM amw_constraints_vl
702        WHERE start_date <= sysdate AND (end_date IS NULL OR end_date >= sysdate)
703        and objective_code = 'PR';
704 l_all_valid_constraints c_all_valid_constraints%ROWTYPE;
705 
706 -- find the number of constraint entries(incompatible functions) by specified constraint_rev_id
707 l_constraint_entries_count NUMBER;
708 l_func_access_count NUMBER;
709 l_group_access_count NUMBER;
710 CURSOR c_constraint_entries_count (l_constraint_rev_id IN NUMBER) IS
711       SELECT count(*)
712         FROM amw_constraint_entries
713 	   WHERE constraint_rev_id=l_constraint_rev_id;
714 
715 
716 TYPE refCurTyp IS REF CURSOR;
717 func_acess_count_c refCurTyp;
718 group_acess_count_c refCurTyp;
719 resp_acess_count_c refCurTyp;
720 
721 l_func_dynamic_sql   VARCHAR2(2500)  :=
722     'select count(distinct function_id) from ( '
723   ||'  select rcd.function_id '
724   ||'  from amw_role_constraint_denorm rcd '
725   ||'      ,'||G_AMW_USER_ROLES||' ur '
726   ||'      ,'||G_AMW_user||' u '
727   ||'  where rcd.constraint_rev_id = :1 '
728   ||'    and u.user_id = :2 '
729   ||'    and u.user_name = ur.user_name '
730   ||'    and ur.role_name = rcd.role_name '
731   ||'    and ur.role_orig_system = ''UMX'' '
732   ||'  UNION ALL '
733   ||'  select rcd.function_id '
734   ||'  from amw_role_constraint_denorm rcd '
735   ||'      ,'||G_AMW_USER_ROLES||' ur '
736   ||'      ,'||G_AMW_user||' u '
737   ||'  where rcd.constraint_rev_id = :3 '
738   ||'    and u.user_id = :4 '
739   ||'    and u.user_name = ur.user_name '
740   ||'    and ur.role_orig_system_id = rcd.responsibility_id '
741   ||'    and ur.role_orig_system = ''FND_RESP'' '
742   ||'  UNION ALL '
743   ||'  select rcd.function_id '
744   ||'  from amw_role_constraint_denorm rcd '
745   ||'      ,'||G_AMW_GRANTS||' gra '
746   ||'      ,'||G_AMW_USER||' u '
747   ||'  where rcd.constraint_rev_id = :5 '
748   ||'    and u.user_id = :6 '
749   ||'    and u.user_name = gra.grantee_key '
750   ||'    and gra.grantee_type = ''USER'' '
751   ||'    and gra.menu_id = rcd.menu_id '
752   ||'    and gra.instance_type = ''GLOBAL'' '
753   ||'    and gra.object_id = -1 '
754   ||'  UNION ALL '
755   ||'  select rcd.function_id '
756   ||'  from amw_role_constraint_denorm rcd '
757   ||'      ,'||G_AMW_GRANTS||' gra '
758   ||'  where rcd.constraint_rev_id = :7 '
759   ||'    and gra.grantee_key = ''GLOBAL'' '
760   ||'    and gra.grantee_type = ''GLOBAL'' '
761   ||'    and gra.menu_id = rcd.menu_id '
762   ||'    and gra.instance_type = ''GLOBAL'' '
763   ||'    and gra.object_id = -1 '
764   ||'  UNION ALL '
765   ||'  select rcd.function_id '
766   ||'  from amw_role_constraint_denorm rcd '
767   ||'  where rcd.constraint_rev_id = :8 '
768   ||'    and rcd.responsibility_id = :9 '
769   ||') ';
770 
771 l_func_set_dynamic_sql   VARCHAR2(2500)  :=
772     'select count(distinct group_code) from ( '
773   ||'  select rcd.group_code '
774   ||'  from amw_role_constraint_denorm rcd '
775   ||'      ,'||G_AMW_USER_ROLES||' ur '
776   ||'      ,'||G_AMW_user||' u '
777   ||'  where rcd.constraint_rev_id = :1 '
778   ||'    and u.user_id = :2 '
779   ||'    and u.user_name = ur.user_name '
780   ||'    and ur.role_name = rcd.role_name '
781   ||'    and ur.role_orig_system = ''UMX'' '
782   ||'  UNION ALL '
783   ||'  select rcd.group_code '
784   ||'  from amw_role_constraint_denorm rcd '
785   ||'      ,'||G_AMW_USER_ROLES||' ur '
786   ||'      ,'||G_AMW_user||' u '
787   ||'  where rcd.constraint_rev_id = :3 '
788   ||'    and u.user_id = :4 '
789   ||'    and u.user_name = ur.user_name '
790   ||'    and ur.role_orig_system_id = rcd.responsibility_id '
791   ||'    and ur.role_orig_system = ''FND_RESP'' '
792   ||'  UNION ALL '
793   ||'  select rcd.group_code '
794   ||'  from amw_role_constraint_denorm rcd '
795   ||'      ,'||G_AMW_GRANTS||' gra '
796   ||'      ,'||G_AMW_USER||' u '
797   ||'  where rcd.constraint_rev_id = :5 '
798   ||'    and u.user_id = :6 '
799   ||'    and u.user_name = gra.grantee_key '
800   ||'    and gra.grantee_type = ''USER'' '
801   ||'    and gra.menu_id = rcd.menu_id '
802   ||'    and gra.instance_type = ''GLOBAL'' '
803   ||'    and gra.object_id = -1 '
804   ||'  UNION ALL '
805   ||'  select rcd.group_code '
806   ||'  from amw_role_constraint_denorm rcd '
807   ||'      ,'||G_AMW_GRANTS||' gra '
808   ||'  where rcd.constraint_rev_id = :7 '
809   ||'    and gra.grantee_key = ''GLOBAL'' '
810   ||'    and gra.grantee_type = ''GLOBAL'' '
811   ||'    and gra.menu_id = rcd.menu_id '
812   ||'    and gra.instance_type = ''GLOBAL'' '
813   ||'    and gra.object_id = -1 '
814   ||'  UNION ALL '
815   ||'  select rcd.group_code '
816   ||'  from amw_role_constraint_denorm rcd '
817   ||'  where rcd.constraint_rev_id = :8 '
818   ||'    and rcd.responsibility_id = :9 '
819   ||') ';
820 
821 -- get the name of the new respsonsibility which this user intends to have
822 new_resp_c refCurTyp;
823 l_new_resp_dynamic_sql   VARCHAR2(500)  :=
824     'select resp.responsibility_name '
825   ||'  from amw_constraint_entries rcd '
826   ||'      ,'||G_AMW_RESPONSIBILITY_VL||' resp '
827   ||'  where rcd.constraint_rev_id = :1 and resp.responsibility_id = :2 '
828   ||'    and rcd.function_id = resp.responsibility_id ';
829 
830 new_func_c refCurTyp;
831 l_new_func_dynamic_sql VARCHAR2(500) :=
832     'select func.user_function_name '
833   ||'  from amw_constraint_entries rcd '
834   ||'      ,'|| G_AMW_FORM_FUNCTIONS_VL ||' func '
835   ||'  where rcd.constraint_rev_id = :1  '
836   ||'    and rcd.function_id = func.function_id ';
837 
838 -- get valid user waiver
839 l_valid_user_waiver_count NUMBER;
840 CURSOR c_valid_user_waivers (l_constraint_rev_id IN NUMBER, l_user_id IN NUMBER) IS
841     SELECT count(*)
842       FROM amw_constraint_waivers_vl
843      WHERE constraint_rev_id = l_constraint_rev_id
844        AND object_type = 'USER'
845        AND PK1 = l_user_id
846        AND start_date <= sysdate AND (end_date >= sysdate or end_date is null);
847 
848  l_resp_sql VARCHAR2(32767);
849 
850 
851 -- all of roles including the existing ones and the newly assigned ones
852 l_resp_all_sql   VARCHAR2(32767)  :=
853   '  select ur.role_orig_system_id '
854   ||'  from '
855   || G_AMW_USER_ROLES||' ur '
856   ||'      ,'||G_AMW_user||' u '
857   ||'      ,amw_constraint_entries cst '
858   ||'  where  u.user_id = :1 '
859   ||'    and  cst.constraint_rev_id = :2 '
860   ||'    and u.user_name = ur.user_name '
861   ||'    and ur.role_orig_system_id = cst.function_id '
862   ||'    and ur.role_orig_system = ''FND_RESP'' '
863   ||'  UNION '
864   ||'  select cst.function_id as orig_system_id '
865   ||'  from  amw_constraint_entries cst '
866   ||'  where  cst.constraint_rev_id = :3 '
867   ||'  and cst.function_id = :4 ';
868 
869 
870 l_resp_dynamic_sql  VARCHAR2(32767) :=
871 ' select count(role_orig_system_id) from ( '
872 || l_resp_all_sql
873 ||')';
874 
875 
876 l_resp_set_all_sql   VARCHAR2(32767)  :=
877   '  select cst.group_code '
878   ||'  from '
879   || G_AMW_USER_ROLES||' ur '
880   ||'      ,'||G_AMW_user||' u '
881   ||'      ,amw_constraint_entries cst '
882   ||'  where  u.user_id = :1 '
883   ||'    and  cst.constraint_rev_id = :2 '
884   ||'    and u.user_name = ur.user_name '
885   ||'    and ur.role_orig_system_id = cst.function_id '
886   ||'    and ur.role_orig_system = ''FND_RESP'' '
887   ||'  UNION '
888   ||'  select cst.group_code '
889   ||'  from   amw_constraint_entries cst '
890   ||'  where  cst.constraint_rev_id = :3 '
891   ||'  and cst.function_id = :4 ';
892 
893   l_resp_set_dynamic_sql   VARCHAR2(32767) :=
894   ' select count(group_code) from ( '
895 || l_resp_set_all_sql
896 ||')';
897 
898 
899 BEGIN
900     IF( l_log_stmt_level >= l_curr_log_level ) THEN
901     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','User_Resp_Violation_Details Start');
902     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','p_user_id             = '|| p_user_id );
903     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','p_responsibility_id   = '|| p_responsibility_id);
904 	END IF;
905 
906   -- default to 'N', which means user doesn't have violations
907   has_violation := 'N';
908   l_violat_existing_resp := NULL;
909   l_violat_existing_role := NULL;
910   l_violat_existing_menu := NULL;
911   l_violat_new_resp := NULL;
912   l_violat_new_func := NULL;
913   l_valid_user_waiver_count := 0;
914 
915   IF (p_user_id IS NOT NULL AND p_responsibility_id IS NOT NULL) THEN
916     -- check all valid constraints
917     OPEN c_all_valid_constraints;
918     LOOP
919      FETCH c_all_valid_constraints INTO l_all_valid_constraints;
920      EXIT WHEN c_all_valid_constraints%NOTFOUND;
921 
922      -- check if this user is waived (due to User Waiver) from this constraint
923      OPEN c_valid_user_waivers(l_all_valid_constraints.constraint_rev_id, p_user_id);
924      FETCH c_valid_user_waivers INTO l_valid_user_waiver_count;
925      CLOSE c_valid_user_waivers;
926 
927 
928      -- IF l_valid_user_waiver_count <= 0 THEN
929      IF l_valid_user_waiver_count <= 0  THEN
930 
931       -- get the name of the new responsibility if combining this will results in violation against this constraint
932       OPEN new_resp_c FOR l_new_resp_dynamic_sql USING
933          l_all_valid_constraints.constraint_rev_id
934         ,p_responsibility_id;
935       FETCH new_resp_c INTO l_violat_new_resp;
936       CLOSE new_resp_c;
937 
938          -- get the name of the new function if combining this will results in violation against this constraint
939       OPEN new_func_c FOR l_new_func_dynamic_sql USING
940          l_all_valid_constraints.constraint_rev_id;
941       FETCH new_func_c BULK COLLECT INTO l_new_func_table;
942       CLOSE new_func_c;
943 
944     IF l_new_func_table IS NOT NULL AND l_new_func_table.FIRST IS NOT NULL THEN
945       l_violat_new_func := l_new_func_table(1);
946       FOR i in 2 .. l_new_func_table.COUNT
947       LOOP
948         l_violat_new_func := l_violat_new_func ||', '||l_new_func_table(i);
949       END LOOP;
950     END IF; -- end of if: l_new_func_table IS NOT NULL
951 
952       IF 'ALL' = l_all_valid_constraints.type_code THEN
953         -- find the number of constraint entries(incompatible functions) by specified constraint_rev_id
954         OPEN c_constraint_entries_count (l_all_valid_constraints.constraint_rev_id);
955         FETCH c_constraint_entries_count INTO l_constraint_entries_count;
956         CLOSE c_constraint_entries_count;
957 
958         -- find the number of distinct constraint entries this user can access
959         OPEN func_acess_count_c FOR l_func_dynamic_sql USING
960           l_all_valid_constraints.constraint_rev_id,
961           p_user_id,
962           l_all_valid_constraints.constraint_rev_id,
963           p_user_id,
964           l_all_valid_constraints.constraint_rev_id,
965           p_user_id,
966           l_all_valid_constraints.constraint_rev_id,
967           l_all_valid_constraints.constraint_rev_id,
968           p_responsibility_id;
969         FETCH func_acess_count_c INTO l_func_access_count;
970         CLOSE func_acess_count_c;
971 
972         -- in ALL type: if user can access to all entries of this constraint,
973         -- he violates this constraint
974         IF l_func_access_count = l_constraint_entries_count THEN
975           -- once he violates at least one constraint, break the loop and inform FALSE to the caller
976           FND_FILE.put_line(fnd_file.log, '------------ fail on constraint - ALL = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
977           l_violat_existing_resp := Get_Violat_Existing_Resp_List (
978                 p_user_id                   => p_user_id,
979                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
980                 p_constraint_type_code      => l_all_valid_constraints.type_code);
981           l_violat_existing_role := Get_Violat_Existing_Role_List (
982                 p_user_id                   => p_user_id,
983                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
984                 p_constraint_type_code      => l_all_valid_constraints.type_code);
985           l_violat_existing_menu := Get_Violat_Existing_Menu_List (
986                 p_user_id                   => p_user_id,
987                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
988                 p_constraint_type_code      => l_all_valid_constraints.type_code);
989 
990           -- concatinate return result(Violation Details)
991           has_violation := substrb(l_violat_new_func, 1, 4000);
992           IF l_violat_existing_resp IS NOT NULL THEN
993             IF has_violation IS NOT NULL THEN
994               has_violation := substrb((has_violation||', '), 1, 4000);
995             END IF;
996             has_violation := substrb((has_violation||l_violat_existing_resp), 1, 4000);
997           END IF;
998           IF l_violat_existing_role IS NOT NULL THEN
999             IF has_violation IS NOT NULL THEN
1000               has_violation := substrb((has_violation||', '), 1, 4000);
1001             END IF;
1002             has_violation := substrb((has_violation||l_violat_existing_role), 1, 4000);
1003           END IF;
1004           IF l_violat_existing_menu IS NOT NULL THEN
1005             IF has_violation IS NOT NULL THEN
1006               has_violation := substrb((has_violation||', '), 1, 4000);
1007             END IF;
1008             has_violation := substrb((has_violation||l_violat_existing_menu), 1, 4000);
1009           END IF;
1010 
1011 	      fnd_message.set_name('AMW', 'AMW_SOD_VIOLATION');
1012 	      fnd_message.set_token('CONSTRAINT', l_all_valid_constraints.constraint_name);
1013 	      fnd_message.set_token('CONST_DETAILS', has_violation);
1014           return substrb((FND_MESSAGE.GET), 1, 2000);
1015         END IF;
1016 
1017       ELSIF 'ME' = l_all_valid_constraints.type_code THEN
1018         -- find the number of distinct constraint entries this user can access
1019         OPEN func_acess_count_c FOR l_func_dynamic_sql USING
1020           l_all_valid_constraints.constraint_rev_id,
1021           p_user_id,
1022           l_all_valid_constraints.constraint_rev_id,
1023           p_user_id,
1024           l_all_valid_constraints.constraint_rev_id,
1025           p_user_id,
1026           l_all_valid_constraints.constraint_rev_id,
1027           l_all_valid_constraints.constraint_rev_id,
1028           p_responsibility_id;
1029         FETCH func_acess_count_c INTO l_func_access_count;
1030         CLOSE func_acess_count_c;
1031 
1032         -- in ME type: if user can access at least two entries of this constraint,
1033         -- he violates this constraint
1034         IF l_func_access_count >= 2 THEN
1035           -- once he violates at least one constraint, break the loop and inform FALSE to the caller
1036           FND_FILE.put_line(fnd_file.log,'------------ fail on constraint - ME = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
1037           l_violat_existing_resp := Get_Violat_Existing_Resp_List (
1038                 p_user_id                   => p_user_id,
1039                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1040                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1041           l_violat_existing_role := Get_Violat_Existing_Role_List (
1042                 p_user_id                   => p_user_id,
1043                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1044                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1045           l_violat_existing_menu := Get_Violat_Existing_Menu_List (
1046                 p_user_id                   => p_user_id,
1047                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1048                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1049 
1050           -- concatinate return result(Violation Details)
1051           has_violation := substrb(l_violat_new_func, 1, 4000);
1052           IF l_violat_existing_resp IS NOT NULL THEN
1053             IF has_violation IS NOT NULL THEN
1054               has_violation := substrb((has_violation||', '), 1, 4000);
1055             END IF;
1056             has_violation := substrb((has_violation||l_violat_existing_resp), 1, 4000);
1057           END IF;
1058           IF l_violat_existing_role IS NOT NULL THEN
1059             IF has_violation IS NOT NULL THEN
1060               has_violation := substrb((has_violation||', '), 1, 4000);
1061             END IF;
1062             has_violation := substrb((has_violation||l_violat_existing_role), 1, 4000);
1063           END IF;
1064           IF l_violat_existing_menu IS NOT NULL THEN
1065             IF has_violation IS NOT NULL THEN
1066               has_violation := has_violation||', ';
1067             END IF;
1068             has_violation := substrb((has_violation||l_violat_existing_menu), 1, 4000);
1069           END IF;
1070 
1071 		  fnd_message.set_name('AMW', 'AMW_SOD_VIOLATION');
1072 	      fnd_message.set_token('CONSTRAINT', l_all_valid_constraints.constraint_name);
1073 	      fnd_message.set_token('CONST_DETAILS', has_violation);
1074           return substrb((FND_MESSAGE.GET), 1, 2000);
1075         END IF;
1076 
1077       ELSIF 'SET' = l_all_valid_constraints.type_code THEN
1078         -- find the number of distinct constraint entries this user can access
1079         OPEN group_acess_count_c FOR l_func_set_dynamic_sql USING
1080           l_all_valid_constraints.constraint_rev_id,
1081           p_user_id,
1082           l_all_valid_constraints.constraint_rev_id,
1083           p_user_id,
1084           l_all_valid_constraints.constraint_rev_id,
1085           p_user_id,
1086           l_all_valid_constraints.constraint_rev_id,
1087           l_all_valid_constraints.constraint_rev_id,
1088           p_responsibility_id;
1089         FETCH group_acess_count_c INTO l_group_access_count;
1090         CLOSE group_acess_count_c;
1091 
1092         -- in SET type: if user can access at least two distinct groups(set) of this constraint,
1093         -- he violates this constraint
1094         IF l_group_access_count >= 2 THEN
1095           -- once he violates at least one constraint, break the loop and inform FALSE to the caller
1096           FND_FILE.put_line(fnd_file.log,'------------ fail on constraint - SET = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
1097           l_violat_existing_resp := Get_Violat_Existing_Resp_List (
1098                 p_user_id                   => p_user_id,
1099                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1100                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1101           l_violat_existing_role := Get_Violat_Existing_Role_List (
1102                 p_user_id                   => p_user_id,
1103                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1104                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1105           l_violat_existing_menu := Get_Violat_Existing_Menu_List (
1106                 p_user_id                   => p_user_id,
1107                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1108                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1109 
1110           -- concatinate return result(Violation Details)
1111            has_violation := substrb(l_violat_new_func, 1, 4000);
1112           IF l_violat_existing_resp IS NOT NULL THEN
1113             IF has_violation IS NOT NULL THEN
1114               has_violation := has_violation||', ';
1115             END IF;
1116             has_violation := substrb((has_violation||l_violat_existing_resp), 1, 4000);
1117           END IF;
1118           IF l_violat_existing_role IS NOT NULL THEN
1119             IF has_violation IS NOT NULL THEN
1120               has_violation := has_violation||', ';
1121             END IF;
1122             has_violation := substrb((has_violation||l_violat_existing_role), 1, 4000);
1123           END IF;
1124           IF l_violat_existing_menu IS NOT NULL THEN
1125             IF has_violation IS NOT NULL THEN
1126               has_violation := has_violation||', ';
1127             END IF;
1128             has_violation := substrb((has_violation||l_violat_existing_menu), 1, 4000);
1129           END IF;
1130 
1131 		  fnd_message.set_name('AMW', 'AMW_SOD_VIOLATION');
1132 	      fnd_message.set_token('CONSTRAINT', l_all_valid_constraints.constraint_name);
1133 	      fnd_message.set_token('CONST_DETAILS', has_violation);
1134           return substrb((FND_MESSAGE.GET), 1, 2000);
1135         END IF;
1136 
1137        ELSIF 'RESPALL' = l_all_valid_constraints.type_code THEN
1138          -- find the number of constraint entries(incompatible functions) by specified constraint_rev_id
1139         OPEN c_constraint_entries_count (l_all_valid_constraints.constraint_rev_id);
1140         FETCH c_constraint_entries_count INTO l_constraint_entries_count;
1141         CLOSE c_constraint_entries_count;
1142 
1143 
1144 
1145             OPEN resp_acess_count_c FOR l_resp_dynamic_sql USING
1146             p_user_id,
1147             l_all_valid_constraints.constraint_rev_id,
1148             l_all_valid_constraints.constraint_rev_id,
1149              p_responsibility_id;
1150             FETCH resp_acess_count_c INTO l_resp_access_count;
1151             CLOSE resp_acess_count_c;
1152 
1153             -- in ALL type: if user can access to all entries of this constraint,
1154             -- he violates this constraint
1155        IF l_resp_access_count = l_constraint_entries_count THEN
1156 
1157             -- Check to see if the fuction enteries in the constraint is same
1158             -- as the functions the user can access due to the assigning of
1159             -- this role
1160 
1161             l_resp_sql := 'select count(distinct role_orig_system_id)'
1162              ||' from ('
1163              ||  l_resp_all_sql
1164              ||' MINUS '
1165              ||' select FUNCTION_ID from amw_constraint_entries where constraint_rev_id = :5'
1166              ||')';
1167 
1168 
1169                 OPEN resp_acess_count_c FOR l_resp_sql USING
1170                 p_user_id,
1171                 l_all_valid_constraints.constraint_rev_id,
1172                 l_all_valid_constraints.constraint_rev_id,
1173                 p_responsibility_id,
1174                 l_all_valid_constraints.constraint_rev_id;
1175                 FETCH resp_acess_count_c INTO l_resp_access_count;
1176                 CLOSE resp_acess_count_c;
1177 
1178        IF l_resp_access_count = 0 THEN
1179        -- once he violates at least one constraint, break the loop and inform FALSE to the caller
1180           FND_FILE.put_line(fnd_file.log, '------------ fail on constraint - ALL = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
1181           l_violat_existing_resp := Get_Violat_Existing_Resp_List (
1182                 p_user_id                   => p_user_id,
1183                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1184                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1185           l_violat_existing_role := Get_Violat_Existing_Role_List (
1186                 p_user_id                   => p_user_id,
1187                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1188                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1189           l_violat_existing_menu := Get_Violat_Existing_Menu_List (
1190                 p_user_id                   => p_user_id,
1191                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1192                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1193 
1194           -- concatinate return result(Violation Details)
1195           has_violation := l_violat_new_resp;
1196           IF l_violat_existing_resp IS NOT NULL THEN
1197             IF has_violation IS NOT NULL THEN
1198               has_violation := has_violation||', ';
1199             END IF;
1200             has_violation := substrb((has_violation||l_violat_existing_resp), 1, 4000);
1201           END IF;
1202           IF l_violat_existing_role IS NOT NULL THEN
1203             IF has_violation IS NOT NULL THEN
1204               has_violation := has_violation||', ';
1205             END IF;
1206             has_violation := substrb((has_violation||l_violat_existing_role), 1, 4000);
1207           END IF;
1208           IF l_violat_existing_menu IS NOT NULL THEN
1209             IF has_violation IS NOT NULL THEN
1210               has_violation := has_violation||', ';
1211             END IF;
1212             has_violation := substrb((has_violation||l_violat_existing_menu), 1, 4000);
1213           END IF;
1214 
1215 		  fnd_message.set_name('AMW', 'AMW_SOD_VIOLATION');
1216 	      fnd_message.set_token('CONSTRAINT', l_all_valid_constraints.constraint_name);
1217 	      fnd_message.set_token('CONST_DETAILS', has_violation);
1218           return substrb((FND_MESSAGE.GET), 1, 2000);
1219         END IF; -- end of l_resp_access_count = 0
1220             END IF;  -- l_resp_access_count = l_constraint_entries_count
1221 
1222         ELSIF 'RESPME' = l_all_valid_constraints.type_code THEN
1223 
1224 
1225                 -- find the number of distinct constraint entries this user can access
1226                 OPEN resp_acess_count_c FOR l_resp_dynamic_sql USING
1227                 p_user_id,
1228                 l_all_valid_constraints.constraint_rev_id,
1229                 l_all_valid_constraints.constraint_rev_id,
1230                 p_responsibility_id;
1231                 FETCH resp_acess_count_c INTO l_resp_access_count;
1232                 CLOSE resp_acess_count_c;
1233 
1234                 IF( l_log_stmt_level >= l_curr_log_level ) THEN
1235     	           FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','l_resp_access_count = '|| l_resp_access_count );
1236                 END IF;
1237 
1238 
1239                 -- in ME type: if user can access at least two entries of this constraint,
1240                 -- he violates this constraint
1241           IF l_resp_access_count >= 2 THEN
1242                  -- once he violates at least one constraint, break the loop and inform FALSE to the caller
1243           FND_FILE.put_line(fnd_file.log, '------------ fail on constraint - ALL = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
1244           l_violat_existing_resp := Get_Violat_Existing_Resp_List (
1245                 p_user_id                   => p_user_id,
1246                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1247                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1248           l_violat_existing_role := Get_Violat_Existing_Role_List (
1249                 p_user_id                   => p_user_id,
1250                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1251                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1252           l_violat_existing_menu := Get_Violat_Existing_Menu_List (
1253                 p_user_id                   => p_user_id,
1254                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1255                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1256 
1257             IF( l_log_stmt_level >= l_curr_log_level ) THEN
1258                 FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','l_violat_new_resp = '|| l_violat_new_resp );
1259                 FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','l_violat_existing_resp = '|| l_violat_existing_resp );
1260                 FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','l_violat_existing_role = '|| l_violat_existing_role );
1261                 FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','l_violat_existing_menu = '|| l_violat_existing_menu );
1262             END IF;
1263 
1264           -- concatinate return result(Violation Details)
1265           has_violation := l_violat_new_resp;
1266           IF l_violat_existing_resp IS NOT NULL THEN
1267             IF has_violation IS NOT NULL THEN
1268               has_violation := has_violation||', ';
1269             END IF;
1270             has_violation := substrb((has_violation||l_violat_existing_resp), 1, 4000);
1271           END IF;
1272           IF l_violat_existing_role IS NOT NULL THEN
1273             IF has_violation IS NOT NULL THEN
1274               has_violation := has_violation||', ';
1275             END IF;
1276             has_violation := substrb((has_violation||l_violat_existing_role), 1, 4000);
1277           END IF;
1278           IF l_violat_existing_menu IS NOT NULL THEN
1279             IF has_violation IS NOT NULL THEN
1280               has_violation := has_violation||', ';
1281             END IF;
1282             has_violation := substrb((has_violation||l_violat_existing_menu), 1, 4000);
1283           END IF;
1284 
1285 		 fnd_message.set_name('AMW', 'AMW_SOD_VIOLATION');
1286 	      fnd_message.set_token('CONSTRAINT', l_all_valid_constraints.constraint_name);
1287 	      fnd_message.set_token('CONST_DETAILS', has_violation);
1288 
1289 
1290         IF( l_log_stmt_level >= l_curr_log_level ) THEN
1291             FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','User_Resp_Violation_Details End');
1292         END IF;
1293 
1294           return substrb((FND_MESSAGE.GET), 1, 2000);
1295         END IF; -- end of l_resp_access_count >= 2
1296 
1297 
1298       ELSIF 'RESPSET' = l_all_valid_constraints.type_code THEN
1299 
1300 
1301               -- find the number of distinct constraint entries this user can access
1302 
1303                 OPEN resp_acess_count_c FOR l_resp_set_dynamic_sql USING
1304                 p_user_id,
1305                 l_all_valid_constraints.constraint_rev_id,
1306                 l_all_valid_constraints.constraint_rev_id,
1307                 p_responsibility_id;
1308                 FETCH resp_acess_count_c INTO l_resp_access_count;
1309                 CLOSE resp_acess_count_c;
1310 
1311                 -- in SET type: if user can access at least two distinct groups(set) of this constraint,
1312                 -- he violates this constraint
1313           IF l_resp_access_count >= 2 THEN
1314                   -- once he violates at least one constraint, break the loop and inform FALSE to the caller
1315           FND_FILE.put_line(fnd_file.log, '------------ fail on constraint - ALL = '||l_all_valid_constraints.constraint_rev_id ||' ---------------');
1316           l_violat_existing_resp := Get_Violat_Existing_Resp_List (
1317                 p_user_id                   => p_user_id,
1318                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1319                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1320           l_violat_existing_role := Get_Violat_Existing_Role_List (
1321                 p_user_id                   => p_user_id,
1322                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1323                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1324           l_violat_existing_menu := Get_Violat_Existing_Menu_List (
1325                 p_user_id                   => p_user_id,
1326                 p_constraint_rev_id         => l_all_valid_constraints.constraint_rev_id,
1327                 p_constraint_type_code      => l_all_valid_constraints.type_code);
1328 
1329           -- concatinate return result(Violation Details)
1330           has_violation := l_violat_new_resp;
1331           IF l_violat_existing_resp IS NOT NULL THEN
1332             IF has_violation IS NOT NULL THEN
1333               has_violation := has_violation||', ';
1334             END IF;
1335             has_violation := substrb((has_violation||l_violat_existing_resp), 1, 4000);
1336           END IF;
1337           IF l_violat_existing_role IS NOT NULL THEN
1338             IF has_violation IS NOT NULL THEN
1339               has_violation := has_violation||', ';
1340             END IF;
1341             has_violation := substrb((has_violation||l_violat_existing_role), 1, 4000);
1342           END IF;
1343           IF l_violat_existing_menu IS NOT NULL THEN
1344             IF has_violation IS NOT NULL THEN
1345               has_violation := has_violation||', ';
1346             END IF;
1347             has_violation := substrb((has_violation||l_violat_existing_menu), 1, 4000);
1348           END IF;
1349 
1350 		 fnd_message.set_name('AMW', 'AMW_SOD_VIOLATION');
1351 	      fnd_message.set_token('CONSTRAINT', l_all_valid_constraints.constraint_name);
1352 	      fnd_message.set_token('CONST_DETAILS', has_violation);
1353           return substrb((FND_MESSAGE.GET), 1, 2000);
1354                 END IF; -- end of l_resp_access_count >= 2
1355       ELSE
1356         -- other constraint types
1357         NULL;
1358       END IF; -- end of if: constraint type_code
1359 
1360      END IF; --end of if: l_valid_user_waiver_count > 0
1361 
1362     END LOOP; --end of loop: c_all_valid_constraints
1363     CLOSE c_all_valid_constraints;
1364 
1365   END IF; -- end of if: p_user_id IS NOT NULL AND p_responsibility_id IS NOT NULL
1366 
1367     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1368         FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Last has_violation '|| has_violation);
1369         FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','User_Resp_Violation_Details End');
1370     END IF;
1371 
1372   return has_violation;
1373 
1374 EXCEPTION
1375     WHEN OTHERS THEN
1376     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1377     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
1378     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','User_Resp_Violation_Details End');
1379 	END IF;
1380 	RAISE;
1381 
1382 END User_Resp_Violation_Details;
1383 
1384 
1385 
1386 
1387 -- ===============================================================
1388 -- Function name
1389 --          Get_Violat_Existing_Role_List
1390 --
1391 -- Purpose
1392 --          get a flat string list of this user's existing role display name, together with those new assigned role(among p_role_names_string)
1393 --          may violate the specified constraint
1394 --
1395 -- Params
1396 --          p_user_id            := input fnd user_id
1397 --          p_constraint_rev_id  := input constraint_rev_id
1398 --          p_constraint_type_code  := input constraint type for p_constraint_rev_id
1399 --
1400 -- Return
1401 --          a string list of role display names which violates the specified constraint,
1402 --          each display name is seperated by ','
1403 --
1404 -- History
1405 -- 		  	07/27/2005    tsho     Create
1406 -- ===============================================================
1407 Function Get_Violat_Existing_Role_List (
1408     p_user_id                   IN  NUMBER,
1409     p_constraint_rev_id         IN  NUMBER,
1410     p_constraint_type_code      IN  VARCHAR2
1411 ) RETURN VARCHAR2
1412 IS
1413 L_API_NAME                  CONSTANT VARCHAR2(30) := 'Get_Violat_Existing_Role_List';
1414 L_API_VERSION_NUMBER        CONSTANT NUMBER		  := 1.0;
1415 
1416 -- store the return value
1417 l_existing_role_string VARCHAR2(32767);
1418 
1419 -- store the existing role this user has against this constraint
1420 l_existing_role_table JTF_VARCHAR2_TABLE_400;
1421 
1422 TYPE refCurTyp IS REF CURSOR;
1423 existing_role_c refCurTyp;
1424 
1425 -- find existing roles this user has (results in violating the specified constraint)
1426 l_existing_role_dynamic_sql   VARCHAR2(500)  :=
1427     'select distinct rv.display_name '
1428   ||'  from amw_role_constraint_denorm rcd '
1429   ||'      ,'||G_AMW_USER_ROLES||' ur '
1430   ||'      ,'||G_AMW_user||' u '
1431   ||'      ,'||G_AMW_ALL_ROLES_VL||' rv '
1432   ||'  where rcd.constraint_rev_id = :1 '
1433   ||'    and u.user_id = :2 '
1434   ||'    and u.user_name = ur.user_name '
1435   ||'    and ur.role_name = rcd.role_name '
1436   ||'    and ur.role_orig_system = ''UMX'' '
1437   ||'    and ur.role_name = rv.name ';
1438 
1439 BEGIN
1440     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1441     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Role_List Start');
1442 	END IF;
1443 
1444   l_existing_role_string := NULL;
1445 
1446   IF (p_user_id IS NOT NULL AND p_constraint_rev_id IS NOT NULL AND p_constraint_type_code IS NOT NULL) THEN
1447     OPEN existing_role_c FOR l_existing_role_dynamic_sql USING
1448           p_constraint_rev_id,
1449           p_user_id;
1450     FETCH existing_role_c BULK COLLECT INTO l_existing_role_table;
1451     CLOSE existing_role_c;
1452 
1453     IF l_existing_role_table IS NOT NULL AND l_existing_role_table.FIRST IS NOT NULL THEN
1454       l_existing_role_string := l_existing_role_table(1);
1455       FOR i in 2 .. l_existing_role_table.COUNT
1456       LOOP
1457         l_existing_role_string := l_existing_role_string||', '||l_existing_role_table(i);
1458       END LOOP;
1459     END IF; -- end of if: l_existing_role_table IS NOT NULL
1460 
1461   END IF; --end of if: p_user_id IS NOT NULL AND p_constraint_rev_id IS NOT NULL AND p_constraint_type_code IS NOT NULL
1462 
1463     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1464     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Role_List End');
1465 	END IF;
1466 
1467   return l_existing_role_string;
1468 
1469 EXCEPTION
1470     WHEN OTHERS THEN
1471     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1472     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
1473     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Role_List End');
1474 	END IF;
1475 	RAISE;
1476 END Get_Violat_Existing_Role_List;
1477 
1478 
1479 
1480 
1481 -- ===============================================================
1482 -- Function name
1483 --          Get_Violat_Existing_Resp_List
1484 --
1485 -- Purpose
1486 --          get a flat string list of this user's existing responsibility display name, together with those new assigned role(among p_role_names_string)
1487 --          may violate the specified constraint
1488 --
1489 -- Params
1490 --          p_user_id            := input fnd user_id
1491 --          p_constraint_rev_id  := input constraint_rev_id
1492 --          p_constraint_type_code  := input constraint type for p_constraint_rev_id
1493 --
1494 -- Return
1495 --          a string list of role display names which violates the specified constraint,
1496 --          each display name is seperated by ','
1497 --
1498 -- History
1499 -- 		  	07/27/2005    tsho     Create
1500 -- ===============================================================
1501 Function Get_Violat_Existing_Resp_List (
1502     p_user_id                   IN  NUMBER,
1503     p_constraint_rev_id         IN  NUMBER,
1504     p_constraint_type_code      IN  VARCHAR2
1505 ) RETURN VARCHAR2
1506 IS
1507 L_API_NAME                  CONSTANT VARCHAR2(30) := 'Get_Violat_Existing_Resp_List';
1508 L_API_VERSION_NUMBER        CONSTANT NUMBER		  := 1.0;
1509 
1510 -- store the return value
1511 l_existing_resp_string VARCHAR2(32767);
1512 
1513 -- store the existing responsibilities this user has against this constraint
1514 l_existing_resp_table JTF_VARCHAR2_TABLE_400;
1515 
1516 TYPE refCurTyp IS REF CURSOR;
1517 existing_resp_c refCurTyp;
1518 
1519 
1520 -- find existing responsibilities this user has (results in violating the specified constraint)
1521 l_existing_resp_dynamic_sql   VARCHAR2(2000)  :=
1522     'select distinct resp.responsibility_name '
1523   ||'  from amw_role_constraint_denorm rcd '
1524   ||'      ,'||G_AMW_USER_ROLES||' ur '
1525   ||'      ,'||G_AMW_user||' u '
1526   ||'      ,'||G_AMW_RESPONSIBILITY_VL||' resp '
1527   ||'  where rcd.constraint_rev_id = :1 '
1528   ||'    and u.user_id = :2 '
1529   ||'    and u.user_name = ur.user_name '
1530   ||'    and ur.role_orig_system_id = rcd.responsibility_id '
1531   ||'    and ur.role_orig_system = ''FND_RESP'' '
1532   ||'    and ur.role_orig_system_id = resp.responsibility_id  '
1533   ||' UNION ALL  '
1534   ||' select distinct resp.responsibility_name '
1535   ||' from amw_constraint_entries cste '
1536   ||'      ,'||G_AMW_USER_ROLES||' ur '
1537   ||'      ,'||G_AMW_user||' u '
1538   ||'      ,'||G_AMW_RESPONSIBILITY_VL||' resp '
1539   ||'  where cste.constraint_rev_id = :3 '
1540   ||'    and u.user_id = :4 '
1541   ||'    and u.user_name = ur.user_name '
1542   ||'    and ur.role_orig_system_id = cste.function_id '
1543   ||'    and ur.role_orig_system = ''FND_RESP'' '
1544   ||'    and ur.role_orig_system_id = resp.responsibility_id ';
1545 
1546 BEGIN
1547 
1548     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1549     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Resp_List Start');
1550 	END IF;
1551 
1552   l_existing_resp_string := NULL;
1553 
1554   IF (p_user_id IS NOT NULL AND p_constraint_rev_id IS NOT NULL AND p_constraint_type_code IS NOT NULL) THEN
1555     OPEN existing_resp_c FOR l_existing_resp_dynamic_sql USING
1556           p_constraint_rev_id,
1557           p_user_id,
1558           p_constraint_rev_id,
1559           p_user_id;
1560     FETCH existing_resp_c BULK COLLECT INTO l_existing_resp_table;
1561     CLOSE existing_resp_c;
1562 
1563     IF l_existing_resp_table IS NOT NULL AND l_existing_resp_table.FIRST IS NOT NULL THEN
1564       l_existing_resp_string := l_existing_resp_table(1);
1565       FOR i in 2 .. l_existing_resp_table.COUNT
1566       LOOP
1567         l_existing_resp_string := l_existing_resp_string||', '||l_existing_resp_table(i);
1568       END LOOP;
1569     END IF; -- end of if: l_existing_resp_table IS NOT NULL
1570 
1571   END IF; --end of if: p_user_id IS NOT NULL AND p_constraint_rev_id IS NOT NULL AND p_constraint_type_code IS NOT NULL
1572 
1573     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1574     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Resp_List End');
1575 	END IF;
1576 
1577   return l_existing_resp_string;
1578 EXCEPTION
1579     WHEN OTHERS THEN
1580     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1581     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
1582     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Resp_List End');
1583 	END IF;
1584 	RAISE;
1585 
1586 END Get_Violat_Existing_Resp_List;
1587 
1588 
1589 
1590 
1591 -- ===============================================================
1592 -- Function name
1593 --          Get_Violat_Existing_Menu_List
1594 --
1595 -- Purpose
1596 --          get a flat string list of this user's existing permission set(menu) display name, ]
1597 --          together with those new assigned role(among p_role_names_string)
1598 --          may violate the specified constraint
1599 --
1600 -- Params
1601 --          p_user_id            := input fnd user_id
1602 --          p_constraint_rev_id  := input constraint_rev_id
1603 --          p_constraint_type_code  := input constraint type for p_constraint_rev_id
1604 --
1605 -- Return
1606 --          a string list of role display names which violates the specified constraint,
1607 --          each display name is seperated by ','
1608 --
1609 -- History
1610 -- 		  	07/27/2005    tsho     Create
1611 -- ===============================================================
1612 Function Get_Violat_Existing_Menu_List (
1613     p_user_id                   IN  NUMBER,
1614     p_constraint_rev_id         IN  NUMBER,
1615     p_constraint_type_code      IN  VARCHAR2
1616 ) RETURN VARCHAR2
1617 IS
1618 L_API_NAME                  CONSTANT VARCHAR2(30) := 'Get_Violat_Existing_Menu_List';
1619 L_API_VERSION_NUMBER        CONSTANT NUMBER		  := 1.0;
1620 
1621 -- store the return value
1622 l_existing_menu_string VARCHAR2(32767);
1623 
1624 -- store the existing menus this user has against this constraint
1625 l_existing_menu_table JTF_VARCHAR2_TABLE_400;
1626 
1627 TYPE refCurTyp IS REF CURSOR;
1628 existing_menu_c refCurTyp;
1629 
1630 -- find existing menus this user has (results in violating the specified constraint)
1631 l_existing_menu_dynamic_sql   VARCHAR2(1500)  :=
1632     '  select menu.user_menu_name '
1633   ||'  from amw_role_constraint_denorm rcd '
1634   ||'      ,'||G_AMW_MENUS_VL||' menu '
1635   ||'      ,'||G_AMW_user||' u '
1636   ||'      ,'||G_AMW_GRANTS||' gra '
1637   ||'  where rcd.constraint_rev_id = :1 '
1638   ||'    and u.user_id = :2 '
1639   ||'    and u.user_name = gra.grantee_key '
1640   ||'    and gra.grantee_type = ''USER'' '
1641   ||'    and gra.instance_type = ''GLOBAL'' '
1642   ||'    and gra.object_id = -1 '
1643   ||'    and gra.menu_id = rcd.menu_id '
1644   ||'    and gra.menu_id = menu.menu_id '
1645   ||' UNION '
1646   ||'  select menu.user_menu_name '
1647   ||'  from amw_role_constraint_denorm rcd '
1648   ||'      ,'||G_AMW_MENUS_VL||' menu '
1649   ||'      ,'||G_AMW_GRANTS||' gra '
1650   ||'  where rcd.constraint_rev_id = :3 '
1651   ||'    and gra.grantee_key = ''GLOBAL'' '
1652   ||'    and gra.grantee_type = ''GLOBAL'' '
1653   ||'    and gra.instance_type = ''GLOBAL'' '
1654   ||'    and gra.object_id = -1 '
1655   ||'    and gra.menu_id = rcd.menu_id '
1656   ||'    and gra.menu_id = menu.menu_id ';
1657 
1658 BEGIN
1659 
1660     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1661     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Menu_List Start');
1662 	END IF;
1663 
1664   l_existing_menu_string := NULL;
1665 
1666   IF (p_user_id IS NOT NULL AND p_constraint_rev_id IS NOT NULL AND p_constraint_type_code IS NOT NULL) THEN
1667     OPEN existing_menu_c FOR l_existing_menu_dynamic_sql USING
1668           p_constraint_rev_id,
1669           p_user_id,
1670           p_constraint_rev_id;
1671     FETCH existing_menu_c BULK COLLECT INTO l_existing_menu_table;
1672     CLOSE existing_menu_c;
1673 
1674     IF l_existing_menu_table IS NOT NULL AND l_existing_menu_table.FIRST IS NOT NULL THEN
1675       l_existing_menu_string := l_existing_menu_table(1);
1676       FOR i in 2 .. l_existing_menu_table.COUNT
1677       LOOP
1678         l_existing_menu_string := l_existing_menu_string||', '||l_existing_menu_table(i);
1679       END LOOP;
1680     END IF; -- end of if: l_existing_menu_table IS NOT NULL
1681 
1682   END IF; --end of if: p_user_id IS NOT NULL AND p_constraint_rev_id IS NOT NULL AND p_constraint_type_code IS NOT NULL
1683 
1684   IF( l_log_stmt_level >= l_curr_log_level ) THEN
1685     FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Menu_List End');
1686   END IF;
1687 
1688   return l_existing_menu_string;
1689 EXCEPTION
1690     WHEN OTHERS THEN
1691     IF( l_log_stmt_level >= l_curr_log_level ) THEN
1692     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Error '||TO_CHAR(SQLCODE)||': '||SQLERRM);
1693     	FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, 'amw.plsql.PreventFormCustomization','Get_Violat_Existing_Menu_List End');
1694 	END IF;
1695 	RAISE;
1696 
1697 END Get_Violat_Existing_Menu_List;
1698 
1699 
1700 /*
1701  * cpetriuc
1702  * ---------------------
1703  * CHECK_MENU_VIOLATIONS
1704  * ---------------------
1705  * Checks if the menu provided as argument violates any SOD (Segregation of Duties)
1706  * constraints.  If a constraint is violated, the function returns an error message
1707  * containing the name of the violated constraint together with the list of functions
1708  * that define the constraint.  Otherwise, the function returns 'N'.
1709  *
1710  * psomanat : bug 5692905 : consider Responsibility waiver. Added the parameters
1711  * p_responsibility_id,p_application_id
1712  */
1713 function CHECK_MENU_VIOLATIONS(p_menu_id NUMBER,
1714                                p_responsibility_id     IN  NUMBER :=NULL,
1715                                p_application_id         IN  NUMBER :=NULL
1716 ) return VARCHAR2 is
1717 
1718 g_menu_function_id_list G_NUMBER_TABLE;
1719 
1720 
1721 cursor MENU_FUNCTIONS(p_menu_id NUMBER) is
1722 select distinct FUNCTION_ID
1723 from FND_COMPILED_MENU_FUNCTIONS
1724 where MENU_ID = p_menu_id;
1725 
1726 
1727 begin
1728 
1729 g_menu_function_id_list.delete();
1730 open MENU_FUNCTIONS(p_menu_id);
1731 fetch MENU_FUNCTIONS bulk collect into g_menu_function_id_list;
1732 close MENU_FUNCTIONS;
1733 
1734 return CHECK_FUNCTION_LIST_VIOLATIONS(g_menu_function_id_list,p_responsibility_id,p_application_id);
1735 
1736 
1737 end CHECK_MENU_VIOLATIONS;
1738 
1739 
1740 
1741 
1742 /*
1743  * cpetriuc
1744  * -------------------------
1745  * CHECK_FUNCTION_VIOLATIONS
1746  * -------------------------
1747  * Checks if any SOD (Segregation of Duties) constraints would be violated if the
1748  * argument function or submenu would be added to the menu provided as argument.  If a
1749  * constraint would be violated, the function returns an error message containing the name
1750  * of the potentially violated constraint together with the list of functions that define
1751  * the constraint.  Otherwise, the function returns 'N'.
1752  */
1753 function CHECK_FUNCTION_VIOLATIONS(p_menu_id NUMBER, p_sub_menu_id NUMBER, p_function_id NUMBER) return VARCHAR2 is
1754     l_menu_id_list G_NUMBER_TABLE;
1755 
1756 m_return_text VARCHAR2(3000);
1757 
1758     CURSOR all_menus_in_hierarchy(p_menu_id NUMBER) is
1759         SELECT sub_menu_id menu_id
1760         FROM   fnd_menu_entries
1761         START WITH menu_id =p_menu_id
1762         CONNECT BY PRIOR sub_menu_id = menu_id
1763         UNION
1764         SELECT menu_id
1765         FROM fnd_menu_entries
1766         START WITH menu_id =p_menu_id
1767         CONNECT BY PRIOR menu_id = sub_menu_id;
1768 
1769 
1770         /** dliao modified on 11/08/2006 for the bug 5610537
1771             use FND_MENU_ENTRIES i.s.o. FND_COMPILED_MENU_FUNCTION because FND_COMPILED_MENU_FUNCTION
1772             won't be populated until all of menu entries are created. Our goal is to check multiple
1773             menu entries that violating the sod before they are created in the database.
1774         ***/
1775 
1776     cursor MENU_FUNCTIONS(p_menu_id NUMBER) is
1777         select distinct FUNCTION_ID
1778         from FND_MENU_ENTRIES  --FND_COMPILED_MENU_FUNCTIONS
1779         where MENU_ID = p_menu_id;
1780 
1781     cursor MENU_AND_SUB_MENU_FUNCTIONS(p_menu_id NUMBER, p_sub_menu_id NUMBER) is
1782         select distinct FUNCTION_ID
1783         from FND_MENU_ENTRIES --FND_COMPILED_MENU_FUNCTIONS
1784         where MENU_ID = p_menu_id or MENU_ID = p_sub_menu_id;
1785 
1786     flag BOOLEAN;
1787 
1788 BEGIN
1789 
1790     g_menu_id_list.delete();
1791     g_function_id_list.delete();
1792     g_menu_function_id_list.delete();
1793 
1794     OPEN all_menus_in_hierarchy(p_menu_id);
1795     FETCH all_menus_in_hierarchy BULK COLLECT INTO l_menu_id_list;
1796     CLOSE all_menus_in_hierarchy;
1797 
1798     IF l_menu_id_list.COUNT <> 0 THEN
1799         FOR i IN 1 .. l_menu_id_list.COUNT
1800         LOOP
1801             IF NOT (g_menu_id_list.EXISTS(i)) THEN
1802                 flag:=process_menu_tree_down_for_mn(l_menu_id_list(i));
1803             END IF;
1804         END LOOP;
1805     END IF;
1806 
1807     -- ptulasi : 07/11/2007
1808     -- bug: 6208788 : Modified below code to eliminate the duplicate entry of
1809     -- pfunction id to g_menu_function_id_list
1810     IF p_function_id IS NOT NULL THEN
1811         IF NOT (g_function_id_list.EXISTS(p_function_id)) THEN
1812             g_menu_function_id_list(g_menu_function_id_list.count+1):=p_function_id;
1813         END IF;
1814     END IF;
1815 
1816     IF p_sub_menu_id IS NOT NULL THEN
1817         flag:=process_menu_tree_down_for_mn(p_sub_menu_id);
1818     END IF;
1819 
1820     m_return_text := CHECK_FUNCTION_LIST_VIOLATIONS(g_menu_function_id_list,NULL,NULL);
1821     if (m_return_text <> 'N') then
1822         return m_return_text;
1823     end if;
1824 
1825     return 'N';
1826 
1827 
1828 -- psomanat : Commenting the below code for bug 6010908
1829 
1830 /*for menu in ALL_MENUS_IN_HIERARCHY(p_menu_id) loop
1831 
1832 g_menu_function_id_list.delete();
1833 
1834 if (p_sub_menu_id is null) then
1835 open MENU_FUNCTIONS(menu.MENU_ID);
1836 fetch MENU_FUNCTIONS bulk collect into g_menu_function_id_list;
1837 close MENU_FUNCTIONS;
1838 else
1839 open MENU_AND_SUB_MENU_FUNCTIONS(menu.MENU_ID, p_sub_menu_id);
1840 fetch MENU_AND_SUB_MENU_FUNCTIONS bulk collect into g_menu_function_id_list;
1841 close MENU_AND_SUB_MENU_FUNCTIONS;
1842 m_return_text := CHECK_FUNCTION_LIST_VIOLATIONS(g_menu_function_id_list,NULL,NULL);
1843 if (m_return_text <> 'N') then return m_return_text; end if;
1844 end if;
1845 
1846 if (p_function_id is not null) then
1847 m_return_text := CHECK_ADD_FUNCTION_VIOLATIONS(g_menu_function_id_list, p_function_id);
1848 if (m_return_text <> 'N') then return m_return_text; end if;
1849 end if;
1850 
1851 end loop;
1852 
1853 return 'N'; */
1854 
1855 
1856 end CHECK_FUNCTION_VIOLATIONS;
1857 
1858 
1859 
1860 
1861 /*
1862  * cpetriuc
1863  * ------------------------------
1864  * CHECK_FUNCTION_LIST_VIOLATIONS
1865  * ------------------------------
1866  * Created initially as a helper function, to be used internally.
1867  *
1868  * Checks if the list of menu functions provided as argument violates any SOD
1869  * (Segregation of Duties) constraints.  If a constraint is violated, the function
1870  * returns an error message containing the name of the violated constraint together
1871  * with the list of functions that define the constraint.  Otherwise, the function
1872  * returns 'N'.
1873  *
1874  * psomanat : bug 5692905 : consider Responsibility waiver. Added the parameters
1875  * p_responsibility_id,p_application_id
1876  */
1877 function CHECK_FUNCTION_LIST_VIOLATIONS(g_menu_function_id_list G_NUMBER_TABLE,
1878                                p_responsibility_id     IN  NUMBER,
1879                                p_application_id         IN  NUMBER) return VARCHAR2 is
1880 
1881 g_constraint_function_id_list G_NUMBER_TABLE;
1882 g_constraint_group_code_list G_NUMBER_TABLE;
1883 g_group_code_list G_NUMBER_TABLE;
1884 m_constraint_details VARCHAR2(4000);
1885 m_counter NUMBER;
1886 m_failed BOOLEAN;
1887 m_function_name VARCHAR2(240);
1888 --fnd.message returns up to 2000 bytes of message
1889 m_return_text VARCHAR2(2000);
1890 
1891 
1892 cursor CONSTRAINTS is
1893 select *
1894 from AMW_CONSTRAINTS_VL
1895 where
1896 (TYPE_CODE = 'ALL' or TYPE_CODE = 'ME' or TYPE_CODE = 'SET') and
1897 START_DATE <= sysdate and
1898 (END_DATE is null or END_DATE >= sysdate)
1899 and objective_code = 'PR';
1900 
1901 cursor CONSTRAINT_ENTRIES(p_constraint_rev_id NUMBER) is
1902 select distinct FUNCTION_ID, GROUP_CODE
1903 from AMW_CONSTRAINT_ENTRIES
1904 where
1905 CONSTRAINT_REV_ID = p_constraint_rev_id and
1906 (OBJECT_TYPE = 'FUNC' or OBJECT_TYPE is null);
1907 
1908 cursor CONSTRAINT_GROUP_CODES(p_constraint_rev_id NUMBER) is
1909 select distinct GROUP_CODE
1910 from AMW_CONSTRAINT_ENTRIES
1911 where
1912 CONSTRAINT_REV_ID = p_constraint_rev_id and
1913 (OBJECT_TYPE = 'FUNC' or OBJECT_TYPE is null);
1914 
1915 l_valid_resp_waiver_count NUMBER;
1916 CURSOR c_valid_resp_waivers (l_constraint_rev_id IN NUMBER, l_resp_id IN NUMBER, l_appl_id IN NUMBER) IS
1917     SELECT count(*)
1918       FROM amw_constraint_waivers_vl
1919      WHERE constraint_rev_id = l_constraint_rev_id
1920        AND object_type = 'RESP'
1921        AND PK1 = l_resp_id
1922        AND PK2 = l_appl_id
1923        AND start_date <= sysdate AND (end_date >= sysdate or end_date is null);
1924 
1925 begin
1926 
1927     for constraint in CONSTRAINTS loop
1928         m_failed := FALSE;
1929         g_constraint_function_id_list.delete();
1930         g_constraint_group_code_list.delete();
1931 
1932         open CONSTRAINT_ENTRIES(constraint.CONSTRAINT_REV_ID);
1933         fetch CONSTRAINT_ENTRIES bulk collect into
1934             g_constraint_function_id_list,
1935             g_constraint_group_code_list;
1936         close CONSTRAINT_ENTRIES;
1937 
1938         for i in 1 .. g_constraint_function_id_list.COUNT loop
1939             select USER_FUNCTION_NAME into m_function_name
1940             from FND_FORM_FUNCTIONS_VL
1941             where FUNCTION_ID = g_constraint_function_id_list(i);
1942 
1943             if i = 1 then m_constraint_details := m_function_name;
1944             else m_constraint_details := substrb((m_constraint_details || ', ' || m_function_name), 1, 4000);
1945             end if;
1946 
1947         end loop;
1948 
1949         ------------------------------------
1950         -- Process a constraint of type ALL.
1951         ------------------------------------
1952 
1953         if constraint.TYPE_CODE = 'ALL' then
1954             for i in 1 .. g_constraint_function_id_list.COUNT loop
1955                 m_failed := FALSE;  -- Each constraint function must exist among the menu functions.
1956                 for j in 1 .. g_menu_function_id_list.COUNT loop
1957                     if g_constraint_function_id_list(i) = g_menu_function_id_list(j) then
1958                         m_failed := TRUE;  -- This constraint function exists among the menu functions.
1959                         exit;
1960                     end if;
1961                 end loop;
1962                 if m_failed = FALSE then
1963                     exit;  -- A constraint function has not been found among the menu functions.
1964                 end if;
1965             end loop;
1966         end if;
1967 
1968         ------------------------------------------------------
1969         -- Process a constraint of type ME (Mutual Exclusion).
1970         ------------------------------------------------------
1971 
1972         if constraint.TYPE_CODE = 'ME' then
1973             m_counter := 0;
1974             for i in 1 .. g_constraint_function_id_list.COUNT loop
1975                 for j in 1 .. g_menu_function_id_list.COUNT loop
1976                     if g_constraint_function_id_list(i) = g_menu_function_id_list(j) then
1977                         m_counter := m_counter + 1;
1978                     end if;
1979                 end loop;
1980             end loop;
1981 
1982             if m_counter >= 2 then
1983                 m_failed := TRUE;
1984             end if;
1985         end if;
1986 
1987         ------------------------------------
1988         -- Process a constraint of type SET.
1989         ------------------------------------
1990         if constraint.TYPE_CODE = 'SET' then
1991             g_group_code_list.delete();
1992 
1993             open CONSTRAINT_GROUP_CODES(constraint.CONSTRAINT_REV_ID);
1994             fetch CONSTRAINT_GROUP_CODES bulk collect into g_group_code_list;
1995             close CONSTRAINT_GROUP_CODES;
1996 
1997             m_failed := TRUE;  -- Assume the contrary.
1998 
1999             for i in 1 .. g_constraint_function_id_list.COUNT loop
2000                 for j in 1 .. g_menu_function_id_list.COUNT loop
2001                     if g_constraint_function_id_list(i) = g_menu_function_id_list(j) then
2002                         g_group_code_list(g_constraint_group_code_list(i)) := 0;
2003                     end if;
2004                 end loop;
2005             end loop;
2006 
2007             for k in 1 .. g_group_code_list.COUNT loop
2008                 if g_group_code_list(k) <> 0 then
2009                     m_failed := FALSE;  -- Not all groups have at least one function among the menu functions.
2010                     exit;
2011                 end if;
2012             end loop;
2013 
2014         end if;
2015 
2016 -- psomanat : bug 5692905 : consider Responsibility waiver when this function
2017 -- is called from CHECK_MENU_VIOLATIONS
2018 IF  p_responsibility_id IS NOT NULL AND p_application_id IS NOT NULL THEN
2019     -- check if this responsibility is waived (due to User Waiver) from this constraint
2020     OPEN c_valid_resp_waivers(constraint.CONSTRAINT_REV_ID,p_responsibility_id,p_application_id);
2021     FETCH c_valid_resp_waivers INTO l_valid_resp_waiver_count;
2022     CLOSE c_valid_resp_waivers;
2023 
2024     IF (l_valid_resp_waiver_count > 0) THEN
2025         m_failed := FALSE;
2026     END IF;
2027 END IF;
2028 
2029 -----------------------------------------------------------------------
2030 -- If this constraint has been violated, return an appropriate message.
2031 -----------------------------------------------------------------------
2032 
2033 if m_failed = TRUE then
2034 
2035     FND_MESSAGE.SET_NAME('AMW', 'AMW_SOD_VIOLATION');
2036     FND_MESSAGE.SET_TOKEN('CONSTRAINT', constraint.CONSTRAINT_NAME);
2037     FND_MESSAGE.SET_TOKEN('CONST_DETAILS', m_constraint_details);
2038     m_return_text := substrb((FND_MESSAGE.GET), 1, 2000);
2039 
2040     return m_return_text;
2041 
2042 end if;
2043 
2044 end loop;  -- CONSTRAINTS cursor loop
2045 
2046 return 'N';
2047 
2048 
2049 end CHECK_FUNCTION_LIST_VIOLATIONS;
2050 
2051 
2052 
2053 
2054 /*
2055  * cpetriuc
2056  * -----------------------------
2057  * CHECK_ADD_FUNCTION_VIOLATIONS
2058  * -----------------------------
2059  * Created initially as a helper function, to be used internally.
2060  *
2061  * Checks if adding the argument function to the list of menu functions provided as
2062  * argument violates any SOD (Segregation of Duties) constraints.  If a constraint is
2063  * violated, the function returns an error message containing the name of the violated
2064  * constraint together with the list of functions that define the constraint.  Otherwise,
2065  * the function returns 'N'.
2066  */
2067 function CHECK_ADD_FUNCTION_VIOLATIONS(g_menu_function_id_list G_NUMBER_TABLE, p_function_id NUMBER) return VARCHAR2 is
2068 
2069 g_constraint_function_id_list G_NUMBER_TABLE;
2070 g_constraint_group_code_list G_NUMBER_TABLE;
2071 g_group_code_list G_NUMBER_TABLE;
2072 m_constraint_details VARCHAR2(4000);
2073 m_failed BOOLEAN;
2074 m_function_name VARCHAR2(240);
2075 --fnd_message.get returns up to 2000 bytes of message
2076 m_return_text VARCHAR2(2000);
2077 
2078 
2079 cursor CONSTRAINTS is
2080 select *
2081 from AMW_CONSTRAINTS_VL
2082 where
2083 (TYPE_CODE = 'ALL' or TYPE_CODE = 'ME' or TYPE_CODE = 'SET') and
2084 START_DATE <= sysdate and
2085 (END_DATE is null or END_DATE >= sysdate)
2086 and objective_code = 'PR';
2087 
2088 cursor CONSTRAINT_ENTRIES(p_constraint_rev_id NUMBER) is
2089 select distinct FUNCTION_ID, GROUP_CODE
2090 from AMW_CONSTRAINT_ENTRIES
2091 where
2092 CONSTRAINT_REV_ID = p_constraint_rev_id and
2093 (OBJECT_TYPE = 'FUNC' or OBJECT_TYPE is null);
2094 
2095 cursor CONSTRAINT_GROUP_CODES(p_constraint_rev_id NUMBER) is
2096 select distinct GROUP_CODE
2097 from AMW_CONSTRAINT_ENTRIES
2098 where
2099 CONSTRAINT_REV_ID = p_constraint_rev_id and
2100 (OBJECT_TYPE = 'FUNC' or OBJECT_TYPE is null);
2101 
2102 
2103 begin
2104 
2105 for constraint in CONSTRAINTS loop
2106     m_failed := FALSE;
2107 
2108     g_constraint_function_id_list.delete();
2109     g_constraint_group_code_list.delete();
2110 
2111     open CONSTRAINT_ENTRIES(constraint.CONSTRAINT_REV_ID);
2112     fetch CONSTRAINT_ENTRIES bulk collect into
2113         g_constraint_function_id_list,
2114         g_constraint_group_code_list;
2115     close CONSTRAINT_ENTRIES;
2116 
2117     for i in 1 .. g_constraint_function_id_list.COUNT loop
2118 
2119         select USER_FUNCTION_NAME into m_function_name
2120         from FND_FORM_FUNCTIONS_VL
2121         where FUNCTION_ID = g_constraint_function_id_list(i);
2122 
2123         if i = 1 then m_constraint_details := m_function_name;
2124         else m_constraint_details := m_constraint_details || ', ' || m_function_name;
2125         end if;
2126 
2127     end loop;
2128 
2129     for i in 1 .. g_constraint_function_id_list.COUNT loop
2130         if g_constraint_function_id_list(i) = p_function_id then
2131             ------------------------------------
2132             -- Process a constraint of type ALL.
2133             ------------------------------------
2134             if constraint.TYPE_CODE = 'ALL' then
2135                 for j in 1 .. g_constraint_function_id_list.COUNT loop
2136                     m_failed := FALSE;  -- Each constraint function must exist among the menu functions.
2137                     if i <> j then
2138                         for k in 1 .. g_menu_function_id_list.COUNT loop
2139                             if g_constraint_function_id_list(j) = g_menu_function_id_list(k) then
2140                                 m_failed := TRUE;  -- This constraint function exists among the menu functions.
2141                                 exit;
2142                             end if;
2143                         end loop;
2144                     else
2145                         m_failed := TRUE;  -- If i = j, continue the loop.
2146                     end if;
2147                     if m_failed = FALSE then
2148                         exit;  -- A constraint function has not been found among the menu functions.
2149                     end if;
2150                 end loop;
2151             end if;
2152 
2153             ------------------------------------------------------
2154             -- Process a constraint of type ME (Mutual Exclusion).
2155             ------------------------------------------------------
2156             if constraint.TYPE_CODE = 'ME' then
2157                 for j in 1 .. g_constraint_function_id_list.COUNT loop
2158                     if i <> j then
2159                         for k in 1 .. g_menu_function_id_list.COUNT loop
2160                             if g_constraint_function_id_list(j) = g_menu_function_id_list(k) then
2161                                 m_failed := TRUE;
2162                                 exit;
2163                             end if;
2164                         end loop;
2165                     end if;
2166 
2167                     if m_failed = TRUE then
2168                         exit;  -- At least one mutual exclusivity has been violated.
2169                     end if;
2170                 end loop;
2171             end if;
2172 
2173             ------------------------------------
2174             -- Process a constraint of type SET.
2175             ------------------------------------
2176             if constraint.TYPE_CODE = 'SET' then
2177                 g_group_code_list.delete();
2178                 open CONSTRAINT_GROUP_CODES(constraint.CONSTRAINT_REV_ID);
2179                 fetch CONSTRAINT_GROUP_CODES bulk collect into g_group_code_list;
2180                 close CONSTRAINT_GROUP_CODES;
2181 
2182                 g_group_code_list(g_constraint_group_code_list(i)) := 0;
2183                 m_failed := TRUE;  -- Assume the contrary.
2184                 for j in 1 .. g_constraint_function_id_list.COUNT loop
2185                     if i <> j then
2186                         for k in 1 .. g_menu_function_id_list.COUNT loop
2187                             if g_constraint_function_id_list(j) = g_menu_function_id_list(k) then
2188                                 g_group_code_list(g_constraint_group_code_list(j)) := 0;
2189                             end if;
2190                         end loop;
2191                     end if;
2192                 end loop;
2193 
2194                 for l in 1 .. g_group_code_list.COUNT loop
2195                     if g_group_code_list(l) <> 0 then
2196                         m_failed := FALSE;  -- Not all groups have at least one function among the menu functions.
2197                         exit;
2198                     end if;
2199                 end loop;
2200             end if;
2201 
2202             -----------------------------------------------------------------------
2203             -- If this constraint has been violated, return an appropriate message.
2204             -----------------------------------------------------------------------
2205             if m_failed = TRUE then
2206                 FND_MESSAGE.SET_NAME('AMW', 'AMW_SOD_VIOLATION');
2207                 FND_MESSAGE.SET_TOKEN('CONSTRAINT', constraint.CONSTRAINT_NAME);
2208                 FND_MESSAGE.SET_TOKEN('CONST_DETAILS', m_constraint_details);
2209                 m_return_text := substrb((FND_MESSAGE.GET), 1, 2000);
2210                 return m_return_text;
2211             end if;
2212 
2213         end if;  -- if g_constraint_function_id_list(i) = p_function_id
2214     end loop;  -- g_constraint_function_id_list loop
2215 
2216 end loop;  -- CONSTRAINTS cursor loop
2217 
2218 return 'N';
2219 
2220 
2221 end CHECK_ADD_FUNCTION_VIOLATIONS;
2222 
2223 
2224 
2225 
2226 
2227 end AMW_VIOLATION_PUB;