1 package body FND_MENU_ENTRIES_PKG as
2 /* $Header: AFMNENTB.pls 120.3 2006/10/16 13:22:48 stadepal ship $ */
3
4 C_PKG_NAME CONSTANT VARCHAR2(30) := 'FND_FUNCTION';
5 C_LOG_HEAD CONSTANT VARCHAR2(30) := 'fnd.plsql.FND_FUNCTION.';
6
7 procedure INSERT_ROW (
8 X_ROWID in out nocopy VARCHAR2,
9 X_MENU_ID in NUMBER,
10 X_ENTRY_SEQUENCE in NUMBER,
11 X_SUB_MENU_ID in NUMBER,
12 X_FUNCTION_ID in NUMBER,
13 X_GRANT_FLAG in VARCHAR2,
14 X_PROMPT in VARCHAR2,
15 X_DESCRIPTION in VARCHAR2,
16 X_CREATION_DATE in DATE,
17 X_CREATED_BY in NUMBER,
18 X_LAST_UPDATE_DATE in DATE,
19 X_LAST_UPDATED_BY in NUMBER,
20 X_LAST_UPDATE_LOGIN in NUMBER
21 ) is
22 cursor C is select ROWID from FND_MENU_ENTRIES
23 where MENU_ID = X_MENU_ID
24 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE
25 ;
26 L_GRANT_FLAG VARCHAR2(1);
27 begin
28 /* for bug 2216556 default the grant_flag to maintain compatibility with*/
29 /* old loader data files that don't have GRANT_FLAG */
30 if (X_GRANT_FLAG is NULL) then
31 L_GRANT_FLAG := 'Y';
32 else
33 L_GRANT_FLAG := substrb(X_GRANT_FLAG,1,1);
34 end if;
35
36 insert into FND_MENU_ENTRIES (
37 MENU_ID,
38 ENTRY_SEQUENCE,
39 SUB_MENU_ID,
40 FUNCTION_ID,
41 GRANT_FLAG,
42 CREATION_DATE,
43 CREATED_BY,
44 LAST_UPDATE_DATE,
45 LAST_UPDATED_BY,
46 LAST_UPDATE_LOGIN
47 ) values (
48 X_MENU_ID,
49 X_ENTRY_SEQUENCE,
50 X_SUB_MENU_ID,
51 X_FUNCTION_ID,
52 L_GRANT_FLAG,
53 X_CREATION_DATE,
54 X_CREATED_BY,
55 X_LAST_UPDATE_DATE,
56 X_LAST_UPDATED_BY,
57 X_LAST_UPDATE_LOGIN
58 );
59
60 -- Added for Function Security Cache Invalidation Project.
61 fnd_function_security_cache.insert_menu_entry(X_MENU_ID, X_SUB_MENU_ID, X_FUNCTION_ID);
62
63 insert into FND_MENU_ENTRIES_TL (
64 MENU_ID,
65 ENTRY_SEQUENCE,
66 LAST_UPDATE_DATE,
67 LAST_UPDATED_BY,
68 LAST_UPDATE_LOGIN,
69 CREATION_DATE,
70 CREATED_BY,
71 PROMPT,
72 DESCRIPTION,
73 LANGUAGE,
74 SOURCE_LANG
75 ) select
76 X_MENU_ID,
77 X_ENTRY_SEQUENCE,
78 X_LAST_UPDATE_DATE,
79 X_LAST_UPDATED_BY,
80 X_LAST_UPDATE_LOGIN,
81 X_CREATION_DATE,
82 X_CREATED_BY,
83 decode(x_PROMPT,
84 fnd_load_util.null_value, null,
85 null, x_prompt,
86 X_PROMPT),
87 X_DESCRIPTION,
88 L.LANGUAGE_CODE,
89 userenv('LANG')
90 from FND_LANGUAGES L
91 where L.INSTALLED_FLAG in ('I', 'B')
92 and not exists
93 (select NULL
94 from FND_MENU_ENTRIES_TL T
95 where T.MENU_ID = X_MENU_ID
96 and T.ENTRY_SEQUENCE = X_ENTRY_SEQUENCE
97 and T.LANGUAGE = L.LANGUAGE_CODE);
98
99 open c;
100 fetch c into X_ROWID;
101 if (c%notfound) then
102 close c;
103 raise no_data_found;
104 end if;
105 close c;
106
107 end INSERT_ROW;
108
109 procedure LOCK_ROW (
110 X_MENU_ID in NUMBER,
111 X_ENTRY_SEQUENCE in NUMBER,
112 X_SUB_MENU_ID in NUMBER,
113 X_FUNCTION_ID in NUMBER,
114 X_GRANT_FLAG in VARCHAR2,
115 X_PROMPT in VARCHAR2,
116 X_DESCRIPTION in VARCHAR2
117 ) is
118 L_GRANT_FLAG VARCHAR2(1);
119
120 cursor c is select
121 SUB_MENU_ID,
122 FUNCTION_ID,
123 GRANT_FLAG
124 from FND_MENU_ENTRIES
125 where MENU_ID = X_MENU_ID
126 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE
127 for update of MENU_ID nowait;
128 recinfo c%rowtype;
129
130 cursor c1 is select
131 PROMPT,
132 DESCRIPTION
133 from FND_MENU_ENTRIES_TL
134 where MENU_ID = X_MENU_ID
135 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE
136 and LANGUAGE = userenv('LANG')
137 for update of MENU_ID nowait;
138 tlinfo c1%rowtype;
139
140 begin
141 /* for bug 2216556 default the grant_flag to maintain compatibility with*/
142 /* old loader data files that don't have GRANT_FLAG */
143 if (X_GRANT_FLAG is NULL) then
144 L_GRANT_FLAG := 'Y';
145 else
146 L_GRANT_FLAG := substrb(X_GRANT_FLAG,1,1);
147 end if;
148
149 open c;
150 fetch c into recinfo;
151 if (c%notfound) then
152 close c;
153 fnd_message.set_name('FND', 'FORM_RECORD_DELETED');
154 app_exception.raise_exception;
155 end if;
156 close c;
157 if ( ((recinfo.SUB_MENU_ID = X_SUB_MENU_ID)
158 OR ((recinfo.SUB_MENU_ID is null) AND (X_SUB_MENU_ID is null)))
159 AND ((recinfo.FUNCTION_ID = X_FUNCTION_ID)
160 OR ((recinfo.FUNCTION_ID is null) AND (X_FUNCTION_ID is null)))
161 AND ((recinfo.GRANT_FLAG = L_GRANT_FLAG)
162 OR ((recinfo.GRANT_FLAG is null) AND (L_GRANT_FLAG is null)))
163 ) then
164 null;
165 else
166 fnd_message.set_name('FND', 'FORM_RECORD_CHANGED');
167 app_exception.raise_exception;
168 end if;
169
170 open c1;
171 fetch c1 into tlinfo;
172 if (c1%notfound) then
173 close c1;
174 return;
175 end if;
176 close c1;
177
178 if ( ((tlinfo.PROMPT = X_PROMPT)
179 OR ((tlinfo.PROMPT is null) AND (X_PROMPT is null)))
180 AND ((tlinfo.DESCRIPTION = X_DESCRIPTION)
181 OR ((tlinfo.DESCRIPTION is null) AND (X_DESCRIPTION is null)))
182 ) then
183 null;
184 else
185 fnd_message.set_name('FND', 'FORM_RECORD_CHANGED');
186 app_exception.raise_exception;
187 end if;
188 return;
189 end LOCK_ROW;
190
191 procedure UPDATE_ROW (
192 X_MENU_ID in NUMBER,
193 X_ENTRY_SEQUENCE in NUMBER,
194 X_SUB_MENU_ID in NUMBER,
195 X_FUNCTION_ID in NUMBER,
196 X_GRANT_FLAG in VARCHAR2,
197 X_PROMPT in VARCHAR2,
198 X_DESCRIPTION in VARCHAR2,
199 X_LAST_UPDATE_DATE in DATE,
200 X_LAST_UPDATED_BY in NUMBER,
201 X_LAST_UPDATE_LOGIN in NUMBER
202 ) is
203 L_GRANT_FLAG VARCHAR2(1);
204 L_SUB_MENU_ID NUMBER;
205 L_FUNCTION_ID NUMBER;
206 begin
207 /* for bug 2216556 default the grant_flag to maintain compatibility with*/
208 /* old loader data files that don't have GRANT_FLAG */
209 if (X_GRANT_FLAG is NULL) then
210 L_GRANT_FLAG := 'Y';
211 else
212 L_GRANT_FLAG := substrb(X_GRANT_FLAG,1,1);
213 end if;
214
215 -- Added for Function Security Cache Invalidation Project
216 begin
217 -- Acquire sub_menu_id using menu_id and entry_sequence.
218 select sub_menu_id into L_SUB_MENU_ID
219 from fnd_menu_entries
220 where menu_id = X_MENU_ID
221 and entry_sequence = X_ENTRY_SEQUENCE;
222
223 exception
224 when no_data_found then
225 L_SUB_MENU_ID := null;
226 return;
227 end;
228
229 -- Added for Function Security Cache Invalidation Project
230 begin
231 -- Acquire function_id using menu_id and entry_sequence.
232 select function_id into L_FUNCTION_ID
233 from fnd_menu_entries
234 where menu_id = X_MENU_ID
235 and entry_sequence = X_ENTRY_SEQUENCE;
236
237 exception
238 when no_data_found then
239 L_FUNCTION_ID := null;
240 return;
241 end;
242
243 update FND_MENU_ENTRIES set
244 SUB_MENU_ID = X_SUB_MENU_ID,
245 FUNCTION_ID = X_FUNCTION_ID,
246 GRANT_FLAG = L_GRANT_FLAG,
247 LAST_UPDATE_DATE = X_LAST_UPDATE_DATE,
248 LAST_UPDATED_BY = X_LAST_UPDATED_BY,
249 LAST_UPDATE_LOGIN = X_LAST_UPDATE_LOGIN
250 where MENU_ID = X_MENU_ID
251 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE;
252
253 if (sql%notfound) then
254 raise no_data_found;
255 else
256 -- This means that a menu entry was updated.
257 -- Added for Function Security Cache Invalidation Project
258 fnd_function_security_cache.update_menu_entry(X_MENU_ID, L_SUB_MENU_ID, L_FUNCTION_ID);
259 fnd_function_security_cache.update_menu_entry(X_MENU_ID, X_SUB_MENU_ID, X_FUNCTION_ID);
260 end if;
261
262 update FND_MENU_ENTRIES_TL
263 set prompt = X_PROMPT,
264 DESCRIPTION = X_DESCRIPTION,
265 LAST_UPDATE_DATE = X_LAST_UPDATE_DATE,
266 LAST_UPDATED_BY = X_LAST_UPDATED_BY,
267 LAST_UPDATE_LOGIN = X_LAST_UPDATE_LOGIN,
268 SOURCE_LANG = userenv('LANG')
269 where MENU_ID = X_MENU_ID
270 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE
271 and userenv('LANG') in (LANGUAGE, SOURCE_LANG);
272
273 if (sql%notfound) then
274 raise no_data_found;
275 end if;
276 end UPDATE_ROW;
277
278 procedure BUMP_ROW(
279 X_USER_ID in NUMBER,
280 X_SHIFT_VALUE in NUMBER,
281 X_ENTRY_SEQUENCE in NUMBER,
282 X_MENU_ID in NUMBER
283 )is
284
285 l_sub_menu_id number;
286 l_function_id number;
287
288 begin
289 -- Bump tl table
290 -- Bug 5579233. Commented WHO col's update during bumping.
291 -- This is becoz of the changes in fnd_load_util.upload_test() api in R12
292 -- which is now considering only LUD but not LUB to return TRUE/FALSE.
293 -- Complete details can be found in bug#5579233
294 update fnd_menu_entries_tl
295 set entry_sequence = entry_sequence + X_SHIFT_VALUE
296 --last_update_date = sysdate,
297 --last_updated_by = 1,
298 --last_update_login = 0
299 where menu_id = X_MENU_ID
300 and entry_sequence = X_ENTRY_SEQUENCE;
301
302 begin
303 -- Added for Function Security Cache Invalidation Project
304 -- Acquire sub_menu_id using menu_id and entry_sequence.
305 select sub_menu_id into l_sub_menu_id
306 from fnd_menu_entries
307 where menu_id = X_MENU_ID
308 and entry_sequence = X_ENTRY_SEQUENCE;
309
310 exception
311 when no_data_found then
312 l_sub_menu_id := null;
313 return;
314 end;
315
316 begin
317 -- Added for Function Security Cache Invalidation Project
318 -- Acquire function_id using menu_id and entry_sequence.
319 select function_id into l_function_id
320 from fnd_menu_entries
321 where menu_id = X_MENU_ID
322 and entry_sequence = X_ENTRY_SEQUENCE;
323
324 exception
325 when no_data_found then
326 l_function_id := null;
327 return;
328 end;
329
330 -- Bump base table
331 -- Bug 5579233. Commented WHO col's update during bumping.
332 -- This is becoz of the changes in fnd_load_util.upload_test() api in R12
333 -- which is now considering only LUD but not LUB to return TRUE/FALSE.
334 -- Complete details can be found in bug#5579233
335 update fnd_menu_entries
336 set entry_sequence = entry_sequence + X_SHIFT_VALUE
337 --last_update_date = sysdate,
338 --last_updated_by = 1,
339 --last_update_login = 0
340 where menu_id = X_MENU_ID
341 and entry_sequence = X_ENTRY_SEQUENCE;
342
343 fnd_function_security_cache.update_menu_entry(X_MENU_ID, l_sub_menu_id, l_function_id);
344
345 end BUMP_ROW;
346
347 /* Overloaded version below */
348 procedure LOAD_ROW (
349 X_MODE in VARCHAR2,
350 X_ENT_SEQUENCE VARCHAR2,
351 X_MENU_NAME in VARCHAR2,
352 X_SUB_MENU_NAME in VARCHAR2,
353 X_FUNCTION_NAME in VARCHAR2,
354 X_GRANT_FLAG in VARCHAR2,
355 X_PROMPT in VARCHAR2,
356 X_DESCRIPTION in VARCHAR2,
357 X_OWNER in VARCHAR2
358 ) is
359 begin
360 fnd_menu_entries_pkg.LOAD_ROW (
361 X_MODE => X_MODE,
362 X_ENT_SEQUENCE => X_ENT_SEQUENCE,
363 X_MENU_NAME => X_MENU_NAME,
364 X_SUB_MENU_NAME => X_SUB_MENU_NAME,
365 X_FUNCTION_NAME => X_FUNCTION_NAME,
366 X_GRANT_FLAG => X_GRANT_FLAG,
367 X_PROMPT => X_PROMPT,
368 X_DESCRIPTION => X_DESCRIPTION,
369 X_OWNER => X_OWNER,
370 X_CUSTOM_MODE => null,
371 X_LAST_UPDATE_DATE => null
372 );
373 end LOAD_ROW;
374
375 /* Overloaded version above */
376 procedure LOAD_ROW (
377 X_MODE in VARCHAR2,
378 X_ENT_SEQUENCE VARCHAR2,
379 X_MENU_NAME in VARCHAR2,
380 X_SUB_MENU_NAME in VARCHAR2,
381 X_FUNCTION_NAME in VARCHAR2,
382 X_GRANT_FLAG in VARCHAR2,
383 X_PROMPT in VARCHAR2,
384 X_DESCRIPTION in VARCHAR2,
385 X_OWNER in VARCHAR2,
386 X_CUSTOM_MODE in VARCHAR2,
387 X_LAST_UPDATE_DATE in VARCHAR2
388 ) is
389 row_id varchar2(64);
390 sub_mnu_id number;
391 mnu_id number;
392 fun_id number;
393 eseq number;
394 eseqmatch varchar2(1);
395 shiftseq number;
396 X_ENTRY_SEQUENCE number;
397 v_mode varchar2(20);
398 f_luby number; -- entity owner in file
399 f_ludate date; -- entity update date in file
400 db_luby number; -- entity owner in db
401 db_ludate date; -- entity update date in db
402 L_GRANT_FLAG VARCHAR2(1);
403 l_sub_menu_name varchar2(4000); -- bug2438503
404 l_function_name varchar2(4000); -- bug2438503
405 l_sub_menu_id number; -- Function Security Cache Invalidation
406 l_function_id number; -- Function Security Cache Invalidation
407
408 CURSOR c_mnu_entry IS
409 SELECT sub_menu_id, function_id
410 FROM fnd_menu_entries E1
411 WHERE E1.MENU_ID = mnu_id
412 and exists (select NULL
413 from FND_MENU_ENTRIES E2
414 where E1.MENU_ID = E2.MENU_ID
415 and NVL(E1.SUB_MENU_ID, -1) = NVL(E2.SUB_MENU_ID, -1)
416 and NVL(E1.FUNCTION_ID, -1) = NVL(E2.FUNCTION_ID, -1)
417 and E1.ENTRY_SEQUENCE > E2.ENTRY_SEQUENCE);
418
419 begin
420 /* for bug 2216556 default the grant_flag to maintain compatibility with*/
421 /* old loader data files that don't have GRANT_FLAG */
422 if (X_GRANT_FLAG is NULL) then
423 L_GRANT_FLAG := 'Y';
424 else
425 L_GRANT_FLAG := substrb(X_GRANT_FLAG,1,1);
426 end if;
427
428 if (X_MODE = 'REPLACE' and X_CUSTOM_MODE = 'FORCE') then
429 v_mode := 'REPLACE_OVERWRITE';
430 elsif (X_MODE = 'MERGE' and X_CUSTOM_MODE = 'FORCE') then
431 v_mode := 'MERGE_OVERWRITE';
432 elsif (X_MODE = 'MERGE' and X_CUSTOM_MODE <> 'FORCE') then
433 v_mode := 'MERGE_NOOVERWRITE';
434 else
435 v_mode := 'MERGE_NOOVERWRITE';
436 end if;
437
438 X_ENTRY_SEQUENCE := to_number(X_ENT_SEQUENCE);
439
440 select decode(X_SUB_MENU_NAME,
441 fnd_load_util.null_value, null,
442 null, X_SUB_MENU_NAME,
443 X_SUB_MENU_NAME) into l_sub_menu_name from dual;
444
445 sub_mnu_id := NULL;
446
447 if (l_sub_menu_name is not null) then
448 begin
449 select menu_id into sub_mnu_id
450 from fnd_menus
451 where menu_name = X_SUB_MENU_NAME;
452 exception
453 when no_data_found then
454 /* The sub menu doesn't yet exist so create a dummy menu*/
455 /* to serve as a temporary placeholder. This solves bug */
456 /* 2225482 about uploading menus whose children hadn't */
457 /* yet been uploaded. This dummy menu will end up getting */
458 /* updated with the real menu information later on during */
459 /* the load when the real menu data gets uploaded. */
460 fnd_menus_pkg.LOAD_ROW(
461 x_menu_name => X_SUB_MENU_NAME,
462 x_menu_type => NULL,
463 x_user_menu_name => X_SUB_MENU_NAME,
464 x_description => NULL,
465 x_owner => X_OWNER,
466 x_custom_mode => X_CUSTOM_MODE,
467 x_last_update_date => X_LAST_UPDATE_DATE);
468 begin
469 select menu_id into sub_mnu_id
470 from fnd_menus
471 where menu_name = X_SUB_MENU_NAME;
472 exception /* This should never happen since we have already loaded*/
473 when no_data_found then
474 fnd_message.set_name('FND', 'SQL_NO_DATA_FOUND');
475 fnd_message.set_token('TABLE', 'FND_MENUS');
476 fnd_message.set_token('COLUMN', 'MENU_NAME');
477 fnd_message.set_token('VALUE', x_sub_menu_name);
478 app_exception.raise_exception;
479 return;
480 end;
481 end;
482 else
483 sub_mnu_id := null;
484 end if;
485
486 select decode(X_FUNCTION_NAME,
487 fnd_load_util.null_value, null,
488 null, X_FUNCTION_NAME,
489 X_FUNCTION_NAME) into l_function_name from dual;
490
491 fun_id := NULL;
492 if (l_function_name is not null) then
493 begin
494 select function_id into fun_id
495 from fnd_form_functions
496 where function_name = X_FUNCTION_NAME;
497 exception
498 when no_data_found then
499 fnd_message.set_name('FND', 'SQL_NO_DATA_FOUND');
500 fnd_message.set_token('TABLE', 'FND_FORM_FUNCTIONS');
501 fnd_message.set_token('COLUMN', 'FUNCTION_NAME');
502 fnd_message.set_token('VALUE', x_function_name);
503 app_exception.raise_exception;
504 return;
505 end;
506 else fun_id := null;
507 end if;
508
509 mnu_id := NULL;
510 begin
511 -- FOR UPDATE is added, to make the upload of entries for the same menu
512 -- from diff ldt files sequential. This is for bug 3657426.
513 select menu_id into mnu_id
514 from fnd_menus
515 where menu_name = X_MENU_NAME
516 for update;
517 exception
518 when no_data_found then
519 fnd_message.set_name('FND', 'SQL_NO_DATA_FOUND');
520 fnd_message.set_token('TABLE', 'FND_MENUS');
521 fnd_message.set_token('COLUMN', 'MENU_NAME');
522 fnd_message.set_token('VALUE', x_menu_name);
523 app_exception.raise_exception;
524 return;
525 end;
526
527 -- Translate owner to file_last_updated_by
528 f_luby := fnd_load_util.owner_id(x_owner);
529
530 -- Translate char last_update_date to date
531 f_ludate := nvl(to_date(x_last_update_date, 'YYYY/MM/DD'), sysdate);
532
533 -- Caculate max sequence for bumping purpose
534 select nvl(max(entry_sequence), 0) + 1
535 into shiftseq
536 from fnd_menu_entries
537 where menu_id = mnu_id;
538
539 -- Delete orphaned rows from the TL table so they don't cause conflicts.
540 -- There shouldn't ever be any, but sometimes the best laid plans...
541 delete from fnd_menu_entries_tl
542 where menu_id = mnu_id
543 and entry_sequence >= shiftseq;
544
545 if (v_mode = 'REPLACE_OVERWRITE') then
546 -- All entries had been pre-deleted in the menu level.
547 -- So, all we have to do is insert.
548 fnd_menu_entries_pkg.bump_row(f_luby, shiftseq, X_ENTRY_SEQUENCE, mnu_id);
549
550 fnd_menu_entries_pkg.insert_row(
551 X_ROWID => row_id,
552 X_MENU_ID => mnu_id,
553 X_ENTRY_SEQUENCE => X_ENTRY_SEQUENCE,
554 X_SUB_MENU_ID => sub_mnu_id,
555 X_FUNCTION_ID => fun_id,
556 X_GRANT_FLAG => L_GRANT_FLAG,
557 X_PROMPT => X_PROMPT,
558 X_DESCRIPTION => X_DESCRIPTION,
559 X_CREATION_DATE => f_ludate,
560 X_CREATED_BY => f_luby,
561 X_LAST_UPDATE_DATE => f_ludate,
562 X_LAST_UPDATED_BY => f_luby,
563 X_LAST_UPDATE_LOGIN => 0);
564
565 return;
566 end if;
567
568 -- Predelete any duplicate entries on this menu to avoid any
569 -- problems later. Theoretically duplicates are not allowed, this
570 -- is to fix problems with existing bad data in databases.
571 delete from FND_MENU_ENTRIES_TL T
572 where T.MENU_ID = mnu_id
573 and exists (select NULL
574 from FND_MENU_ENTRIES E1, FND_MENU_ENTRIES E2
575 where T.MENU_ID = E1.MENU_ID
576 and T.ENTRY_SEQUENCE = E1.ENTRY_SEQUENCE
577 and E1.MENU_ID = E2.MENU_ID
578 and NVL(E1.SUB_MENU_ID, -1) = NVL(E2.SUB_MENU_ID, -1)
579 and NVL(E1.FUNCTION_ID, -1) = NVL(E2.FUNCTION_ID, -1)
580 and E1.ENTRY_SEQUENCE > E2.ENTRY_SEQUENCE);
581
582 -- Since this delete statement may affect more than 1 record, a cursor has been created to
583 -- determine the records for deletion.
584 delete from FND_MENU_ENTRIES E1
585 where E1.MENU_ID = mnu_id
586 and exists (select NULL
587 from FND_MENU_ENTRIES E2
588 where E1.MENU_ID = E2.MENU_ID
589 and NVL(E1.SUB_MENU_ID, -1) = NVL(E2.SUB_MENU_ID, -1)
590 and NVL(E1.FUNCTION_ID, -1) = NVL(E2.FUNCTION_ID, -1)
591 and E1.ENTRY_SEQUENCE > E2.ENTRY_SEQUENCE);
592
593 -- Added for Function Security Cache Invalidation Project.
594 -- Seems that I need make sure that each menu entry deleted is taken into account.
595 -- This loop uses the cursor c_mnu_entry defined.
596 for mentry in c_mnu_entry loop
597 fnd_function_security_cache.delete_menu_entry(mnu_id,
598 mentry.sub_menu_id, mentry.function_id);
599 end loop;
600
601 begin
602 -- Select this entry
603 select decode(e.entry_sequence, X_ENTRY_SEQUENCE, 'Y', 'N') seqmatch,
604 e.entry_sequence, e.last_updated_by, e.last_update_date
605 into eseqmatch, eseq, db_luby, db_ludate
606 from fnd_menu_entries e, fnd_menu_entries_tl t
607 where e.menu_id = mnu_id
608 and nvl(e.sub_menu_id, -1) = nvl(sub_mnu_id, -1)
609 and nvl(e.function_id, -1) = nvl(fun_id, -1)
610 and e.menu_id = t.menu_id
611 and e.entry_sequence = t.entry_sequence
612 and userenv('LANG') = t.language;
613
614
615 if ((v_mode = 'MERGE_OVERWRITE') or
616 (fnd_load_util.upload_test(f_luby, f_ludate, db_luby,
617 db_ludate, X_CUSTOM_MODE))) then
618
619 if (eseqmatch = 'N') then
620 -- If row is found, but position mismatches,
621 -- or if row is not found, then we are either going to
622 -- update a row to a position which might conflict,
623 -- or we are going to create a row with a possible
624 -- position conflict. To avoid this, any existing
625 -- rows with the same sequence value must be moved
626
627 fnd_menu_entries_pkg.bump_row(f_luby,shiftseq,X_ENTRY_SEQUENCE,mnu_id);
628
629 -- Update sequence in tl
630 update fnd_menu_entries_tl
631 set entry_sequence = X_ENTRY_SEQUENCE,
632 last_update_date = f_ludate,
633 last_updated_by = f_luby,
634 last_update_login = 0
635 where menu_id = mnu_id
636 and entry_sequence = eseq;
637
638 -- Added for Function Security Cache Invalidation Project
639 begin
640 -- Acquire sub_menu_id using menu_id and entry_sequence.
641 select sub_menu_id into l_sub_menu_id
642 from fnd_menu_entries
643 where menu_id = mnu_id
644 and entry_sequence = eseq;
645
646 exception
647 when no_data_found then
648 l_sub_menu_id := null;
649 return;
650 end;
651
652 -- Added for Function Security Cache Invalidation Project
653 begin
654 -- Acquire function_id using menu_id and entry_sequence.
655 select function_id into l_function_id
656 from fnd_menu_entries
657 where menu_id = mnu_id
658 and entry_sequence = eseq;
659
660 exception
661 when no_data_found then
662 l_function_id := null;
663 return;
664 end;
665
666 -- Update sequence in base
667 update fnd_menu_entries
668 set entry_sequence = X_ENTRY_SEQUENCE,
669 last_update_date = f_ludate,
670 last_updated_by = f_luby,
671 last_update_login = 0
672 where menu_id = mnu_id
673 and entry_sequence = eseq;
674
675 fnd_function_security_cache.update_menu_entry(mnu_id, l_sub_menu_id, l_function_id);
676
677 end if;
678
679 -- entry found. and sequence has been taken care of if different.
680 -- Check other columns.
681
682
683 -- Added for Function Security Cache Invalidation Project
684 begin
685 -- Acquire sub_menu_id using menu_id and entry_sequence.
686 select sub_menu_id into l_sub_menu_id
687 from fnd_menu_entries
688 where menu_id = mnu_id
689 and entry_sequence = X_ENTRY_SEQUENCE;
690
691 exception
692 when no_data_found then
693 l_sub_menu_id := null;
694 return;
695 end;
696
697 -- Added for Function Security Cache Invalidation Project
698 begin
699 -- Acquire function_id using menu_id and entry_sequence.
700 select function_id into l_function_id
701 from fnd_menu_entries
702 where menu_id = mnu_id
703 and entry_sequence = X_ENTRY_SEQUENCE;
704
705 exception
706 when no_data_found then
707 l_function_id := null;
708 return;
709 end;
710
711 /* Bug 3227451 - Removed grant flag change check.
712 The last_update_date of the base table needs to be updated
713 when the upload test passes even if the base table grant flag
714 is not updated */
715
716 update fnd_menu_entries
717 set grant_flag = L_GRANT_FLAG,
718 last_update_date = f_ludate,
719 last_update_login = 0,
720 last_updated_by = f_luby
721 where entry_sequence = X_ENTRY_SEQUENCE
722 and menu_id = mnu_id;
723
724 fnd_function_security_cache.update_menu_entry(mnu_id, l_sub_menu_id, l_function_id);
725
726 -- Bug2410699 - Modified condition to ensure that
727 -- an update occurs when the PROMPT or DESCRIPTION
728 -- from the database has a NULL value. Also no
729 -- update occurs if the PROMPT or DESCRIPTION in the
730 -- data file has NULL value. Update will occur when
731 -- the LDT file has the *NULL* constant defined.
732
733 /* Bug 3227451 - Removed prompt and description change check.
734 The last_update_date of the tl table needs to be updated
735 when the upload test passes even if neither prompt nor
736 description have changed. */
737 update fnd_menu_entries_tl
738 set prompt = decode(X_PROMPT,
739 fnd_load_util.null_value, null,
740 null, prompt,
741 X_PROMPT),
742 description = X_DESCRIPTION,
743 last_update_date = f_ludate,
744 last_update_login = 0,
745 last_updated_by = f_luby
746 where entry_sequence = X_ENTRY_SEQUENCE
747 and menu_id = mnu_id
748 and userenv('LANG') in (LANGUAGE, SOURCE_LANG);
749
750 /* Bug 3227451 - Removed update to base table version info.
751 This is no longer needed since we are now updating both base and
752 tl tables if either one is updated. */
753 end if;
754 exception
755 when no_data_found then
756 -- Both MERGE_OVERWRITE and MERGE_NO_OVERWRITE mode
757 -- create new one in base and tl
758 fnd_menu_entries_pkg.bump_row(f_luby,shiftseq, X_ENTRY_SEQUENCE, mnu_id);
759
760 fnd_menu_entries_pkg.insert_row(
761 X_ROWID => row_id,
762 X_MENU_ID => mnu_id,
763 X_ENTRY_SEQUENCE => X_ENTRY_SEQUENCE,
764 X_SUB_MENU_ID => sub_mnu_id,
765 X_FUNCTION_ID => fun_id,
766 X_GRANT_FLAG => L_GRANT_FLAG,
767 X_PROMPT => X_PROMPT,
768 X_DESCRIPTION => X_DESCRIPTION,
769 X_CREATION_DATE => f_ludate,
770 X_CREATED_BY => f_luby,
771 X_LAST_UPDATE_DATE => f_ludate,
772 X_LAST_UPDATED_BY => f_luby,
773 X_LAST_UPDATE_LOGIN => 0);
774 end;
775 -- Delete unreferenced entries, i.e. any entries which
776 -- are greater than the linear count or which have fractional values.
777 -- Do NOT delete unreferenced entries if running in insert-only mode.
778 if (v_mode <> 'INSERT') then
779 -- delete them
780 null;
781 end if;
782
783 end LOAD_ROW;
784
785
786 procedure DELETE_ROW (
787 X_MENU_ID in NUMBER,
788 X_ENTRY_SEQUENCE in NUMBER
789 ) is
790
791 l_sub_menu_id number;
792 l_function_id number;
793
794 begin
795
796 -- Added for Function Security Cache Invalidation Project
797 begin
798 -- Acquire sub_menu_id using menu_id and entry_sequence.
799 select sub_menu_id into l_sub_menu_id
800 from fnd_menu_entries
801 where menu_id = X_MENU_ID
802 and entry_sequence = X_ENTRY_SEQUENCE;
803
804 exception
805 when no_data_found then
806 l_sub_menu_id := null;
807 return;
808 end;
809
810 -- Added for Function Security Cache Invalidation Project
811 begin
812 -- Acquire function_id using menu_id and entry_sequence.
813 select function_id into l_function_id
814 from fnd_menu_entries
815 where menu_id = X_MENU_ID
816 and entry_sequence = X_ENTRY_SEQUENCE;
817
818 exception
819 when no_data_found then
820 l_function_id := null;
821 return;
822 end;
823
824 delete from FND_MENU_ENTRIES
825 where MENU_ID = X_MENU_ID
826 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE;
827
828 if (sql%notfound) then
829 raise no_data_found;
830 else
831 -- This means that the menu entry was updated.
832 -- Added for Function Security Cache Invalidation Project
833 -- Acquire sub_menu_id and function_id using menu_id and entry_sequence
834
835 fnd_function_security_cache.delete_menu_entry(X_MENU_ID, l_sub_menu_id, l_function_id);
836 end if;
837
838 delete from FND_MENU_ENTRIES_TL
839 where MENU_ID = X_MENU_ID
840 and ENTRY_SEQUENCE = X_ENTRY_SEQUENCE;
841
842 if (sql%notfound) then
843 raise no_data_found;
844 end if;
845 end DELETE_ROW;
846
847 procedure ADD_LANGUAGE
848 is
849 begin
850 /* Mar/19/03 requested by Ric Ginsberg */
851 /* The following delete and update statements are commented out */
852 /* as a quick workaround to fix the time-consuming table handler issue */
853 /* Eventually we'll need to turn them into a separate fix_language procedure */
854 /*
855
856 delete from FND_MENU_ENTRIES_TL T
857 where not exists
858 (select NULL
859 from FND_MENU_ENTRIES B
860 where B.MENU_ID = T.MENU_ID
861 and B.ENTRY_SEQUENCE = T.ENTRY_SEQUENCE
862 );
863
864 update FND_MENU_ENTRIES_TL T set (
865 PROMPT,
866 DESCRIPTION
867 ) = (select
868 B.PROMPT,
869 B.DESCRIPTION
870 from FND_MENU_ENTRIES_TL B
871 where B.MENU_ID = T.MENU_ID
872 and B.ENTRY_SEQUENCE = T.ENTRY_SEQUENCE
873 and B.LANGUAGE = T.SOURCE_LANG)
874 where (
875 T.MENU_ID,
876 T.ENTRY_SEQUENCE,
877 T.LANGUAGE
878 ) in (select
879 SUBT.MENU_ID,
880 SUBT.ENTRY_SEQUENCE,
881 SUBT.LANGUAGE
882 from FND_MENU_ENTRIES_TL SUBB, FND_MENU_ENTRIES_TL SUBT
883 where SUBB.MENU_ID = SUBT.MENU_ID
884 and SUBB.ENTRY_SEQUENCE = SUBT.ENTRY_SEQUENCE
885 and SUBB.LANGUAGE = SUBT.SOURCE_LANG
886 and (SUBB.PROMPT <> SUBT.PROMPT
887 or (SUBB.PROMPT is null and SUBT.PROMPT is not null)
888 or (SUBB.PROMPT is not null and SUBT.PROMPT is null)
889 or SUBB.DESCRIPTION <> SUBT.DESCRIPTION
890 or (SUBB.DESCRIPTION is null and SUBT.DESCRIPTION is not null)
891 or (SUBB.DESCRIPTION is not null and SUBT.DESCRIPTION is null)
892 ));
893 */
894
895 insert into FND_MENU_ENTRIES_TL (
896 MENU_ID,
897 ENTRY_SEQUENCE,
898 LAST_UPDATE_DATE,
899 LAST_UPDATED_BY,
900 LAST_UPDATE_LOGIN,
901 CREATION_DATE,
902 CREATED_BY,
903 PROMPT,
904 DESCRIPTION,
905 LANGUAGE,
906 SOURCE_LANG
907 ) select
908 B.MENU_ID,
909 B.ENTRY_SEQUENCE,
910 B.LAST_UPDATE_DATE,
911 B.LAST_UPDATED_BY,
912 B.LAST_UPDATE_LOGIN,
913 B.CREATION_DATE,
914 B.CREATED_BY,
915 B.PROMPT,
916 B.DESCRIPTION,
917 L.LANGUAGE_CODE,
918 B.SOURCE_LANG
919 from FND_MENU_ENTRIES_TL B, FND_LANGUAGES L
920 where L.INSTALLED_FLAG in ('I', 'B')
921 and B.LANGUAGE = userenv('LANG')
922 and not exists
923 (select NULL
924 from FND_MENU_ENTRIES_TL T
925 where T.MENU_ID = B.MENU_ID
926 and T.ENTRY_SEQUENCE = B.ENTRY_SEQUENCE
927 and T.LANGUAGE = L.LANGUAGE_CODE);
928 end ADD_LANGUAGE;
929
930 /* Overloaded version below */
931 procedure TRANSLATE_ROW (
932 X_MENU_ID in NUMBER,
933 X_SUB_MENU_ID in NUMBER,
934 X_FUNCTION_ID in NUMBER,
935 X_PROMPT in VARCHAR2,
936 X_DESCRIPTION in VARCHAR2,
937 X_OWNER in VARCHAR2,
938 X_CUSTOM_MODE in VARCHAR2
939 ) is
940 begin
941 fnd_menu_entries_pkg.TRANSLATE_ROW (
942 X_MENU_ID => X_MENU_ID,
943 X_SUB_MENU_ID => X_SUB_MENU_ID,
944 X_FUNCTION_ID => X_FUNCTION_ID,
945 X_PROMPT => X_PROMPT,
946 X_DESCRIPTION => X_DESCRIPTION,
947 X_OWNER => X_OWNER,
948 X_CUSTOM_MODE => X_CUSTOM_MODE,
949 X_LAST_UPDATE_DATE => null
950 );
951 end TRANSLATE_ROW;
952
953 /* Overloaded version above */
954 procedure TRANSLATE_ROW (
955 X_MENU_ID in NUMBER,
956 X_SUB_MENU_ID in NUMBER,
957 X_FUNCTION_ID in NUMBER,
958 X_PROMPT in VARCHAR2,
959 X_DESCRIPTION in VARCHAR2,
960 X_OWNER in VARCHAR2,
961 X_CUSTOM_MODE in VARCHAR2,
962 X_LAST_UPDATE_DATE in VARCHAR2
963 ) is
964 ent_seq NUMBER;
965 f_luby number; -- entity owner in file
966 f_ludate date; -- entity update date in file
967 db_luby number; -- entity owner in db
968 db_ludate date; -- entity update date in db
969
970 begin
971 select entry_sequence into ent_seq
972 from fnd_menu_entries
973 where nvl(sub_menu_id, -1) = nvl(X_SUB_MENU_ID, -1)
974 and nvl(function_id, -1) = nvl(X_FUNCTION_ID, -1)
975 and menu_id = X_MENU_ID;
976
977 -- Translate owner to file_last_updated_by
978 f_luby := fnd_load_util.owner_id(x_owner);
979
980 -- Translate char last_update_date to date
981 f_ludate := nvl(to_date(x_last_update_date, 'YYYY/MM/DD'), sysdate);
982
983 select LAST_UPDATED_BY, LAST_UPDATE_DATE
984 into db_luby, db_ludate
985 from FND_MENU_ENTRIES_TL
986 where MENU_ID = X_MENU_ID
987 and ENTRY_SEQUENCE = ent_seq
988 and userenv('LANG') = LANGUAGE;
989
990 if (fnd_load_util.upload_test(f_luby, f_ludate, db_luby,
991 db_ludate, X_CUSTOM_MODE)) then
992 update FND_MENU_ENTRIES_TL
993 set prompt = decode(X_PROMPT,
994 fnd_load_util.null_value, null,
995 null, prompt,
996 X_PROMPT),
997 DESCRIPTION = X_DESCRIPTION,
998 LAST_UPDATE_DATE = f_ludate,
999 LAST_UPDATED_BY = f_luby,
1000 LAST_UPDATE_LOGIN = 0,
1001 SOURCE_LANG = userenv('LANG')
1002 where MENU_ID = X_MENU_ID
1003 and ENTRY_SEQUENCE = ent_seq
1004 and userenv('LANG') in (LANGUAGE, SOURCE_LANG);
1005 end if;
1006
1007
1008 -- Bug 3571184 - Removed 'sql%notfound' and 'raise no_data_found', replaced with
1009 -- an exception handler so all SQL in this block is covered - per request of GB
1010 -- as in bug - we do not want to roll back any changes made for other children in
1011 -- this tree ... MSKEES
1012 EXCEPTION
1013 WHEN NO_DATA_FOUND THEN NULL;
1014
1015 end TRANSLATE_ROW;
1016
1017
1018 /* SUBMIT_COMPILE- Submit a concurrent request to compile the menu/entries*/
1019 /* This routine must be called after loading, inserting, updating, or */
1020 /* deleting data in the menu entries table. It will submit a concurrent */
1021 /* request which will compile that data into the */
1022 /* FND_COMPILED_MENU_FUNCTIONS table. This can be called just once at */
1023 /* the end of loading a number or menu entries. */
1024 /* This routine will check to see if a request has been submitted and */
1025 /* is pending, and will submit one if there is not one pending. */
1026 /* RETURNs: status- 'P' if the request is already pending */
1027 /* 'S' if the request was submitted */
1028 /* 'E' if an error prevented request from being submitted*/
1029 function SUBMIT_COMPILE return varchar2 is
1030 begin
1031 return(FND_JOBS_PKG.SUBMIT_MENU_COMPILE);
1032 end SUBMIT_COMPILE;
1033
1034 end FND_MENU_ENTRIES_PKG;