DBA Data[Home] [Help]

PACKAGE BODY: APPS.FND_SEQNUM

Source


1 package body FND_SEQNUM as
2 /* $Header: AFSQNUMB.pls 120.2 2005/11/03 08:12:59 fskinner ship $ */
3 
4 
5 /*	Private structure for storing a cache of the info retrieved by get_seq_info()
6 	it is likey that during a given session this function may be called 100's of
7 	times with the same input parameters - thus the same Doc_Seq info */
8 
9 TYPE t_SeqInfo IS RECORD (
10 	initFlag		boolean := FALSE,
11 	app_id			number,
12 	cat_code		varchar2(30),
13     sob_id			number,
14     met_code		char,
15     docseq_id		number,
16     docseq_type		char,
17     docseq_name		varchar2(30),
18 	db_seq_name		varchar2(30),
19 	seq_ass_id		number,
20 	prd_tab_name	varchar2(30),
21 	aud_tab_name	varchar2(30),
22 	msg_flag		char,
23 	startDate		date,
24 	endDate			date,
25 	retStat			number );
26 
27 v_SeqInfoCache	t_SeqInfo;	-- declare my global cache buffer
28 
29   function get_next_sequence (appid    in     number,
30                               cat_code in     varchar2,
31                               sobid    in     number,
32                               met_code in     char,
33                               trx_date in     date,
34                               dbseqnm  in out nocopy varchar2,
35                               dbseqid  in out nocopy integer) return number
36   is
37     t varchar2(1);
38     seqval   integer;   /* the next sequence value */
39     seqassid integer;   /* sequence assignment id  */
40   begin
41 
42     /* Get DB_SEQUENCE_NAME, DOC_SEQUENCE_ID and SEQUENCE_ASSIGNMENT_ID. */
43     get_seq_name(appid,cat_code,sobid,met_code,trx_date,
44                  dbseqnm,dbseqid,seqassid);
45 
46 	/* Bug 701013 - change where clause to use DOC_SEQUENCE_ID instead of
47 	DB_SEQUENCE_NAME user and gapless don't use db sequences */
48     select type into t
49       from FND_DOCUMENT_SEQUENCES
50      where DOC_SEQUENCE_ID = dbseqid;
51 
52 	/* Bug 701013 - added 't = G' to if statement to get Gapless */
53     if ( (t = 'U') OR (t = 'G') ) then
54       seqval := get_next_user_sequence(0,seqassid,dbseqid);
55     elsif (t = 'A') then
56       seqval := get_next_auto_seq(dbseqnm);
57     end if;
58 
59     return(seqval);
60 
61   end get_next_sequence;
62 
63   procedure get_seq_name (appid    in  number,
64                           cat_code in  varchar2,
65                           sobid    in  number,
66                           met_code in  char,
67                           trx_date in  date,
68                           dbseqnm  out nocopy varchar2,
69                           dbseqid  out nocopy integer,
70                           seqassid out nocopy integer)
71   is
72   begin
73 
74      SELECT SEQ.DB_SEQUENCE_NAME,
75             SEQ.DOC_SEQUENCE_ID,
76             SA.doc_sequence_assignment_id
77       INTO dbseqnm, dbseqid, seqassid
78       FROM FND_DOCUMENT_SEQUENCES SEQ,
79            FND_DOC_SEQUENCE_ASSIGNMENTS SA
80      WHERE SEQ.DOC_SEQUENCE_ID        = SA.DOC_SEQUENCE_ID
81        AND SA.APPLICATION_ID          = appid
82        AND SA.CATEGORY_CODE           = cat_code
83        AND (SA.METHOD_CODE = met_code or SA.METHOD_CODE is NULL)
84        AND (SA.SET_OF_BOOKS_ID = sobid or SA.SET_OF_BOOKS_ID is NULL)
85 	/* bug 1019289, 1295363 - change between to add .9999 to end date -- also removed extra
86 		todate() tochar() and work with straight dates */
87        AND trx_date between SA.START_DATE and nvl( SA.END_DATE + .9999, trx_date + .9999 );
88   end get_seq_name;
89 
90 /*
91  * This function gets the nextval for a db sequence given the seq name.
92  * Fix Bug 1073084 - changed to use EXECUTE IMMEDIATE instead of dbms_sql.
93  */
94 function get_next_auto_seq (dbseqnm in varchar2) return number
95 is
96 	v_proc_stmt		varchar2(100);
97 	v_nextVal		integer;
98 
99 begin
100 	v_proc_stmt := 'select ' || dbseqnm || '.nextval ' || 'into :next_val from sys.dual';
101 
102 	EXECUTE IMMEDIATE v_proc_stmt INTO v_nextVal;
103 	return( v_nextVal );
104 
105 	exception
106 		when others then
107 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
108 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
109 			fnd_message.set_token( 'ROUTINE', 'get_next_auto_seq', FALSE );
110 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
111 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
112 			fnd_message.set_token( 'SQLSTMT', v_proc_stmt, FALSE );
113 			app_exception.raise_exception;
114 			return( NULL );
115 
116 end get_next_auto_seq;
117 
118   /*-------------------------------------------------------------------------+
119    | get_next_auto_sequence
120    |
121    |  Determines the sequence used in the provided context and returns the
122    |  next value. Sequence must exist, otherwise, an error message is issued.
123    |
124    |  'in' variables:
125    |   appid = application_id
126    |   sobid = set_of_books_id
127    |   cat_code = category_code
128    |   met_code = method_code
129    |   trx_date = transaction_date
130    *-------------------------------------------------------------------------*/
131   function get_next_auto_sequence (appid in number,
132                                    cat_code in varchar2,
133                                    sobid in number,
134                                    met_code in char,
135                                    trx_date in varchar2) return number
136   is
137      proc_stmt      varchar2(100);
138      dbseqnm        varchar2(30);
139      c              integer;
140      row_processed  integer;
141      temp           integer;
142      val            integer;
143      next_val       integer;
144 
145   begin
146 
147      SELECT SEQ.DB_SEQUENCE_NAME into dbseqnm
148       FROM FND_DOCUMENT_SEQUENCES SEQ,
149            FND_DOC_SEQUENCE_ASSIGNMENTS SA
150      WHERE SEQ.DOC_SEQUENCE_ID        = SA.DOC_SEQUENCE_ID
151        AND SA.APPLICATION_ID          = appid
152        AND SA.CATEGORY_CODE           = cat_code
153        AND (SA.METHOD_CODE = met_code or SA.METHOD_CODE is NULL)
154        AND (SA.SET_OF_BOOKS_ID = sobid or SA.SET_OF_BOOKS_ID is NULL)
155 -- bug 1019289, 1295363 - change between to add .9999 to end date, also removed trunc's
156        AND to_date( trx_date, decode( length(trx_date),
157                                   9,'DD-MON-RR',
158                                   10,'DD-MM-YYYY',
159                                   11,'DD-MON-YYYY',
160                                      'YYYY/MM/DD') ) between
161            sa.start_date and nvl(sa.end_date + .9999,to_date(trx_date,decode(length(trx_date),
162                                          9,'DD-MON-RR',
163                                          10,'DD-MM-YYYY',
164                                          11,'DD-MON-YYYY',
165                                             'YYYY/MM/DD')) +.9999);
166 
167     c := dbms_sql.open_cursor;
168 
169     proc_stmt := 'begin select ' || dbseqnm || '.nextval ' ||
170                  'into :next_val from sys.dual; end;';
171 
172     dbms_sql.parse(c, proc_stmt, dbms_sql.native);
173     dbms_sql.bind_variable(c, 'next_val', next_val);
174 
175     row_processed := dbms_sql.execute(c);
176     dbms_sql.variable_value(c,'next_val', val);
177 
178     dbms_sql.close_cursor(c);
179     return (val);
180 
181     exception
182       when NO_DATA_FOUND then
183         fnd_message.set_name('FND', 'GET_NEXT_SEQ_VALUE_ERROR');
184         fnd_message.set_token('SEQUENCE', dbseqnm, FALSE);
185         app_exception.raise_exception;
186 
187   end get_next_auto_sequence;
188 
189   function get_next_auto_sequence (appid in number,
190                                    cat_code in varchar2,
191                                    sobid in number,
192                                    met_code in char,
193                                    trx_date in date) return number
194   is
195      proc_stmt      varchar2(100);
196      dbseqnm        varchar2(30);
197      c              integer;
198      row_processed  integer;
199      temp           integer;
200      val            integer;
201      next_val       integer;
202 
203   begin
204 
205      SELECT SEQ.DB_SEQUENCE_NAME into dbseqnm
206       FROM FND_DOCUMENT_SEQUENCES SEQ,
207            FND_DOC_SEQUENCE_ASSIGNMENTS SA
208      WHERE SEQ.DOC_SEQUENCE_ID        = SA.DOC_SEQUENCE_ID
209        AND SA.APPLICATION_ID          = appid
210        AND SA.CATEGORY_CODE           = cat_code
211        AND (SA.METHOD_CODE = met_code or SA.METHOD_CODE is NULL)
212        AND (SA.SET_OF_BOOKS_ID = sobid or SA.SET_OF_BOOKS_ID is NULL)
213 /* bug 1019289, 1295363 - change between to add .9999 to end date also removed trunc
214 and date coversion routines not needed since this trx_date is a date */
215        AND trx_date between sa.start_date and nvl(sa.end_date + .9999, trx_date + .9999);
216 
217     c := dbms_sql.open_cursor;
218 
219     proc_stmt := 'begin select ' || dbseqnm || '.nextval ' ||
220                  'into :next_val from sys.dual; end;';
221 
222     dbms_sql.parse(c, proc_stmt, dbms_sql.native);
223     dbms_sql.bind_variable(c, 'next_val', next_val);
224 
225     row_processed := dbms_sql.execute(c);
226     dbms_sql.variable_value(c,'next_val', val);
227 
228     dbms_sql.close_cursor(c);
229     return (val);
230 
231     exception
232       when NO_DATA_FOUND then
233         fnd_message.set_name('FND', 'GET_NEXT_SEQ_VALUE_ERROR');
234         fnd_message.set_token('SEQUENCE', dbseqnm, FALSE);
235         app_exception.raise_exception;
236 
237   end get_next_auto_sequence;
238 
239   procedure create_gapless_sequences
240   is
241      cursor c
242          is
243      select seq.doc_Sequence_id
244        from fnd_document_sequences seq
245       where seq.doc_sequence_id not in
246          (select su.doc_Sequence_id
247            from fnd_doc_sequence_users su)
248         and seq.type='G';
249      seqid    number;
250      result   number;
251   begin
252 
253      open c;
254 
255      loop
256        fetch c into seqid;
257        exit when c%notfound;
258 
259        result := create_gapless_sequence(seqid);
260 
261      end loop;
262      close c;
263 
264     commit;
265 
266     exception
267       when others then
268         fnd_message.set_name('FND', 'SQL-GENERIC ERROR');
269         fnd_message.set_token('ERRNO', sqlcode, FALSE);
270         fnd_message.set_token('ROUTINE', 'create_gapless_sequence', FALSE);
271         fnd_message.set_token('REASON', sqlerrm, FALSE);
272         fnd_message.set_token('ERRFILE', 'AFSQNUMB.pls', FALSE);
273         fnd_message.set_token('SQLSTMT', 'select seq.doc_Sequence_id ...', FALSE);
274         app_exception.raise_exception;
275 
276   end create_gapless_sequences;
277 
278   /* This function creates a row in the fnd_doc_sequence_users
279    * to keep track of the sequence value of a gapless sequence.
280    * This is called when a sequence is assigned to a document in
281    * Assign Document Sequence form (FNDSNASQ).
282    *
283    * Bug 494345: FND_DOC_SEQUENCE_USERS should only record one sequence
284    *             per entry, instead of one assignment per entry. Therefore,
285    *             the sequence_assignment_id in this table is not really used
286    *             in determining the sequence next value. The assignment_id
287    *             of the first assignment that uses that particular sequence
288    *             will be recorded.
289    */
290   function create_gapless_sequence (seqid in number) return number
291   is
292   begin
293 
294       insert into fnd_doc_sequence_users
295                  (doc_sequence_id,
296                   doc_sequence_assignment_id,
297                   user_id,
298                   nextval,
299                   creation_date,
300                   created_by,
301                   last_update_date,
302                   last_updated_by,
303                   last_update_login)
304       select seq.doc_sequence_id,
305              sa.doc_sequence_assignment_id,
306              0,
307      /* Bug 508093: removed '+1' that was added to the NVL of initial_value
308                     not sure why it was there in the first place it
309                     prevented the value of '1' from ever being used by
310                     a gapless sequence - the forms now protects against
311                     the zero value - which may have been why we had it
312                     there - so now the default will be 1 instead of 2
313 
314                     Replaced NVL with Decode - now we proctect the API from
315                     zero or NULL (as per request from MWARREN) and do not
316                     depend on forms.
317       */
318              DECODE(seq.initial_value, NULL, 1, 0, 1, seq.initial_value),
319              sysdate, 0, sysdate, 0, 0
320       from fnd_document_sequences seq,
321            fnd_doc_sequence_assignments sa
322       where seq.doc_sequence_id = sa.doc_sequence_id
323       and   sa.doc_sequence_id = seqid
324       and   sa.doc_Sequence_assignment_id =
325         (select min(doc_sequence_assignment_id)
326          from fnd_doc_sequence_assignments
327          where doc_sequence_id = seqid);
328 
329       return(1);
330 
331     exception
332       when others then
333         fnd_message.set_name('FND', 'SQL-GENERIC ERROR');
334         fnd_message.set_token('ERRNO', sqlcode, FALSE);
335         fnd_message.set_token('ROUTINE', 'create_gapless_sequence( '|| seqid || ' )', FALSE);
336         fnd_message.set_token('REASON', sqlerrm, FALSE);
337         fnd_message.set_token('ERRFILE', 'AFSQNUMB.pls', FALSE);
338         fnd_message.set_token('SQLSTMT', 'insert into fnd_doc_sequence_users ...', FALSE);
339  		app_exception.raise_exception;
340         return(0);
341 
342   end create_gapless_sequence;
343 
344 
345 
346   /* This function gets the nextval of a gapless/user sequence and update the
347    * next nextval.
348    *  fds_user_id = 0 for gapless sequence, userid for user sequence
349    *  seqassid = sequence_assignment_id - not used since bug 494345
350    *  seqid = doc_sequence_id
351    */
352 function get_next_user_sequence (	fds_user_id	in number,
353 									seqassid	in number, -- not used
354 									seqid		in number) return number
355 is
356 	v_nextVal number;
357 begin
358 	update	fnd_doc_sequence_users
359 	set		nextval = nextval + 1
360 	where	user_id = fds_user_id and doc_sequence_id = seqid;
361 
362 	select	distinct nextval-1
363 	into	v_nextVal
364 	from	fnd_doc_sequence_users
365 	where	doc_sequence_id = seqid and user_id = fds_user_id;
366 
367 	return(v_nextVal);
368 
369 	exception
370 		when no_data_found then
371 			fnd_message.set_name( 'FND','SQL-ERROR SELECTING' );
372 			fnd_message.set_token( 'TABLENAME', 'FND_DOC_SEQUENCE_USERS' ,FALSE);
373 			app_exception.raise_exception;
374 			return(0);
375 
376 		when others then
377 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
378 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
379 			fnd_message.set_token( 'ROUTINE', 'get_next_user_sequence', FALSE );
380 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
381 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
382 			fnd_message.set_token( 'SQLSTMT', 'update fnd_doc_sequence_users ... nextval', FALSE );
383 			app_exception.raise_exception;
384 			return(0);
385 end get_next_user_sequence;
386 
387 
388 
389 /*	This procedure is added for bug 586077 and creates data base sequences
390 	for all AUTOMATIC sequences defined in FND_DOCUMENT_SEQUENCES but does
391 	not yet have a real DB sequences in ALL_SEQUENCES.  This is done by the
392 	this server side PLSQL rather than spawning a Concurrent Request. */
393 /*	Fix for bug 1106208 -- behavior is changed from above to remove the outer
394 	join to ALL_SEQUENCES -- instead we now call this routine at the PRE-INSERT
395 	trigger of the define form for each record inserted.  Thus we can pass the
396 	new db_sequence_name and initial_value and create the DB Seq directly.  The
397 	only bad effect of calling from PRE-INSERT is that if something wierd happens
398 	and the commit fails and AD_DDL does not the DB Seq has still been created,
399 	this will not cause any functional problems since the call to create the name
400 	is called before this call - FND_DOCUMENT_SEQUENCES_S.nextval has already been
401 	fired and a duplicate name will not be generated - we do have an unused DB Seq
402 	hanging around, but the odds of this happing are low since this the last thing
403 	we do before the insert */
404 procedure create_db_seq (	db_seq_name	in	fnd_document_sequences.db_sequence_name%TYPE,
405 							init_value	in	fnd_document_sequences.initial_value%TYPE )
406 is
407 	v_ddl_sql		varchar2(150);
408 	v_fnd_schema	fnd_oracle_userid.oracle_username%TYPE;
409 	v_stage			number := 0;  /* sets the stage of execution for exception processing */
410 
411 begin
412 	-- First get the FND schema name
413 	SELECT	fou.oracle_username into v_fnd_schema
414 	FROM	fnd_product_installations fpi,
415 			fnd_oracle_userid fou,
416 			fnd_application fa
417 	WHERE	fpi.application_id = fa.application_id
418 	AND		fpi.oracle_id = fou.oracle_id
419 	AND		fa.application_short_name = 'FND';
420 
421 	-- actually create the DB seq using the magic of AD_DDL
422 	v_stage := 1;
423 	v_ddl_sql := 'CREATE SEQUENCE ' || db_seq_name ||
424 		' MINVALUE 1 NOMAXVALUE START WITH ' || init_value ||
425 		' NOCACHE ORDER NOCYCLE';
426 	ad_ddl.do_ddl( v_fnd_schema, 'FND', ad_ddl.create_sequence,
427 			v_ddl_sql, db_seq_name );
428 
429     exception
430     	when others then
431 	        fnd_message.set_name('FND', 'SQL-GENERIC ERROR');
432 	        fnd_message.set_token('ERRNO', sqlcode, FALSE);
433 	        fnd_message.set_token('ROUTINE', 'create_db_seq', FALSE);
434 	        fnd_message.set_token('REASON', sqlerrm, FALSE);
435 	        fnd_message.set_token('ERRFILE', 'AFSQNUMB.pls', FALSE);
436 	        IF v_stage = 0 THEN
437 		        fnd_message.set_token('SQLSTMT', 'SELECT fou.oracle_username into v_fnd_schema ...', FALSE);
438 	        ELSE
439 		        fnd_message.set_token('SQLSTMT', ad_ddl.error_buf, FALSE);
440 		    END IF;
441 	        app_exception.raise_exception;
442 
443 end create_db_seq;
444 
445 /*
446  * This function replaces or performs the actions of the 'C' code function fdssop()
447  * Please see the comments in the spec file for usage information
448  */
449 function get_seq_info (	app_id			in number,
450 						cat_code		in varchar2,
451 					    sob_id			in number,
452 					    met_code		in char,
453 					    trx_date		in date,
454 					    docseq_id		out nocopy number,
455 					    docseq_type		out nocopy char,
456 					    docseq_name		out nocopy varchar2,
457 						db_seq_name		out nocopy varchar2,
458 						seq_ass_id		out nocopy number,
459 						prd_tab_name	out nocopy varchar2,
460 						aud_tab_name	out nocopy varchar2,
461 						msg_flag		out nocopy char,
462 					    suppress_error	in char default 'N',
463 					    suppress_warn	in char default 'N'
464 					    ) return number
465 is
466 	v_profVal	varchar2(40);
467 begin
468 
469 	/* Check to if the cache has been initialized */
470 	IF v_SeqInfoCache.initFlag THEN
471 		/* Check to see if the data in the cache has the 4 key values and the transaction date
472 			is still in range for this assignment */
473 		IF ( v_SeqInfoCache.app_id = app_id ) AND ( v_SeqInfoCache.cat_code = cat_code ) AND
474 		  ( v_SeqInfoCache.sob_id = sob_id ) AND ( v_SeqInfoCache.met_code = met_code ) AND
475 		  ( trx_date >= v_SeqInfoCache.startDate ) AND ( trx_date <= v_SeqInfoCache.endDate ) THEN
476 			IF v_SeqInfoCache.retStat = FND_SEQNUM.SEQSUCC THEN
477 			/* if we had a good status from the first select use the cache to populate this
478 				request's output parameters */
479 				docseq_id := v_SeqInfoCache.docseq_id;
480 				docseq_type := v_SeqInfoCache.docseq_type;
481 				docseq_name := v_SeqInfoCache.docseq_name;
482 				db_seq_name := v_SeqInfoCache.db_seq_name;
483 				seq_ass_id := v_SeqInfoCache.seq_ass_id;
484 				prd_tab_name := v_SeqInfoCache.prd_tab_name;
485 				aud_tab_name := v_SeqInfoCache.aud_tab_name;
486 				msg_flag := v_SeqInfoCache.msg_flag;
487 			END IF; /* retStat */
488 			/* if the status was bad last time, it still is and the data is not used
489 				so we just pass the same bad status again - i am not sure the
490 				functional app would call us twice in the same session with the
491 				same parameters after the first fail but if they do lets not waste
492 				the select time ... */
493 			return( v_SeqInfoCache.retStat );
494 		END IF; /* parameter compare */
495 		/* During a session the initFlag will always be TRUE after the first call but
496 			since the parameters have changed we will just drop through  and start anew */
497 	END IF; /* initFlag */
498 
499 	/* No cache or new parameters - so load the parameters into the cache */
500 	v_SeqInfoCache.app_id := app_id;
501 	v_SeqInfoCache.cat_code := cat_code;
502 	v_SeqInfoCache.sob_id := sob_id;
503 	v_SeqInfoCache.met_code := met_code;
504 	v_SeqInfoCache.startDate := trx_date + 1;
505 	v_SeqInfoCache.endDate := trx_date - 1;
506 	v_SeqInfoCache.initFlag := TRUE;
507 
508 	/* This call will retrieve the value of the "Sequential Numbering" profile option
509 	   'A' = Always Used, 'N' = Not Used, 'P' = Partially Used */
510 	FND_PROFILE.GET( 'UNIQUE:SEQ_NUMBERS', v_profVal );
511 	IF  v_profVal = 'N' THEN
512 		v_SeqInfoCache.retStat := FND_SEQNUM.NOTUSED;
513 		return( v_SeqInfoCache.retStat );
514 	ELSIF v_profVal <> 'P' AND v_profVal <> 'A' THEN
515 		v_SeqInfoCache.retStat := FND_SEQNUM.BADPROF;
516 		fnd_message.set_name( 'FND', 'PROFILES-VALUES' ); -- this should never happen, BUT...
517 		app_exception.raise_exception;
518 		return( v_SeqInfoCache.retStat );
519 	END IF; /* v_profVal */
520 
521 	/* do our select into the cache */
522 	select	SEQ.DOC_SEQUENCE_ID, SEQ.TYPE, SEQ.NAME,
523 			SEQ.AUDIT_TABLE_NAME, SEQ.DB_SEQUENCE_NAME, SEQ.TABLE_NAME,
524 			SA.DOC_SEQUENCE_ASSIGNMENT_ID, SEQ.MESSAGE_FLAG,
525 			SA.START_DATE, SA.END_DATE
526 	into	v_SeqInfoCache.docseq_id, v_SeqInfoCache.docseq_type, v_SeqInfoCache.docseq_name,
527 			v_SeqInfoCache.aud_tab_name, v_SeqInfoCache.db_seq_name, v_SeqInfoCache.prd_tab_name,
528 			v_SeqInfoCache.seq_ass_id, v_SeqInfoCache.msg_flag,
529 			v_SeqInfoCache.startDate, v_SeqInfoCache.endDate
530 	from 	FND_DOCUMENT_SEQUENCES SEQ, FND_DOC_SEQUENCE_ASSIGNMENTS SA
531 	where 	SEQ.DOC_SEQUENCE_ID = SA.DOC_SEQUENCE_ID and
532 			SA.APPLICATION_ID = v_SeqInfoCache.app_id and
533 			SA.CATEGORY_CODE = v_SeqInfoCache.cat_code and
534 			( SA.SET_OF_BOOKS_ID = v_SeqInfoCache.sob_id or SA.SET_OF_BOOKS_ID is NULL ) and
535 		/* bug 1354846 -  add the NULL compare to v_SeqInfoCache.met_code so the
536 		assignment query can check for either type */
537 			( SA.METHOD_CODE = v_SeqInfoCache.met_code or SA.METHOD_CODE is NULL
538 				or v_SeqInfoCache.met_code is NULL ) and
539 		/* bug 1019289, 1295363 - change between to add .9999 to end date and trx_date */
540 			trx_date between SA.START_DATE and nvl( SA.END_DATE + .9999, trx_date + .9999 );
541 
542 	/* Load the output parameters  from the newly filled cache */
543 	docseq_id := v_SeqInfoCache.docseq_id;
544 	docseq_type := v_SeqInfoCache.docseq_type;
545 	docseq_name := v_SeqInfoCache.docseq_name;
546 	db_seq_name := v_SeqInfoCache.db_seq_name;
547 	seq_ass_id := v_SeqInfoCache.seq_ass_id;
548 	prd_tab_name := v_SeqInfoCache.prd_tab_name;
549 	aud_tab_name := v_SeqInfoCache.aud_tab_name;
550 	msg_flag := v_SeqInfoCache.msg_flag;
551 	v_SeqInfoCache.retStat := FND_SEQNUM.SEQSUCC;
552 
553 	return( v_SeqInfoCache.retStat );
554 
555 	exception
556 		when no_data_found then
557 			/* 'A' = Always Used, 'N' = Not Used, 'P' = Partially Used */
558 			IF v_profVal = 'P' THEN
559 				v_SeqInfoCache.retStat := FND_SEQNUM.NOASSIGN;
560 				IF upper(suppress_warn) = 'N' THEN
561 					fnd_message.set_name( 'FND', 'UNIQUE-NO ASSIGNMENT' );
562 					app_exception.raise_exception;
563 				END IF;
564 			ELSIF v_profVal = 'A' THEN
565 				v_SeqInfoCache.retStat := FND_SEQNUM.ALWAYS;
566 				IF upper(suppress_error) = 'N' THEN
567 					fnd_message.set_name( 'FND', 'UNIQUE-ALWAYS USED' );
568 					app_exception.raise_exception;
569 				END IF;
570 			END IF;
571 			return( v_SeqInfoCache.retStat );
572 
573 		when others then
574 			v_SeqInfoCache.retStat := FND_SEQNUM.ORAFAIL;
575 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
576 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
577 			fnd_message.set_token( 'ROUTINE', 'get_seq_info', FALSE );
578 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
579 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
580 			fnd_message.set_token( 'SQLSTMT', 'select SEQ.DOC_SEQUENCE_ID, SEQ.TYPE, SEQ.NAME ...', FALSE );
581 			app_exception.raise_exception;
582 			return( v_SeqInfoCache.retStat );
583 
584 end get_seq_info;
585 
586 /*
587  * This finction creates an audit record in the audit table for the current DocSeq
588  * Fix Bug 1073084 - changed to use EXECUTE IMMEDIATE instead of dbms_sql.
589  */
590 function create_audit_rec (	aud_tab_name	in varchar2,
591 							docseq_id		in number,
592 							seq_val 		in number,
593 							seq_ass_id		in number,
594 							user_id			in number
595 							) return number
596 is
597 	v_proc_stmt		varchar2(500);
598 	v_row_processed	integer;
599 begin
600 
601 
602 	v_proc_stmt := 'INSERT INTO ' || aud_tab_name || ' (DOC_SEQUENCE_ID, DOC_SEQUENCE_VALUE, ' ||
603 			'DOC_SEQUENCE_ASSIGNMENT_ID, CREATION_DATE, CREATED_BY) VALUES ( :seq_id, :val, ' ||
604 			':asgn_id, sysdate, :cr_by)';
605 	EXECUTE IMMEDIATE v_proc_stmt USING docseq_id, seq_val, seq_ass_id, user_id;
606 	return( FND_SEQNUM.SEQSUCC );
607 
608 	exception
609 		when dup_val_on_index then
610 			fnd_message.set_name( 'FND', 'UNIQUE-DUPLICATE SEQUENCE' );
611 			app_exception.raise_exception;
612 			return( FND_SEQNUM.NOTUNIQ );
613 		when others then
614 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
615 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
616 			fnd_message.set_token( 'ROUTINE', 'create_audit_rec', FALSE );
617 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
618 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
619 			fnd_message.set_token( 'SQLSTMT', v_proc_stmt, FALSE );
620 			app_exception.raise_exception;
621 			return( FND_SEQNUM.ORAFAIL );
622 
623 end create_audit_rec;
624 
625 /*
626  * This function replaces/performs the actions of the user exit #FND SEQVAL
627  * Please see the comments in the spec file for usage information
628  */
629 function get_seq_val (	app_id			in number,
630 						cat_code		in varchar2,
631 					    sob_id			in number,
632 					    met_code		in char,
633 					    trx_date		in date,
634 					    seq_val 		in out nocopy number,
635 					    docseq_id		out nocopy number,
636 					    suppress_error	in char default 'N',
637 					    suppress_warn	in char default 'N'
638 					    ) return number
639 is
640 	v_seqType 	char;
641 	v_seqName	varchar2(30);
642 	v_dbSeqNm	varchar2(30);
643 	v_seqAssID	number;
644 	v_prdTabNm	varchar2(30);
645 	v_audTabNm	varchar2(30);
646 	v_msgFlg	char;
647 	v_stat		number;
648 	v_profVal	varchar2(70);
649 	v_docSeqId	number;
650 begin
651 
652 	/* Get all the needed Doc_Seq info */
653 	v_stat := get_seq_info( app_id, cat_code, sob_id, met_code, trx_date, v_docSeqId, v_seqType,
654 		v_seqName, v_dbSeqNm, v_seqAssID, v_prdTabNm, v_audTabNm, v_msgFlg, suppress_error, suppress_warn );
655 	docseq_id := v_docSeqId;
656 	IF v_stat <> FND_SEQNUM.SEQSUCC THEN
657 		IF v_stat = FND_SEQNUM.NOTUSED THEN
658 			/* the profile is set to not used so we just return peacefully */
659 			return( FND_SEQNUM.SEQSUCC );
660 		ELSIF  v_stat = FND_SEQNUM.NOASSIGN THEN
661 			/* we found nothing but the profile is only set to partial so that is OK BUT,
662 			we would have given a warning in get_seq_info() based on the suppress_warn flag */
663 			return( FND_SEQNUM.SEQSUCC );
664 		ELSE
665 			return( v_stat );
666 		END IF;
667 	END IF;
668 
669 	/* This call will retrieve the value of the "USER_ID" profile option */
670 	FND_PROFILE.GET( 'USER_ID', v_profVal );
671 	IF v_profVal IS NULL THEN
672 		fnd_message.set_name( 'FND', 'USER' ); -- this should never happen, BUT...
673 		app_exception.raise_exception;
674 		return( FND_SEQNUM.BADPROF );
675 	END IF;
676 	/* we found a good Doc_Seq assignment so we proceed ...
677 	first we check the Seq Type from the FND_DOCUMENT_SEQUENCES.TYPE - valid values are :
678 	'A' = Automatic, 'G' = Gapless and 'M' = Manual
679 	'U' = Auto by User - but it is not really working - never has(??) */
680 	IF v_seqType = 'A' THEN
681 		seq_val := get_next_auto_seq( v_dbSeqNm );
682 	ELSIF v_seqType = 'G' THEN
683 		seq_val := get_next_user_sequence( 0, v_seqAssID, v_docSeqId );
684 	ELSIF v_seqType = 'U' THEN
685 		seq_val := get_next_user_sequence( to_number(v_profVal), v_seqAssID, v_docSeqId );
686 	ELSIF v_seqType = 'M' THEN
687 		IF seq_val IS NULL THEN
688 			fnd_message.set_name( 'FND', 'UNIQUE-NO VALUE' );
689 			fnd_message.set_token( 'SEQUENCE', v_seqName, FALSE );
690 			app_exception.raise_exception;
691 			return( FND_SEQNUM.NOVALUE );
692 		END IF;
693 		/* i don't actually have a routine to check the uniqueness of the Manual DocSeq
694 		like they did in the 'C' code since the very next call from #FND SEQVAL updates
695 		the audit record - where we can trap the error and report it.  If there is a
696 		requirement for an equivalent to #FND SEQCHK we can write it seperately */
697 	ELSE
698 		 -- this should never happen, unless someone uses sqlplus on our tables form validates value...
699 		return( FND_SEQNUM.BADTYPE );
700 	END IF;
701 
702 	v_stat := create_audit_rec( v_audTabNm, v_docSeqId, seq_val, v_seqAssID, to_number(v_profVal) );
703 	/* we could/should test this return stat but every thing we can handle is handled
704 		in the routine so lets just pass it on, and use it for debug on the wierd error */
705 	return( v_stat );
706 
707 end get_seq_val;
708 
709 /*
710  * This function is for special internal Applications use to create new Document
711  * Sequences in batch form by the Product teams for upgrades or coversions
712  */
713 function define_doc_seq (
714 		app_id			in number,
715 		docseq_name		in fnd_document_sequences.name%TYPE,
716 		docseq_type		in fnd_document_sequences.type%TYPE,
717 		msg_flag		in fnd_document_sequences.message_flag%TYPE,
718 		init_value		in fnd_document_sequences.initial_value%TYPE,
719 		p_startDate		in date,
720 		p_endDate		in date default NULL
721 		) return number
722 is
723 	v_numRows	number;
724 	v_audTabNm	fnd_document_sequences.audit_table_name%TYPE;
725 	v_docSeqId	number;
726 	v_dbSeqNm	fnd_document_sequences.db_sequence_name%TYPE;
727 	v_startDate	date;
728 	v_endDate	date;
729 begin
730 
731 	begin /* APPLICATION_ID check block */
732 		select count( APPLICATION_ID ) into v_numRows
733 		from FND_APPLICATION where APPLICATION_ID = app_id;
734 		IF v_numRows = 0 THEN
735 			return ( FND_SEQNUM.BADAPPID );
736 		END IF;
737 	exception
738 		when others then
739 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
740 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
741 			fnd_message.set_token( 'ROUTINE', 'define_doc_seq', FALSE );
742 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
743 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
744 			fnd_message.set_token( 'SQLSTMT', 'select count from FND_APPLICATION where APPLICATION_ID = ' || to_char(app_id), FALSE );
745 			app_exception.raise_exception;
746 			return( FND_SEQNUM.ORAFAIL );
747 	end;	/* APPLICATION_ID check block */
748 
749 	begin /* FND_DOCUMENT_SEQUENCES.NAME uniqueness check block */
750 		select count( NAME ) into v_numRows
751 		from FND_DOCUMENT_SEQUENCES where NAME = docseq_name;
752 		IF v_numRows > 0 THEN
753 			return ( FND_SEQNUM.DUPNAME );
754 		END IF;
755 	exception
756 		when others then
757 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
758 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
759 			fnd_message.set_token( 'ROUTINE', 'define_doc_seq', FALSE );
760 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
761 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
762 			fnd_message.set_token( 'SQLSTMT', 'select count from FND_DOCUMENT_SEQUENCES where NAME = ' || docseq_name, FALSE );
763 			app_exception.raise_exception;
764 			return( FND_SEQNUM.ORAFAIL );
765 	end;	/* NAME check block */
766 /* validate the type */
767 	-- IF docseq_type NOT IN ( 'A', 'G', 'M', 'U' ) THEN  /* we do not do User any more ?? */
768 	IF docseq_type NOT IN ( 'A', 'G', 'M' ) THEN
769 		return( FND_SEQNUM.BADTYPE );
770 	END IF;
771 /* validate the message_flag */
772 	IF msg_flag NOT IN ( 'Y', 'N' ) THEN
773 		return( FND_SEQNUM.BADFLAG );
774 	END IF;
775 /* basic sanity on the dates only ???
776 	first the forms format mask only allows whole dates no hours so ... */
777 	v_startDate := trunc( p_startDate );
778 	v_endDate := trunc( p_endDate );
779 	IF p_endDate <> NULL THEN
780 		IF v_startDate >= v_endDate THEN
781 			return( FND_SEQNUM.BADDATE );
782 		END IF;
783 	END IF;
784 /* this Audit Table name decode is also in the form FNDSNDSQ so change both if any */
785 	begin /* make Audit Table name block */
786 		select DECODE(app_id,0,'FND',	1,'FND',	101,'GL',	111,'RA',	140,'FA',
787 			160,'ALR',	168,'RG',	200,'AP',	201,'PO',	222,'AR',	260,'CE',
788 			300,'OE',	401,'INV',	500,'SA',	700,'MFG',	702,'BOM',	703,'ENG',
789 			704,'MRP',	705,'CRP',	706,'WIP',	800,'PER',	801,'PAY',	802,'FF',
790 			803,'DT',	804,'SSP',	7000,'JA',	7002,'JE',	7003,'JG',	7004,'JL',
791 			'FND') || '_DOC_SEQUENCE_AUDIT' into v_audTabNm from dual;
792 	exception
793 		when others then
794 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
795 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
796 			fnd_message.set_token( 'ROUTINE', 'define_doc_seq', FALSE );
797 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
798 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
799 			fnd_message.set_token( 'SQLSTMT', 'select DECODE(' || to_char(app_id) || '...) from dual', FALSE );
800 			app_exception.raise_exception;
801 			return( FND_SEQNUM.ORAFAIL );
802 	end;	/* Audit Table name block */
803 
804 /* hopefully we have checked enough to do an insert so lets pop the id sequence */
805 	begin /* get next DOC_SEQUENCE_ID block */
806 		select FND_DOCUMENT_SEQUENCES_S.nextval into v_docSeqId from dual;
807 	exception
808 		when others then
809 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
810 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
811 			fnd_message.set_token( 'ROUTINE', 'define_doc_seq', FALSE );
812 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
813 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
814 			fnd_message.set_token( 'SQLSTMT', 'select FND_DOCUMENT_SEQUENCES_S.nextval from dual', FALSE );
815 			app_exception.raise_exception;
816 			return( FND_SEQNUM.ORAFAIL );
817 	end;	/* FND_DOCUMENT_SEQUENCES_S block */
818 
819 	IF docseq_type = 'A' THEN
820 		v_dbSeqNm := 'FND_DOC_SEQ_'|| to_char(v_docSeqId) || '_S';
821 		FND_SEQNUM.create_db_seq( v_dbSeqNm, init_value );
822 	ELSE
823 		v_dbSeqNm := NULL;
824 	END IF;
825 
826 	insert into FND_DOCUMENT_SEQUENCES ( DOC_SEQUENCE_ID, NAME, APPLICATION_ID,
827 		AUDIT_TABLE_NAME, DB_SEQUENCE_NAME, MESSAGE_FLAG, TYPE, INITIAL_VALUE,
828 		START_DATE, END_DATE, LAST_UPDATE_DATE, LAST_UPDATED_BY, CREATION_DATE,
829 		CREATED_BY, LAST_UPDATE_LOGIN )
830 	values ( v_docSeqId, docseq_name, app_id, v_audTabNm, v_dbSeqNm, msg_flag,
831 		docseq_type, init_value, v_startDate, v_endDate, SYSDATE, FND_GLOBAL.USER_ID,
832 		SYSDATE, FND_GLOBAL.USER_ID, FND_GLOBAL.LOGIN_ID );
833 
834 -- ok i assume all is well let's return SEQSUCC
835 	return( FND_SEQNUM.SEQSUCC );
836 
837 exception
838 	when others then
839 		fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
840 		fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
841 		fnd_message.set_token( 'ROUTINE', 'define_doc_seq', FALSE );
842 		fnd_message.set_token( 'REASON', sqlerrm, FALSE );
843 		fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
844 		fnd_message.set_token( 'SQLSTMT', 'insert into FND_DOCUMENT_SEQUENCES ..' || docseq_name || '...', FALSE );
845 		app_exception.raise_exception;
846 		return( FND_SEQNUM.ORAFAIL );
847 
848 end define_doc_seq;
849 
850 /*
851  * This function is for special internal Applications use to create new Doc_Seq
852  * Assignments in batch form by the Product teams for upgrades or coversions
853  */
854 function assign_doc_seq (
855 		app_id			in number,
856 		docseq_name		in fnd_document_sequences.name%TYPE,
857 		cat_code		in fnd_doc_sequence_assignments.category_code%TYPE,
858 		sob_id			in fnd_doc_sequence_assignments.set_of_books_id%TYPE,
859 		met_code		in fnd_doc_sequence_assignments.method_code%TYPE,
860 		p_startDate		in date,
861 		p_endDate		in date default NULL
862 		) return number
863 is
864 	v_seqAssID	number;
865 	v_docSeqId	number;
866 	v_type		fnd_document_sequences.type%TYPE;
867 	v_prdTabNm	fnd_document_sequences.table_name%TYPE;
868 	v_enabled	fnd_descr_flex_column_usages.enabled_flag%TYPE;
869 	v_numRows	number;
870 	v_startDate	date;
871 	v_endDate	date;
872 begin
873 
874 	begin /* APPLICATION_ID check block */
875 		select count( APPLICATION_ID ) into v_numRows
876 		from FND_APPLICATION where APPLICATION_ID = app_id;
877 		IF v_numRows = 0 THEN
878 			return ( FND_SEQNUM.BADAPPID );
879 		END IF;
880 	exception
881 		when others then
882 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
883 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
884 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
885 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
886 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
887 			fnd_message.set_token( 'SQLSTMT', 'select count from FND_APPLICATION where APPLICATION_ID = ' || to_char(app_id), FALSE );
888 			app_exception.raise_exception;
889 			return( FND_SEQNUM.ORAFAIL );
890 	end;	/* APPLICATION_ID check block */
891 
892 	begin	/* FND_DOCUMENT_SEQUENCES.NAME check block */
893 		select DOC_SEQUENCE_ID, TYPE into v_docSeqId, v_type
894 		from FND_DOCUMENT_SEQUENCES where NAME = docseq_name;
895 	exception
896 		when NO_DATA_FOUND then
897 			return( FND_SEQNUM.BADNAME );
898 		when others then
899 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
900 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
901 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
902 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
903 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
904 			fnd_message.set_token( 'SQLSTMT', 'select DOC_SEQUENCE_ID from FND_DOCUMENT_SEQUENCES where NAME = ' || docseq_name, FALSE );
905 			app_exception.raise_exception;
906 			return( FND_SEQNUM.ORAFAIL );
907 	end;	/* NAME check block */
908 
909 	begin	/* get the table name for category_code */
910 		select TABLE_NAME into v_prdTabNm from FND_DOC_SEQUENCE_CATEGORIES
911 		where CODE = cat_code and APPLICATION_ID = app_id;
912 	exception
913 		when NO_DATA_FOUND then
914 			return( FND_SEQNUM.BADCODE );
915 		when others then
916 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
917 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
918 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
919 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
920 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
921 			fnd_message.set_token( 'SQLSTMT', 'select TABLE_NAME from FND_DOC_SEQUENCE_CATEGORIES where CODE = ' || cat_code, FALSE );
922 			app_exception.raise_exception;
923 			return( FND_SEQNUM.ORAFAIL );
924 	end;	/* table name for category_code block */
925 
926 	begin	/* check for Set of Books in Document Flexfield */
927 		select ENABLED_FLAG into v_enabled from FND_DESCR_FLEX_COLUMN_USAGES
928 		where APPLICATION_ID = 0 and APPLICATION_COLUMN_NAME = 'SET_OF_BOOKS_ID'
929 		and DESCRIPTIVE_FLEXFIELD_NAME = 'Document Flexfield'
930 		and DESCRIPTIVE_FLEX_CONTEXT_CODE = 'Global Data Elements';
931 		IF v_enabled = 'Y' THEN
932 			begin	/* verify the Set of Books ID */
933 				select count( SET_OF_BOOKS_ID ) into v_numRows
934 				from GL_SETS_OF_BOOKS where SET_OF_BOOKS_ID = sob_id;
935 				IF v_numRows = 0 THEN
936 					return ( FND_SEQNUM.BADSOB );
937 				END IF;
938 			exception
939 				when others then
940 					fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
941 					fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
942 					fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
943 					fnd_message.set_token( 'REASON', sqlerrm, FALSE );
944 					fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
945 					fnd_message.set_token( 'SQLSTMT', 'select count from GL_SETS_OF_BOOKS where SET_OF_BOOKS_ID = ' || to_char( sob_id ), FALSE );
946 					app_exception.raise_exception;
947 					return( FND_SEQNUM.ORAFAIL );
948 			end;	/* SOB block */
949 		END IF;
950 	exception
951 		when others then
952 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
953 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
954 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
955 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
956 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
957 			fnd_message.set_token( 'SQLSTMT', 'select ENABLED_FLAG from ... SET_OF_BOOKS_ID', FALSE );
958 			app_exception.raise_exception;
959 			return( FND_SEQNUM.ORAFAIL );
960 	end;	/* Document Flexfield block */
961 
962 	begin	/* check for Method Code in Document Flexfield */
963 		select ENABLED_FLAG into v_enabled from FND_DESCR_FLEX_COLUMN_USAGES
964 		where APPLICATION_ID = 0 and APPLICATION_COLUMN_NAME = 'METHOD_CODE'
965 		and DESCRIPTIVE_FLEXFIELD_NAME = 'Document Flexfield'
966 		and DESCRIPTIVE_FLEX_CONTEXT_CODE = 'Global Data Elements';
967 		IF v_enabled = 'Y' THEN
968 			IF met_code NOT IN ( 'A', 'M', NULL ) THEN
969 				return( FND_SEQNUM.BADMTHD );
970 			END IF;
971 		END IF;
972 	exception
973 		when others then
974 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
975 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
976 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
977 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
978 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
979 			fnd_message.set_token( 'SQLSTMT', 'select ENABLED_FLAG from ... METHOD_CODE', FALSE );
980 			app_exception.raise_exception;
981 			return( FND_SEQNUM.ORAFAIL );
982 	end;	/* Document Flexfield block */
983 
984 	begin	/* DATE check - again most of this code in forms so dual maintain */
985 		-- first the forms format mask only allows whole dates no hours so ...
986 		v_startDate := trunc( p_startDate );
987 		v_endDate := trunc( p_endDate );
988 		IF v_endDate is NULL THEN
989 			-- see if any rows of this document exist with a null end date.
990 			select	count( DOC_SEQUENCE_ASSIGNMENT_ID ) into v_numRows
991 			from	FND_DOC_SEQUENCE_ASSIGNMENTS
992 			where	CATEGORY_CODE = cat_code
993 			and		NVL( METHOD_CODE, 'NONE' ) = NVL( met_code, 'NONE' )
994 			and		APPLICATION_ID = app_id
995 			and		NVL( SET_OF_BOOKS_ID, 0 ) = NVL( sob_id, 0 )
996 			and		END_DATE IS NULL;
997 			IF v_numRows > 0  THEN
998 				-- ERROR!  there is another row with a null end_date!
999 				FND_MESSAGE.SET_NAME('FND','UNIQUE-NULL END DATE');
1000 				return( FND_SEQNUM.BADDATE ); /* comment out this line and uncomment the next for debugging */
1001 				-- app_exception.raise_exception;
1002 			ELSE
1003 				-- See if there is another row for this document with dates that overlap
1004 				select	count( DOC_SEQUENCE_ASSIGNMENT_ID ) into v_numRows
1005 				from	FND_DOC_SEQUENCE_ASSIGNMENTS
1006 				where	CATEGORY_CODE = cat_code
1007 				and		NVL( METHOD_CODE, 'NONE' ) = NVL( met_code, 'NONE' )
1008 				and		APPLICATION_ID = app_id
1009 				and		NVL( SET_OF_BOOKS_ID, 0 ) = NVL( sob_id, 0 )
1010 				and		v_startDate <= END_DATE;
1011 				IF v_numRows > 0  THEN
1012 					-- ERROR!  there is a date overlap problem.
1013 					FND_MESSAGE.SET_NAME('FND','UNIQUE-DATE OVERLAP');
1014 					return( FND_SEQNUM.BADDATE ); /* comment out this line and uncomment the next for debugging */
1015 					-- app_exception.raise_exception;
1016 				END IF;
1017 			END IF;
1018 		ELSE
1019 			-- see if there is another row in the database for the same document
1020 			select	count( DOC_SEQUENCE_ASSIGNMENT_ID ) into v_numRows
1021 			from	FND_DOC_SEQUENCE_ASSIGNMENTS
1022 			where	CATEGORY_CODE = cat_code
1023 			and		NVL( METHOD_CODE, 'NONE' ) = NVL( met_code, 'NONE' )
1024 			and		APPLICATION_ID = app_id
1025 			and		NVL( SET_OF_BOOKS_ID, 0 ) = NVL( sob_id, 0 );
1026 			IF v_numRows > 0  THEN
1027 				select	count( DOC_SEQUENCE_ASSIGNMENT_ID ) into v_numRows
1028 				from	FND_DOC_SEQUENCE_ASSIGNMENTS
1029 				where	CATEGORY_CODE = cat_code
1030 				and		NVL( METHOD_CODE, 'NONE' ) = NVL( met_code, 'NONE' )
1031 				and		APPLICATION_ID = app_id
1032 				and		NVL( SET_OF_BOOKS_ID, 0 ) = NVL( sob_id, 0 )
1033 				and
1034 				(	( v_startDate >= START_DATE and v_startDate <= NVL(END_DATE, v_endDate) )
1035 				or	( v_endDate >= START_DATE and v_endDate <= NVL(END_DATE, v_endDate) )
1036 				or	( v_endDate <= START_DATE and v_endDate >= NVL(END_DATE, v_endDate + 1) ) );
1037 				IF v_numRows > 0  THEN
1038 					-- ERROR!  there is a date overlap problem.
1039 					FND_MESSAGE.SET_NAME('FND','UNIQUE-DATE OVERLAP');
1040 					return( FND_SEQNUM.BADDATE ); /* comment out this line and uncomment the next for debugging */
1041 					-- app_exception.raise_exception;
1042 				END IF;
1043 			END IF;
1044 		END IF;
1045 	exception
1046 		when others then
1047 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
1048 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
1049 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
1050 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
1051 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
1052 			fnd_message.set_token( 'SQLSTMT', 'select count( DOC_SEQUENCE_ASSIGNMENT_ID ) .. DATE checks', FALSE );
1053 			app_exception.raise_exception;
1054 			return( FND_SEQNUM.ORAFAIL );
1055 	end;	/* DATE check block */
1056 
1057 /* hopefully we have checked enough to do an insert so lets pop the id sequence */
1058 	begin /* get next DOC_SEQUENCE_ASSIGNMENT_ID block */
1059 		select FND_DOC_SEQUENCE_ASSIGNMENTS_S.nextval into v_seqAssID from dual;
1060 	exception
1061 		when others then
1062 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
1063 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
1064 			fnd_message.set_token( 'ROUTINE', 'define_doc_seq', FALSE );
1065 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
1066 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
1067 			fnd_message.set_token( 'SQLSTMT', 'select FND_DOC_SEQUENCE_ASSIGNMENTS_S.nextval from dual', FALSE );
1068 			app_exception.raise_exception;
1069 			return( FND_SEQNUM.ORAFAIL );
1070 	end;	/* FND_DOC_SEQUENCE_ASSIGNMENTS_S block */
1071 
1072 	insert into FND_DOC_SEQUENCE_ASSIGNMENTS ( DOC_SEQUENCE_ASSIGNMENT_ID, DOC_SEQUENCE_ID,
1073 		APPLICATION_ID, CATEGORY_CODE, SET_OF_BOOKS_ID, METHOD_CODE, START_DATE, END_DATE,
1074 		LAST_UPDATE_DATE, LAST_UPDATED_BY, CREATION_DATE, CREATED_BY, LAST_UPDATE_LOGIN )
1075 	values ( v_seqAssID, v_docSeqId, app_id, cat_code, sob_id, met_code, v_startDate, v_endDate,
1076 		SYSDATE, FND_GLOBAL.USER_ID, SYSDATE, FND_GLOBAL.USER_ID, FND_GLOBAL.LOGIN_ID );
1077 
1078 	begin	/* update the table name for the Doc_Seq */
1079 		UPDATE FND_DOCUMENT_SEQUENCES
1080 		set TABLE_NAME = v_prdTabNm
1081 		where DOC_SEQUENCE_ID = v_docSeqId;
1082 	exception
1083 		when others then
1084 			fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
1085 			fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
1086 			fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
1087 			fnd_message.set_token( 'REASON', sqlerrm, FALSE );
1088 			fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
1089 			fnd_message.set_token( 'SQLSTMT', 'update FND_DOCUMENT_SEQUENCES set TABLE_NAME (..' || docseq_name || '..)', FALSE );
1090 			app_exception.raise_exception;
1091 			return( FND_SEQNUM.ORAFAIL );
1092 	end;	/* Doc_Seq update block */
1093 
1094 	IF v_type = 'G' THEN
1095 		begin /* Create Gapless check block */
1096 			select count( DOC_SEQUENCE_ID ) into v_numRows
1097 			from FND_DOC_SEQUENCE_USERS where DOC_SEQUENCE_ID = v_docSeqId;
1098 			IF v_numRows = 0 THEN
1099 				v_numRows := FND_SEQNUM.create_gapless_sequence( v_docSeqId );
1100 				IF v_numRows <> 1 THEN
1101 					return( FND_SEQNUM.ORAFAIL );
1102 				END IF;
1103 			END IF;
1104 		exception
1105 			when others then
1106 				fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
1107 				fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
1108 				fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
1109 				fnd_message.set_token( 'REASON', sqlerrm, FALSE );
1110 				fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
1111 				fnd_message.set_token( 'SQLSTMT', 'select count(DOC_SEQUENCE_ID) from FND_DOC_SEQUENCE_USERS', FALSE );
1112 				app_exception.raise_exception;
1113 				return( FND_SEQNUM.ORAFAIL );
1114 		end;	/* Gapless check block */
1115 	END IF;
1116 
1117 -- ok i assume all is well let's return SEQSUCC
1118 	return( FND_SEQNUM.SEQSUCC );
1119 
1120 exception
1121 	when others then
1122 		fnd_message.set_name( 'FND', 'SQL-GENERIC ERROR' );
1123 		fnd_message.set_token( 'ERRNO', sqlcode, FALSE );
1124 		fnd_message.set_token( 'ROUTINE', 'assign_doc_seq', FALSE );
1125 		fnd_message.set_token( 'REASON', sqlerrm, FALSE );
1126 		fnd_message.set_token( 'ERRFILE', 'AFSQNUMB.pls', FALSE );
1127 		fnd_message.set_token( 'SQLSTMT', 'insert into FND_DOC_SEQUENCE_ASSIGNMENTS (..' || docseq_name || '..)', FALSE );
1128 		app_exception.raise_exception;
1129 		return( FND_SEQNUM.ORAFAIL );
1130 
1131 end	assign_doc_seq;
1132 
1133 end FND_SEQNUM;
1134