DBA Data[Home] [Help]

PACKAGE BODY: APPS.MTL_SERIAL_CHECK

Source


1 PACKAGE BODY MTL_SERIAL_CHECK AS
2 /* $Header: INVSERLB.pls 120.1 2005/10/10 08:51:05 methomas noship $ */
3 
4   G_PKG_NAME CONSTANT VARCHAR2(30) := 'MTL_SERIAL_CHECK';
5 
6 
7 /*====================================================+
8 | debugging utility                                   |
9 +-----------------------------------------------------*/
10 procedure mdebug(msg in varchar2)
11 is
12     l_debug number := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
13 begin
14    --dbms_output.put_line(msg);
15    null;
16 end;
17 
18 /*=========================================================================
19 | Error numbers
20 105 INV_SER_INVALID_STATUS
21 106 INV_SER_STATUS_NA
22 107 INV_SER_ORG_INVALID
23 108 INV_SER_REV_INVALID
24 109 INV_SER_LOT_INVALID
25 110 INV_SER_SUB_INVALID
26 111 INV_SER_LOC_INVALID
27 113 INV_SER_UNIQ1
28 114 INV_SER_UNIACR
29 115 INV_INLTIS_SER1
30 116 INV_QTYBTWN_ISSREC
31 118 INV_SER_NOTEXIST
32 119 INV_QTYBTWN_PFX
33 120 INV_QTYBTWN_LGTH
34 121 INV_QTYBTWN_LAST
35 122 INV_QTYBTWN_NUM
36 123 INV_INLTIS_SNGET_MASK
37 124 INV_QTYBTWN_NO_SERIAL
38 ===========================================================================*/
39 /*==========================================================================+
40 |  TITLE:    qtybtwn (user exit QTYBTWN)
41 |  PURPOSE:  Takes two alphanumeric serial numbers and returns both the
42 |      quantity of individual serial numbers which fall between them and
43 |      the alpha prefix of the first serial number.
44 |
45 |  PARAMETERS:
46 |      P_FROM_SERIAL_NUMBER and P_TO_SERIAL_NUMBER specify the range of
47 |      alphanumeric serial numbers from which QTYBTWN is to determine the
48 |      quantity.  P_QUANTITY is the field name to which the quantity of
49 |      serial numbers is to bewritten.  P_PREFIX is the field name to which
50 |      the alpha prefix is to be written.
51 |
52 |  RETURN:   Returns RET_FAILURE if failure.
53 +==========================================================================*/
54 
55 /*-------------------------------------------------------------------------+
56 |  Every serial number is given a current_status which indicates where the
57 |  unit is and for what transactions it is available.  Supported statuses
58 |  are:
59 |      o 1  The unit is defined but has not been received into or issued out
60 |           of stores.
61 |      o 3  The unit has been received into stores.
62 |      o 4  The unit has been issued out of stores.
63 |      o 5  The unit has been issued out of stores and now resides in
64 |           intransit.
65 |  A serialized unit is available to be used for a particular transaction
66 |  according to the following criteria:
67 |      o 1  Available to be received into or issued out of stores in any
68 |           transaction requiring serialized units.
69 |      o 3  Available to be issued out of stores in any transaction requiring
70 |           serialized units
71 |      o 4  Available to be received into stores in any transaction requiring
72 |           serialized units
73 |      o 5  Available to be received into stores by an intransit receipt
74 |           transaction.
75 |  In addition, there are several types of serial control which determine
76 |  under what conditions serialized units are required.  Supported serial
77 |  controls are:
78 |      o 1  No serial number control.
79 |      o 2  Predefined S/N - full control.
80 |      o 3  Predefined S/N - inventory receipt.
81 |      o 5  Dynamic entry at inventory receipt.
82 |      o 6  Dynamic entry at sales order issue.
83 |
84 |  The type of transaction determines which statuses are valid for the
85 |  transaction, and which status will be assigned to the unit after the
86 |  transaction.  The supported transactions can be divided into four basic
87 |  groups, with a further division between issues and receipts in each
88 |  group.  The four groups are SO/RMA, Standard, Subinventory Transfer, and
89 |  Intransit.  The following diagram shows the relationships between
90 |  the type of transaction, serial control, and status.
91 |
92 |  A transaction may accept one or more statuses, but it only assigns one
93 |  status.  A transaction may accept serial numbers which have not yet
94 |  been defined (Dynamic entry).
95 |
96 |  SO/RMA
97 |     Issue/     Serial       Available      Assigned
98 |     Receipt    Control       Status         Status
99 |     -------   ---------   ------------   ------------
100 |     issue     1
101 |     issue       2 3 5       3                4
102 |     issue             6   1 3     Dyn        4
103 |     receipt   1
104 |     receipt     2 3       1   4            3
105 |     receipt         5     1   4   Dyn      3
106 |     receipt           6   1   4   Dyn    1
107 |
108 |  Standard
109 |     Issue/     Serial       Available      Assigned
110 |     Receipt    Control       Status         Status
111 |     -------   ---------   ------------   ------------
112 |     receipt   1       6
113 |     receipt     2 3       1   4            3
114 |     receipt         5     1   4   Dyn      3
115 |     issue     1       6
116 |     issue       2 3 5       3                4
117 |
118 |  Subinventory Transfer
119 |     Issue/     Serial       Available      Assigned
120 |     Receipt    Control       Status         Status
121 |     -------   ---------   ------------   ------------
122 |     receipt   1       6
123 |     receipt     2 3 5       3              3
124 |     issue     1       6
125 |     issue       2 3 5       3              3
126 |
127 |  Intransit
128 |     Issue/     Serial       Available      Assigned
129 |     Receipt    Control       Status         Status
130 |     -------   ---------   ------------   ------------
131 |     receipt   1       6
132 |     receipt     2 3       1   4 5          3
133 |     receipt         5     1   4 5 Dyn      3
134 |     issue     1       6
135 |     issue       2 3 5       3                  5
136 |
137 |  The array sn_mask is declared below.  It is a representation of the
138 |  above diagram.
139 +-------------------------------------------------------------------------*/
140 
141 PROCEDURE INV_QTYBETWN
142 ( p_api_version                IN    NUMBER,
143   p_init_msg_list              IN    VARCHAR2 DEFAULT FND_API.G_FALSE,
144   p_commit                     IN    VARCHAR2 DEFAULT FND_API.G_FALSE,
145   p_validation_level           IN    NUMBER DEFAULT FND_API.G_VALID_LEVEL_FULL,
146   x_return_status              OUT NOCOPY   VARCHAR2,
147   x_msg_count                  OUT NOCOPY   NUMBER,
148   x_msg_data                   OUT NOCOPY   VARCHAR2,
149   x_errorcode                  OUT NOCOPY   NUMBER,
150 
151   P_FROM_SERIAL_NUMBER         IN    VARCHAR2,
152   P_TO_SERIAL_NUMBER           IN    VARCHAR2,
153   X_QUANTITY                   OUT NOCOPY   NUMBER,
154   X_PREFIX                     OUT NOCOPY   VARCHAR2,
155   P_ITEM_ID                    IN    NUMBER,
156   P_ORGANIZATION_ID            IN    NUMBER,
157   P_SERIAL_NUMBER_TYPE         IN    NUMBER,
158   P_TRANSACTION_ACTION_ID      IN    NUMBER,
159   P_TRANSACTION_SOURCE_TYPE_ID IN    NUMBER,
160   P_SERIAL_CONTROL             IN    NUMBER,
161   P_REVISION                   IN    VARCHAR2,
162   P_LOT_NUMBER                 IN    VARCHAR2,
163   P_SUBINVENTORY               IN    VARCHAR2,
164   P_LOCATOR_ID                 IN    NUMBER,
165   P_RECEIPT_ISSUE_FLAG         IN    VARCHAR2,
166   p_simulate                   IN    VARCHAR2 DEFAULT FND_API.G_FALSE
167 ) IS
168 
169    -- Start OF comments
170    -- API name  : INV_QTYBETWN
171    -- TYPE      : Private
172    -- Pre-reqs  : None
173    -- FUNCTION  :
174    -- as explained above
175    -- Parameters:
176    --     IN    :
177    --  p_api_version      IN  NUMBER (required)
178    --  API Version of this procedure
179    --
180    --  p_init_msg_list   IN  VARCHAR2 (optional)
181    --    DEFAULT = FND_API.G_FALSE,
182    --
183    -- p_commit           IN  VARCHAR2 (optional)
184    --     DEFAULT = FND_API.G_FALSE
185    --
186    --  p_validation_level IN  NUMBER (optional)
187    --      DEFAULT = FND_API.G_VALID_LEVEL_FULL,
188    --
189    --  P_FROM_SERIAL_NUMBER          VARCHAR2
190    --  P_TO_SERIAL_NUMBER            VARCHAR2
191    --  X_QUANTITY                    VARCHAR2
192    --  X_PREFIX                      VARCHAR2
193    --  P_ITEM_ID                     NUMBER
194    --  P_ORGANIZATION_ID             NUMBER
195    --  P_SERIAL_NUMBER_TYPE          NUMBER
196    --  P_TRANSACTION_ACTION_ID       NUMBER
197    --  P_TRANSACTION_SOURCE_TYPE_ID  NUMBER
198    --  P_SERIAL_CONTROL              NUMBER
199    --  P_REVISION                    VARCHAR2
200    --  P_LOT_NUMBER                  VARCHAR2
201    --  P_SUBINVENTORY                VARCHAR2
202    --  P_LOCATOR_ID                  NUMBER
203    --  P_RECEIPT_ISSUE_FLAG          VARCHAR2
204    --  P_VALIDATE                    VARCHAR2
205    -- p_simulate  - flag that signals whether to do any insertions/updates
206    -- if equals to FND_API.G_TRUE then no inserts/updates will be done
207    -- and procedure will run in simulation mode. by default does necessary
208    -- inserts/updates
209    --
210    --     OUT   :
211    --  X_Return_Status    OUT NUMBER
212    --  Result of all the operations
213    --
214    --  X_Msg_Count        OUT NUMBER,
215    --
216    --  X_Msg_Data         OUT VARCHAR2,
217    --
218    --  X_ErrorCode        OUT NUMBER
219    --  X_QUANTITY         OUT VARCHAR2
220    --  X_PREFIX           OUT VARCHAR2
221 
222    -- Version: Current Version 0.9
223    --              Changed : Nothing
224    --          No Previous Version 0.0
225    --          Initial version 0.9
226    -- Notes  : Note text
227    -- END OF comments
228 
229    l_api_version   CONSTANT NUMBER := 0.9;
230    l_api_name      CONSTANT VARCHAR2(30) := 'INV_QTYBETWN';
231 
232    -- Initialization of local variables
233 
234    l_number_part     NUMBER := 0;
235    l_counter         NUMBER := 0;
236    l_serial_number   VARCHAR2(30);
237    l_to_status       NUMBER := 0;
238    l_dynamic_ok      NUMBER := 0 ;
239    l_mask            VARCHAR2(14);
240    l_SerExists       NUMBER:= 1;
241    l_user_id         NUMBER;
242    l_from_number     VARCHAR2(30);
243    l_to_number       VARCHAR2(30);
244    l_length          NUMBER;
245    l_padded_length   NUMBER;
246    l_obj_seq_num     NUMBER;
247 
248     l_debug number := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
249 BEGIN
250    --
251    -- Standard start of API savepoint
252    SAVEPOINT InvQtyBetwn;
253    -- Standard Call to check for call compatibility
254    IF NOT FND_API.Compatible_API_Call(l_api_version
255      , p_api_version
256      , l_api_name
257      , G_PKG_NAME) THEN
258       RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
259    END IF;
260    --
261    -- Initialize message list if p_init_msg_list is set to true
262    IF FND_API.to_Boolean(p_init_msg_list) THEN
263       FND_MSG_PUB.initialize;
264    END IF;
265    --
266    -- Initialisize API return status to access
267    x_return_status := FND_API.G_RET_STS_SUCCESS;
268    x_errorcode := 0;
269 
270    --
271    -- API Body
272    --
273 
274 
275    -- Check the Input variable receipt_issue is either Issue or Receipt
276    -- Otherwise return error message
277    IF p_receipt_issue_flag NOT IN ('I','R') then
278       FND_MESSAGE.set_name('INV','INV_QTYBTWN_ISSREC');
279       FND_MSG_PUB.Add;
280       x_errorcode := 116;
281       RAISE FND_API.G_EXC_ERROR;
282    END IF;
283 
284    -- Calling Serial Info Routine
285    --
286 
287    IF NOT INV_SERIAL_INFO
288      (p_from_serial_number  =>  p_from_serial_number ,
289       p_to_serial_number    =>  p_to_serial_number ,
290       x_prefix              =>  x_prefix,
291       x_quantity            =>  x_quantity,
292       x_from_number         =>  l_from_number,
293       x_to_number           =>  l_to_number,
294       x_errorcode           =>  x_errorcode)
295      THEN
296       -- no need to process error here since it was already added to msg
297       -- list inside inv_serial_info subroutine
298       RAISE FND_API.G_EXC_ERROR;
299    END IF;
300 
301    IF (l_debug = 1) THEN
302       mdebug('Quantity ' || to_char(x_quantity));
303       mdebug('Prefix ' || x_prefix );
304       mdebug('FROM QTY ' || l_from_number);
305       mdebug('TO QTY ' || l_to_number);
306    END IF;
307 
308    IF (p_validation_level = FND_API.G_VALID_LEVEL_FULL) THEN
309 
310       l_mask := '00000000000000';
311       --
312       IF (l_debug = 1) THEN
313          mdebug('Mask before '||l_mask);
314       END IF;
315       --
316       IF NOT SNGetMask(P_transaction_action_id,
317 	P_transaction_source_type_id,
318 	P_serial_control,
319 	l_to_status,
320 	l_dynamic_ok,
321 	P_receipt_issue_flag,
322 	l_mask,
323 	x_errorcode) then
324 
325 	 IF (l_debug = 1) THEN
326    	 mdebug('Mask Proc - Error');
327 	 END IF;
328 	 RAISE FND_API.G_EXC_ERROR ;
329       END IF;
330 
331       IF (l_debug = 1) THEN
332          mdebug('Mask ' || l_mask);
333          mdebug('x_quantity ' || x_quantity);
334          mdebug('l_counter ' || l_counter);
335       END IF;
336 
337       /*---------------------------------------------------------------+
338       | Generate the serial numbers starting from from_serial_number
339       | upto To serial number. Validate the serial numbers as you generate.
340       +---------------------------------------------------------------*/
341 
342 
343       l_number_part := TO_NUMBER(l_FROM_NUMBER);
344       l_counter := 1;
345       -- Get the length of the serial number
346       l_length := length(p_from_serial_number);
347 
348       WHILE (l_counter <= x_quantity) LOOP
349 	 -- The padded length will be the length of the serial number minus
350 	 -- the length of the number part
351 	 -- Fix by etam
352 	 l_padded_length := l_length - nvl(length(l_number_part),0);
353 	 l_serial_number := RPAD(nvl(x_Prefix, '0'), l_padded_length, '0') ||
354 	   l_number_part;
355 
356 	 IF (l_debug = 1) THEN
357    	 mdebug('Calling SNValidate procedure ');
358    	 mdebug('Item: =======> '|| to_char(p_item_id));
359    	 mdebug('Org: ========> '|| to_char(p_organization_id));
360    	 mdebug('Subinv: =====> '|| P_subinventory);
361    	 mdebug('Txn Src Id: => '|| to_char(P_transaction_source_type_id));
362    	 mdebug('Txn Act Id: => '|| to_char(P_transaction_action_id));
363    	 mdebug('Serial: =====> '|| l_serial_number);
364    	 mdebug('Loc: ========> '|| to_char(P_locator_id));
365    	 mdebug('Lot: ========> '|| P_lot_number);
366    	 mdebug('Rev: ========> '|| P_revision);
367    	 mdebug('Mask: =======> '|| l_mask);
368    	 mdebug('Dynamic: ====> '|| to_char(l_dynamic_ok));
369 	 END IF;
370 
371 	 SNValidate
372 	   (p_api_version      =>  0.9,
373 	    x_return_status    =>  x_return_status,
374 	    x_errorcode        =>  x_errorcode,
375 	    x_msg_count        =>  x_msg_count,
376 	    x_msg_data         =>  x_msg_data,
377 	    p_item_id          =>  P_item_id,
378 	    p_org_id           =>  P_organization_id,
379 	    p_subinventory     =>  P_subinventory,
380 	    p_txn_src_type_id  =>  P_transaction_source_type_id,
381 	    p_txn_action_id    =>  P_transaction_action_id,
382 	    p_serial_number    =>  l_serial_number,
383 	    p_locator_id       =>  p_locator_id,
384 	    p_lot_number       =>  P_lot_number,
385 	    p_revision         =>  P_revision,
386 	    x_SerExists        =>  l_SerExists,
387 	    p_mask             =>  l_mask,
388 	    p_dynamic_ok       =>  l_dynamic_ok);
389 
390 
394 	    END IF;
391 	 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
392 	    IF (l_debug = 1) THEN
393    	    mdebug('Calling SNValidate : Error!');
395 	    RAISE FND_API.G_EXC_ERROR ;
396 	 END IF;
397 
398 	 IF (l_debug = 1) THEN
399    	 mdebug('After Calling SNValidate procedure ');
400 	 END IF;
401 
402 	 --
403 	 IF l_SerExists = 0  then   -- serial num does not exist
404 	    IF (l_debug = 1) THEN
405    	    mdebug('Calling SNUniqueCheck Proc ');
406 	    END IF;
407 
408 	    SNUniqueCheck(
409 	      p_api_version         =>  0.9,
410 	      x_return_status       =>  x_return_status,
411 	      x_errorcode           =>  x_errorcode,
412 	      x_msg_count           =>  x_msg_count,
413 	      x_msg_data            =>  x_msg_data,
414 	      p_org_id              =>  P_Organization_Id,
415 	      p_serial_number_type  =>  P_Serial_number_type,
416 	      p_serial_number       =>  l_Serial_number);
417 
418 	    IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
419 	       RAISE FND_API.G_EXC_ERROR ;
420 	    END IF;
421 
422 
423 	    IF (l_debug = 1) THEN
424    	    mdebug('After Calling SNUniqueCheck Proc ');
425 	    END IF;
426     /*
427      * Get the next sequence number for this 'object' and insert
428      * into GEN_OBJECT_ID field : Object Genealogy
429      */
430 
431     SELECT MTL_GEN_OBJECT_ID_S.NEXTVAL
432     INTO l_obj_seq_num FROM DUAL;
433 
434 
435 	    IF NOT FND_API.to_Boolean(p_simulate) THEN
436 	       l_user_id := FND_GLOBAL.USER_ID ;
437 	       BEGIN
438 		  IF (l_debug = 1) THEN
439    		  mdebug('Inserting row with SL NO '||l_serial_number);
440 		  END IF;
441 		  INSERT INTO MTL_SERIAL_NUMBERS
442 		    (INVENTORY_ITEM_ID,
443 		    SERIAL_NUMBER,
444 		    LAST_UPDATE_DATE,
445 		    LAST_UPDATED_BY,
446 		    INITIALIZATION_DATE,
447 		    CREATION_DATE,
448 		    CREATED_BY,
449 		    LAST_UPDATE_LOGIN,
450 		    CURRENT_STATUS,
451 		    CURRENT_ORGANIZATION_ID,
452         GEN_OBJECT_ID)
453 		    VALUES
454 		    (P_Item_id, l_serial_number, sysdate,
455 		    l_user_id, sysdate, sysdate,
456 		    l_user_id, -1, 6, P_organization_id,l_obj_seq_num);
457 
458 		  IF SQL%FOUND THEN
459 		     IF (l_debug = 1) THEN
460    		     mdebug('Inserted row with SL NO '||l_serial_number);
461 		     END IF;
462 		   ELSE
463 		     IF (l_debug = 1) THEN
464    		     mdebug('Inserted failure');
465 		     END IF;
466 		  END IF;
467 
468 	       EXCEPTION
469 		  WHEN OTHERS THEN
470 		     IF (l_debug = 1) THEN
471    		     mdebug('Exception : Inserted failure:');
472 		     END IF;
473 		     NULL;
474 	       END;
475 	    END IF;  -- if not in simulation mode
476 
477 	 END IF;  -- if serial number does not exist
478          /*---------------------------------------------------------+
479          | Get next serial number
480 	 +---------------------------------------------------------*/
481          l_number_part := l_number_part + 1;
482 	 l_counter :=  l_counter + 1;
483       END LOOP;
484 
485    END IF;
486 
487    --
488    -- END of API Body
489    --
490 
491    -- Standard check of p_commit
492    IF FND_API.to_Boolean(p_commit) THEN
493       COMMIT;
494    END IF;
495 
496    -- Standard call to get message count and if count is 1, get message info
497    FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
498      , p_data => x_msg_data);
499 
500 EXCEPTION
501    WHEN FND_API.G_EXC_ERROR THEN
502       --
503       ROLLBACK TO InvQtyBetwn;
504       --
505       x_return_status := FND_API.G_RET_STS_ERROR;
506       --
507       FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
508 				, p_data => x_msg_data);
509       --
510       IF (l_debug = 1) THEN
511          mdebug('Exception :FND_API.G_EXC_ERROR');
512       END IF;
513 
514    WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
515       IF (l_debug = 1) THEN
516          mdebug('InvQtyBetwn: Unexpected error');
517       END IF;
518       --
519       ROLLBACK TO InvQtyBetwn;
520       --
521       IF (l_debug = 1) THEN
522          mdebug('InvQtyBetwn: Unexpected error-2');
523       END IF;
524       x_errorcode := -1;
525       IF (l_debug = 1) THEN
526          mdebug('InvQtyBetwn: Unexpected error-3');
527       END IF;
528       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
529       IF (l_debug = 1) THEN
530          mdebug('InvQtyBetwn: x_return_status='||x_return_status);
531       END IF;
532 
533       FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
534 				, p_data => x_msg_data);
535       --
536       IF (l_debug = 1) THEN
537          mdebug('Exception :FND_API.G_EXC_UNEXPECTED_ERROR');
538       END IF;
539 
540    WHEN OTHERS THEN
541       --
542       ROLLBACK TO InvQtyBetwn;
543       --
544       x_errorcode := -1;
545       x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
546       --
547       IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_UNEXP_ERROR) THEN
548 	 FND_MSG_PUB.Add_Exc_Msg(G_PKG_NAME, l_api_name);
552 			       , p_data => x_msg_data);
549      END IF;
550      --
551      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
553      IF (l_debug = 1) THEN
554         mdebug('Exception :');
555      END IF;
556 
557 END INV_QTYBETWN ;
558 /*---------------------------------------------------------------------------
559 ----------------------------End of INV_QTYBETWN -----------------------------
560 ----------------------------------------------------------------------------*/
561 
562 /*==========================================================================+
563 |  TITLE:    FUNCTION : SNUniqueCheck
564 |  PURPOSE:
565 |      Determine whether or not a given serial can be created without
566 |      violating the organization uniqueness criteria.
567 |
568 |  PARAMETERS:
569 |      org_id is the organization_id, serial_number_type is the value from
570 |      MTL_PARAMETERS, ser_number is the serial number in question, message
571 |      is expected to point to a text[241].
572 |
573 |  RETURN:
574 |      Returns TRUE on success, FALSE on error.
575 |
576 |  ERROR CONDITIONS:
577 |
578 |      Violation of uniqueness criteria.
579 +==========================================================================*/
580 /*------------------------------------------------------------+
581 | Dynamically create a new serial number record.  We must
582 | follow the serial number uniqueness criteria specified
583 | in the inventory parameters of this organization.  The
584 | possible criteria are:
585 |
586 |  o 1  Unique serial numbers within inventory items.
587 |       No duplicate serial numbers for any particular
588 |       inventory item across all organizations.
589 |
590 |       A serial number may be assigned to at most one
591 |       unit of each item across all organizations. This
592 |       translates into at most one record in
593 |       MTL_SERIAL_NUMBERS for each combination of
594 |       SERIAL_NUMBER and INVENTORY_ITEM_ID.
595 |
596 |  o 2  Unique serial numbers within organization.
597 |       No duplicate serial numbers within any particular
598 |       organization.
599 |
600 |       A serial number may be assigned to at most one unit
601 |       of one item in each organization, with the caveat
602 |       that the same serial number may not be assigned to
603 |       the same item in two different organizations.  This
604 |       translates into at most one record in
605 |       MTL_SERIAL_NUMBERS for each combination of
606 |       SERIAL_NUMBER and INVENTORY_ITEM_ID with the
607 |       overriding condition that there be at most one
608 |       record for any given combination of SERIAL_NUMBER
609 |       and ORGANIZATION_ID.
610 |
611 |  o 3  Unique serial numbers across organizations.
612 |       No duplicate serial numbers in the entire system.
613 |
614 |       A serial number may be assigned to at most one unit
615 |       of one item across all organizations.  This
616 |       translates into at most one record in
617 |       MTL_SERIAL_NUMBERS for each value of SERIAL_NUMBER.
618 +-------------------------------------------------------------*/
619 PROCEDURE SNUniqueCheck
620   (
621    p_api_version                 IN    NUMBER,
622    p_init_msg_list               IN    VARCHAR2 DEFAULT FND_API.G_FALSE,
623    p_commit                      IN    VARCHAR2 DEFAULT FND_API.G_FALSE,
624    p_validation_level            IN    NUMBER DEFAULT FND_API.G_VALID_LEVEL_FULL,
625    x_return_status               OUT NOCOPY   VARCHAR2,
626    x_msg_count                   OUT NOCOPY   NUMBER,
627    x_msg_data                    OUT NOCOPY   VARCHAR2,
628    x_errorcode                   OUT NOCOPY   NUMBER,
629 
630    p_org_id                      IN    NUMBER,
631    p_serial_number_type          IN    NUMBER ,
632    p_serial_number               IN    VARCHAR2 )
633 IS
634    l_api_version constant number := 0.9;
635    l_api_name constant varchar2(30) := 'SNUniqueCheck';
636 
637    L_nothing VARCHAR2(10) ;
638     l_debug number := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
639 BEGIN
640    -- Standard start of API savepoint
641    SAVEPOINT SNUniqueCheck;
642    -- Standard Call to check for call compatibility
643    IF NOT FND_API.Compatible_API_Call(l_api_version
644      , p_api_version
645      , l_api_name
646      , G_PKG_NAME) THEN
647       RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
648    END IF;
649    --
650    -- Initialize message list if p_init_msg_list is set to true
651    IF FND_API.to_Boolean(p_init_msg_list) THEN
652       FND_MSG_PUB.initialize;
653    END IF;
654    --
655    -- Initialisize API return status to access
656    x_return_status := FND_API.G_RET_STS_SUCCESS;
657    x_errorcode := 0;
658 
659    --
660    -- API Body
661    --
662 
663    IF P_serial_number_type = 2 then
664       BEGIN
665          SELECT  'X'
666          INTO    L_nothing
667          FROM    MTL_SERIAL_NUMBERS
668          WHERE   SERIAL_NUMBER = P_serial_number
669          AND     CURRENT_ORGANIZATION_ID + 0 = P_org_id;
670          --
671          if L_nothing is not NULL then
672             FND_MESSAGE.set_name('INV','INV_SER_UNIQ1');
673 	    FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
674 	    FND_MSG_PUB.Add;
675 	    x_errorcode := 113;
676 	    RAISE FND_API.G_EXC_ERROR;
677          end if;
678       EXCEPTION
682 	  FND_MSG_PUB.Add;
679         WHEN TOO_MANY_ROWS THEN
680 	  FND_MESSAGE.set_name('INV','INV_SER_UNIQ1');
681 	  FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
683 	  x_errorcode := 113;
684 	  RAISE FND_API.G_EXC_ERROR;
685 
686 	 WHEN NO_DATA_FOUND  then
687 	   null;
688       END;
689 
690       BEGIN
691 	 SELECT 'x'
692 	   INTO L_nothing
693 	     FROM MTL_SERIAL_NUMBERS S,
694 	     MTL_PARAMETERS P
695 	     WHERE S.CURRENT_ORGANIZATION_ID = P.ORGANIZATION_ID
696 	     AND S.SERIAL_NUMBER = P_serial_number
697 	     AND P.SERIAL_NUMBER_TYPE = 3;
698 
699 	   if L_nothing is not NULL then
700 	      FND_MESSAGE.set_name('INV','INV_SER_UNIACR');
701 	      FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
702 	      FND_MSG_PUB.Add;
703 	      x_errorcode := 114;
704 	      raise FND_API.G_EXC_ERROR;
705 	   end if;
706 
707       EXCEPTION
708 	 WHEN TOO_MANY_ROWS THEN
709 	   FND_MESSAGE.set_name('INV','INV_SER_UNIACR');
710 	   FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
711 	   FND_MSG_PUB.Add;
712 	   x_errorcode := 114;
713 	   RAISE FND_API.G_EXC_ERROR;
714 	 WHEN NO_DATA_FOUND THEN
715 	   null;
716       END;
717 
718    ELSIF P_serial_number_type = 3 then
719       BEGIN
720          SELECT 'x'
721          INTO L_nothing
722          FROM MTL_SERIAL_NUMBERS
723          WHERE SERIAL_NUMBER = P_serial_number;
724          if L_nothing is not NULL then
725             FND_MESSAGE.set_name('INV','INV_INLTIS_SER1');
726 	    FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
727 	    FND_MSG_PUB.Add;
728 	    x_errorcode := 115;
729 	    RAISE FND_API.G_EXC_ERROR;
730          end if;
731       EXCEPTION
732          WHEN TOO_MANY_ROWS THEN
733               FND_MESSAGE.set_name('INV','INV_INLTIS_SER1');
734 	   FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
735 	   FND_MSG_PUB.Add;
736 	   x_errorcode := 115;
737 	   RAISE FND_API.G_EXC_ERROR;
738          WHEN NO_DATA_FOUND THEN
739 	   null;
740       END;
741    END IF;
742 
743    --
744    -- END of API body
745    --
746 
747    -- Standard check of p_commit
748    IF FND_API.to_Boolean(p_commit) THEN
749       COMMIT;
750    END IF;
751 
752    -- Standard call to get message count and if count is 1, get message info
753    FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
754      , p_data => x_msg_data);
755 
756 
757 EXCEPTION
758    WHEN FND_API.G_EXC_ERROR THEN
759      --
760      ROLLBACK TO SNUniqueCheck;
761      --
762      x_return_status := FND_API.G_RET_STS_ERROR;
763      --
764      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count, p_data => x_msg_data);
765 
766    WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
767      --
768      ROLLBACK TO SNUniqueCheck;
769 
770      x_errorcode := -1;
771      x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
772 
773      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
774        , p_data => x_msg_data);
775 
776    WHEN OTHERS THEN
777      --
778      ROLLBACK TO SNUniqueCheck;
779      --
780      x_errorcode := -1;
781      x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
782      --
783      IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_UNEXP_ERROR) THEN
784 	FND_MSG_PUB.Add_Exc_Msg(G_PKG_NAME, l_api_name);
785      END IF;
786      --
787      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
788        , p_data => x_msg_data);
789 
790 END SNUniqueCheck;
791 /*----------------------------------------------------------------------------
792 -----------------------End of SNUniqueCheck Function -----------------------
793 ----------------------------------------------------------------------------*/
794 
795 /*---------------------------------------------------------------------------
796  | Retrieves mask corresponding to passed transaction action id, transaction
797  | source type id, serial number control code and receive or issue flag
798  | the mask represents the above serial number status transition diagram
799  | also returns whether dynamic creation is ok, and to what status the
800  | serial number would go as result of this transaction
801  | in case of error returns false and x_errorcode indicates error
802  +--------------------------------------------------------------------------*/
803 FUNCTION SNGetMask(P_txn_act_id          IN      NUMBER,
804                    P_txn_src_type_id     IN      NUMBER,
805                    P_serial_control      IN      NUMBER,
806                    x_to_status           OUT NOCOPY     NUMBER,
807                    x_dynamic_ok          OUT NOCOPY     NUMBER,
808                    P_receipt_issue_flag  IN      VARCHAR2,
809 		   x_mask                OUT NOCOPY     VARCHAR2,
810 		   x_errorcode           OUT NOCOPY     NUMBER)
811                    RETURN BOOLEAN IS
812    --
813    TYPE L_mask_tab IS TABLE OF VARCHAR2(14)
814         INDEX BY BINARY_INTEGER;
815    L_sn_mask  L_mask_tab;
816    L_group NUMBER := 0;
817    --
818     l_debug number := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
819 BEGIN
820    -- initialize out variables
821    x_errorcode := 0;
822    x_to_status := 0;
826    L_sn_mask(2) := 'I0000011010014';
823    x_dynamic_ok := 0;
824 
825    L_sn_mask(1) := 'I0110100010004';
827    L_sn_mask(3) := 'R0110001001003';
828    L_sn_mask(4) := 'R0000101991013';
829    L_sn_mask(5) := 'R0000011001011';
830    L_sn_mask(6) := '00000000000000';
831    L_sn_mask(7) := 'R0110001001003';
832    L_sn_mask(8) := 'R0000101001013';
833    L_sn_mask(9) := 'I0110100010004';
834    L_sn_mask(10):= '00000000000000';
835    L_sn_mask(11):= 'R0110110001003';
836    L_sn_mask(12):= 'I0110110010004';
837    L_sn_mask(13):= '00000000000000';
838    L_sn_mask(14):= 'R0110001001103';
839    L_sn_mask(15):= 'R0000101001113';
840    L_sn_mask(16):= 'I0110100010005';
841    L_sn_mask(17):= '00000000000000';
842    /*---------------------------------------------------------------------
843    | Determine which group the transactions to.  the value of
844    |  group will be used to provide the appropriate offset in the sn_mask
845    |  array table
846    +----------------------------------------------------------------------*/
847    -- Sales Order [SO] - 2
848    -- RMA              - 12
849    -- SO RMA GROUP     - 0
850    IF P_txn_src_type_id in (2,12) then
851        L_group := 0;
852    ELSE
853       IF P_txn_act_id = 2 then                -- SUBXFR
854          L_group := 10 ;                      -- SUB_XFER_GROUP
855       ELSIF P_txn_act_id = 12 then            -- INTERECEIPT
856          null;                                -- Not defined yet
857       ELSIF P_txn_act_id = 21 then            -- INTSHIP
858          L_group := 13 ;                      -- INTRANS_GROUP
859       ELSE                                    -- Default Value
860          L_group := 6 ;                       -- STD_GROUP
861       END IF;
862    END IF;
863    L_group := L_group + 1;    -- It starts from 0th position, just to avoid
864    x_mask := L_sn_mask(L_group);
865    /*---------------------------------------------------------------------
866    | Match up the transaction with the appropriate mas and get the assigned
867    | status.  If there is no match, then to_status will still be zero after
868    | the loop
869    +-----------------------------------------------------------------------*/
870    WHILE ( substr(x_mask,1,1) <> '0' )
871    LOOP
872       if ( substr(x_mask,1,1) = P_receipt_issue_flag ) AND
873          ( substr(x_mask,P_serial_control+1,1) = '1' ) then
874          x_to_status := to_number(substr(x_mask,14,1));  -- get the 14th character from mask
875          x_dynamic_ok := to_number(substr(x_mask,13,1)); -- get the 13th character from mask
876          exit;
877       end if;
878       L_group := L_group + 1;  -- go to next mask group
879       x_mask := L_sn_mask(L_group);
880    END LOOP;
881 
882    IF x_to_status = 0  then
883       FND_MESSAGE.SET_NAME('INV', 'INV_INLTIS_SNGET_MASK');
884       FND_MSG_PUB.Add;
885       x_errorcode := 123;
886       return(FALSE);
887    ELSE
888       return(TRUE);
889    END IF;
890 
891 EXCEPTION
892    WHEN OTHERS THEN
893      x_errorcode := -1;
894      return(FALSE);
895 END SNGetmask;
896 /*---------------------------------------------------------------------------
897 -----------------------End of SNGetmask Function ---------------------------
898 ----------------------------------------------------------------------------*/
899 
900 -- TODO: need to add serial geneology stuff
901 PROCEDURE SNValidate
902   (p_api_version                IN   NUMBER,
903    p_init_msg_list              IN   VARCHAR2 DEFAULT FND_API.G_FALSE ,
904    p_commit                     IN   VARCHAR2 DEFAULT FND_API.G_FALSE,
905    p_validation_level           IN   NUMBER DEFAULT FND_API.G_VALID_LEVEL_FULL,
906    x_return_status              OUT NOCOPY  VARCHAR2,
907    x_msg_count                  OUT NOCOPY  NUMBER,
908    x_msg_data                   OUT NOCOPY  VARCHAR2,
909    x_errorcode                  OUT NOCOPY  NUMBER,
910 
911    p_item_id                    IN   NUMBER,
912    p_org_id                     IN   NUMBER,
913    p_subinventory               IN   VARCHAR2,
914    p_txn_src_type_id            IN   NUMBER,
915    p_txn_action_id              IN   NUMBER,
916    p_serial_number              IN   VARCHAR2,
917    p_locator_id                 IN   NUMBER,
918    p_lot_number                 IN   VARCHAR2,
919    p_revision                   IN   VARCHAR2,
920    x_SerExists                  OUT NOCOPY  NUMBER,
921    P_mask                       IN   VARCHAR2,
922    P_dynamic_ok                 IN   NUMBER)
923 IS
924    L_api_version CONSTANT NUMBER := 0.9;
925    L_api_name CONSTANT VARCHAR2(30) := 'SNValidate';
926 
927   -- Declare Local variables
928   L_current_status          NUMBER;
929   L_current_revision        VARCHAR2(4);
930 -- Increased lot size to 80 Char - Mercy Thomas - B4625329
931   L_current_lot_number      VARCHAR2(80);
932   L_current_subinventory    VARCHAR2(10);
933   L_current_locator_id      NUMBER;
934   L_current_organization_id NUMBER;
935   L_wip_entity_id           NUMBER;
936   L_nothing                 VARCHAR2(10);
937   L_user_id                 NUMBER;
938     l_debug number := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
939 BEGIN
940    SAVEPOINT SNValidate;
941    -- Standard Call to check for call compatibility
942    IF NOT FND_API.Compatible_API_Call(l_api_version
946       RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
943      , p_api_version
944      , l_api_name
945      , G_PKG_NAME) THEN
947    END IF;
948    --
949    -- Initialize message list if p_init_msg_list is set to true
950    IF FND_API.to_Boolean(p_init_msg_list) THEN
951       FND_MSG_PUB.initialize;
952    END IF;
953    --
954    -- Initialisize API return status to success
955    x_return_status := FND_API.G_RET_STS_SUCCESS;
956    x_errorcode := 0;
957 
958 
959    --
960    x_serexists := 1;
961 
962    --
963    -- API Body
964    --
965 
966 
967   /*-------------------------------------------+
968   |  Check for existence of the serial number
969   +-------------------------------------------*/
970   IF (l_debug = 1) THEN
971      mdebug ('SNValidate : Begin ');
972   END IF;
973   -- Validate Serial Number for exist
974   BEGIN
975      SELECT  decode(current_status,6,1,current_status),
976        revision,
977        lot_number,
978        current_subinventory_code,
979        current_locator_id,
980        current_organization_id,
981        original_wip_entity_id
982        INTO    L_current_status,
983        L_current_revision,
984        L_current_lot_number,
985        L_current_subinventory,
986        L_current_locator_id,
987        L_current_organization_id,
988        L_wip_entity_id
989        FROM    MTL_SERIAL_NUMBERS
990        WHERE   inventory_item_id = P_Item_id
991        AND     serial_number = P_serial_number;
992      IF (l_debug = 1) THEN
993         mdebug ('SNValidate : After SQL ');
994      END IF;
995 
996 
997      IF L_current_locator_id is null then
998 	L_current_locator_id := 0;
999      END IF;
1000 
1001      IF L_current_organization_id is null then
1002 	L_current_organization_id := 0;
1003      END IF;
1004 
1005      IF (l_debug = 1) THEN
1006         mdebug ('SNValidate : Before status check ');
1007      END IF;
1008 
1009      IF L_current_status is NULL or
1010        L_current_status = 2 or
1011        L_current_status < 1 or
1012         L_current_status > 5 then
1013 	FND_MESSAGE.set_name('INV','INV_SER_INVALID_STATUS');
1014 	FND_MESSAGE.SET_TOKEN('TOKEN',P_serial_number);
1015 	FND_MSG_PUB.Add;
1016 	x_errorcode := 105;
1017 	raise FND_API.G_EXC_ERROR;
1018      END IF;
1019 
1020      IF (l_debug = 1) THEN
1021         mdebug ('SNValidate : After status check ');
1022      END IF;
1023      /* Check the current status aginst the available status in the mask
1024      */
1025 
1026      IF (l_debug = 1) THEN
1027         mdebug ('SNValidate : current status '||to_char(L_current_status));
1028         mdebug ('SNValidate : Mask '||P_mask);
1029      END IF;
1030      IF substr(P_mask,L_current_status+7,1)='0' then
1031 	FND_MESSAGE.set_name('INV','INV_SER_STATUS_NA');
1032 	FND_MESSAGE.SET_TOKEN('TOKEN',P_serial_number);
1033 	FND_MSG_PUB.Add;
1034 	x_errorcode := 106;
1035 	raise FND_API.G_EXC_ERROR;
1036      END IF;
1037      IF (l_debug = 1) THEN
1038         mdebug ('SNValidate : After Stats+7 ');
1039      END IF;
1040 
1041      /*-----------------------------------------------------------+
1042      |  If the unit is currently in inventory (status 3), then it
1043      |  must be issued or transferred to the same revision,
1044      |  lot number, and org that it was received against.
1045      |  If the unit is defined but not transacted (status 1) then
1046      |  it must be received to or issued from the organization
1047      |  for which it is defined.
1048      +----------------------------------------------------------*/
1049      IF (l_debug = 1) THEN
1050         mdebug ('SNValidate : Curr Stat'||to_char(L_current_status));
1051         mdebug ('SNValidate : P_Org '||to_char(p_org_id));
1052         mdebug ('SNValidate : L_Org '||to_char(L_current_organization_id));
1053      END IF;
1054 
1055      IF (L_current_status = 3 or
1056        L_current_status = 1) AND
1057        L_current_organization_id <> p_org_id then
1058 	FND_MESSAGE.set_name('INV','INV_SER_ORG_INVALID');
1059 	FND_MESSAGE.SET_TOKEN('TOKEN',P_serial_number);
1060 	FND_MSG_PUB.Add;
1061 	x_errorcode := 107;
1062 	RAISE FND_API.G_EXC_ERROR;
1063      END IF;
1064 
1065      IF (l_debug = 1) THEN
1066         mdebug ('SNValidate : After Stats - not org ');
1067      END IF;
1068 
1069      IF  L_current_status = 3 then
1070 	IF L_current_revision <> P_revision then
1071 	   FND_MESSAGE.set_name('INV','INV_SER_REV_INVALID');
1072 	   FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
1073 	   FND_MESSAGE.SET_TOKEN('TOKEN2',L_current_revision);
1074 	   FND_MSG_PUB.Add;
1075 	   x_errorcode := 108;
1076 	   raise FND_API.G_EXC_ERROR;
1077 	ELSIF L_current_lot_number <> P_lot_number then
1078 	   FND_MESSAGE.set_name('INV','INV_SER_LOT_INVALID');
1079 	   FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
1080 	   FND_MESSAGE.SET_TOKEN('TOKEN2',L_current_lot_number);
1081 	   FND_MSG_PUB.Add;
1082 	   x_errorcode := 109;
1083 	   raise FND_API.G_EXC_ERROR;
1084 	END IF;
1085      END IF;
1086      /*--------------------------------------------------------------+
1087       |  If issuing a unit which is currently in inventory, then we
1091      IF (l_debug = 1) THEN
1088       |  must issue from the organization, subinventory, and locator
1089       |  in which the unit is currently located.
1090       +--------------------------------------------------------------*/
1092         mdebug ('SNValidate : Before mask check 0 - 3 ');
1093      END IF;
1094      IF substr(P_mask,1,1)='I' and L_current_status = 3 then
1095 	IF L_current_subinventory <> P_subinventory then
1096 	   FND_MESSAGE.set_name('INV','INV_SER_SUB_INVALID');
1097 	   FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
1098 	   FND_MESSAGE.SET_TOKEN('TOKEN2',L_current_subinventory);
1099 	   FND_MSG_PUB.Add;
1100 	   x_errorcode := 110;
1101 	   RAISE FND_API.G_EXC_ERROR;
1102 	ELSIF L_current_locator_id <> P_locator_id then
1103 	   FND_MESSAGE.set_name('INV','INV_SER_LOC_INVALID');
1104 	   FND_MESSAGE.SET_TOKEN('TOKEN1',P_serial_number);
1105 	   FND_MSG_PUB.Add;
1106 	   x_errorcode := 111;
1107 	   RAISE FND_API.G_EXC_ERROR;
1108 	END IF;
1109      END IF;
1110 
1111   EXCEPTION
1112      WHEN NO_DATA_FOUND THEN
1113         IF (l_debug = 1) THEN
1114            mdebug('Exception :whennodatafound dynamic '||to_char(nvl(P_dynamic_ok,0)));
1115         END IF;
1116 
1117         IF nvl(P_dynamic_ok,0)= 0 then
1118            FND_MESSAGE.set_name('INV','INV_SER_NOTEXIST');
1119 	   FND_MESSAGE.SET_TOKEN('TOKEN',P_serial_number);
1120 	   FND_MSG_PUB.Add;
1121 	   x_errorcode := 118;
1122 	   RAISE FND_API.G_EXC_ERROR;
1123         ELSE
1124            x_SerExists := 0;
1125         END IF;
1126   END;
1127 
1128 
1129   IF P_txn_src_type_id = 5 AND
1130     (( P_txn_action_id = 31 and L_current_status <> 1) OR
1131     ( P_txn_action_id = 32 ) OR
1132     ( P_txn_action_id = 27 ) ) AND
1133     L_wip_entity_id is  NULL  then
1134      FND_MESSAGE.set_name('INV','INV_SER_STATUS_NA');
1135      FND_MESSAGE.SET_TOKEN('TOKEN',P_serial_number);
1136      FND_MSG_PUB.Add;
1137      x_errorcode := 106;
1138      raise FND_API.G_EXC_ERROR;
1139   END IF;
1140 
1141   --
1142   -- SERIAL GENEOLOGY UPDATE GOES HERE
1143   --
1144 
1145 
1146   --
1147   -- END of API body
1148   --
1149 
1150   IF FND_API.to_Boolean(p_commit) THEN
1151      COMMIT;
1152   END IF;
1153   -- Standard call to get message count and if count is 1, get message info
1154   FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
1155     , p_data => x_msg_data);
1156 
1157 EXCEPTION
1158    WHEN FND_API.G_EXC_ERROR THEN
1159      --
1160      ROLLBACK TO SNValidate;
1161      --
1162      x_return_status := FND_API.G_RET_STS_ERROR;
1163      --
1164      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
1165        , p_data => x_msg_data);
1166        --
1167 
1168    WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
1169      IF (l_debug = 1) THEN
1170         mdebug('InvQtyBetwn: Unexpected error '||sqlerrm);
1171      END IF;
1172      --
1173      ROLLBACK TO SNValidate;
1174      --
1175      x_errorcode := -1;
1176 
1177      x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1178 
1179      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
1180        , p_data => x_msg_data);
1181 
1182 
1183    WHEN OTHERS THEN
1184      IF (l_debug = 1) THEN
1185         mdebug('SNValidate other:' || sqlerrm);
1186      END IF;
1187      --
1188      ROLLBACK TO SNValidate;
1189      --
1190      x_errorcode := -1;
1191      x_return_status := FND_API.G_RET_STS_UNEXP_ERROR;
1192      --
1193      IF FND_MSG_PUB.Check_Msg_Level(FND_MSG_PUB.G_MSG_LVL_UNEXP_ERROR) THEN
1194 	FND_MSG_PUB.Add_Exc_Msg(G_PKG_NAME, l_api_name);
1195      END IF;
1196      --
1197      FND_MSG_PUB.Count_And_Get(p_count => x_msg_count
1198        , p_data => x_msg_data);
1199 
1200 END SNValidate;
1201 /*---------------------------------------------------------------------------
1202 -----------------------End of SNValidate Function --------------------------
1203 ----------------------------------------------------------------------------*/
1204 
1205 /* ========================================================================
1206  | Helper procedure called form inv_qtybetwn
1207  | takes p_from_serial_number and p_to_serial_number and
1208  | parses out common prefix and range of numbers from them
1209  | (if p_to_serial_number is not supplied than it will be assumed to be the
1210  | same as p_from_serial_number)
1211  |
1212  | pre: none
1213  |
1214  | returns: true upon successful completion
1215  |
1216  |    false upon failure, x_errorcode will contain error number
1217  |
1218  | if function completes successfully then
1219  | x_prefix will contain common prefix or null if both from and two do not
1220  | have alpha prefix
1221  | x_quantity will contain positive quantity (# of serial numbers between
1222  | p_from_serial_number and p_to_serial_number)
1223  | x_from number will contain starting number
1224  | x_to_serial_number will contain ending range number
1225  +-------------------------------------------------------------------------*/
1226 
1227 
1228  FUNCTION INV_SERIAL_INFO(P_FROM_SERIAL_NUMBER       IN       VARCHAR2,
1229                           P_TO_SERIAL_NUMBER         IN       VARCHAR2,
1230                           x_PREFIX                   OUT NOCOPY      VARCHAR2,
1234 			  x_errorcode                OUT NOCOPY      NUMBER)
1231                           x_QUANTITY                 OUT NOCOPY      VARCHAR2,
1232                           X_FROM_NUMBER              OUT NOCOPY      VARCHAR2,
1233 			  X_TO_NUMBER                OUT NOCOPY      VARCHAR2,
1235  RETURN BOOLEAN IS
1236    L_f_alp_part VARCHAR2(30);
1237    L_t_alp_part VARCHAR2(30);
1238    L_f_num_part VARCHAR2(30);
1239    L_t_num_part VARCHAR2(30);
1240    L_ser_col_val VARCHAR2(30);
1241    L_ser_col_num NUMBER;
1242    L_from_length NUMBER;
1243    L_to_length NUMBER;
1244    L_f_ser_num VARCHAR2(30);
1245    L_t_ser_num VARCHAR2(30);
1246     l_debug number := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
1247  BEGIN
1248     x_errorcode := 0;
1249 
1250     L_f_ser_num := P_FROM_SERIAL_NUMBER;
1251     L_t_ser_num := P_TO_SERIAL_NUMBER;
1252 
1253 
1254 
1255         /*--------------------------------------------------------------+
1256         | Get the lengths of the two serial numbers. If the to serial
1257         | number is not specified copy from serial number to it.
1258         +--------------------------------------------------------------*/
1259        L_from_length := nvl(LENGTH(L_f_ser_num),0);
1260        L_to_length   := nvl(LENGTH(L_t_ser_num),0);
1261        IF (l_debug = 1) THEN
1262           mdebug('L_from_length='||L_from_length);
1263           mdebug('L_to_length='||L_to_length);
1264        END IF;
1265 
1266        --
1267        IF L_from_length = 0 then
1268 	  FND_MESSAGE.SET_NAME('INV', 'INV_QTYBTWN_NO_SERIAL');
1269 	  FND_MSG_PUB.Add;
1270 	  x_errorcode := 124;
1271 	  return (FALSE);
1272        END IF;
1273 
1274        IF L_to_length = 0 then
1275           L_t_ser_num := L_f_ser_num;
1276           L_to_length := L_from_length;
1277        END IF;
1278         /*-----------------------------------------------------------------+
1279         | Split the given serial number into alpha
1280         | prefix and numeric part.
1281         +-----------------------------------------------------------------*/
1282        -- From Serial Number
1283        L_ser_col_num := L_from_length;
1284        --
1285        while (L_ser_col_num > 0 )
1286        loop
1287          L_ser_col_val := substr(L_f_ser_num,L_ser_col_num,1);
1288          if ASCII(L_ser_col_val) >= 48 and ASCII(L_ser_col_val) <= 57 then
1289             L_f_num_part := L_ser_col_val||L_f_num_part;
1290          else
1291             L_f_alp_part := substr(L_f_ser_num,1,L_ser_col_num);
1292             exit;
1293          end if;
1294          L_ser_col_num := L_ser_col_num - 1;
1295        end loop;
1296        -- To Serial Number
1297        -- Values for 0 to 9 is corresponds to ASCII value 48 TO 57
1298        -- All other values are Non-numeric value
1299        --
1300        L_ser_col_num := L_to_length;
1301        while (L_ser_col_num > 0)
1302        loop
1303          L_ser_col_val := substr(L_t_ser_num,L_ser_col_num,1);
1304          if ascii(L_ser_col_val) >= 48 and ascii(L_ser_col_val) <= 57 then
1305             L_t_num_part := L_ser_col_val||L_t_num_part;
1306          else
1307             L_t_alp_part := substr(L_t_ser_num,1,L_ser_col_num);
1308             exit;
1309          end if;
1310          L_ser_col_num := L_ser_col_num - 1;
1311        end loop;
1312         /*----------------------------------------------------------------+
1313         | We compare the prefixes to see if they are the same
1314 	+----------------------------------------------------------------*/
1315 
1316 	if (L_f_alp_part <> L_t_alp_part) or
1317 	  (l_f_alp_part is null and l_t_alp_part is not null) or
1318 	   (l_f_alp_part is not null and l_t_alp_part is null)
1319 	then
1320 	   FND_MESSAGE.set_name('INV','INV_QTYBTWN_PFX');
1321 	   FND_MSG_PUB.Add;
1322 	   x_errorcode := 119;
1323 	   RETURN(FALSE);
1324 
1325 	end if;
1326         /*---------------------------------------------------------------+
1327         | Check the lengths of the two serial numbers to make sure they
1328         | match.
1329         +---------------------------------------------------------------*/
1330        if (L_from_length <> L_to_length) then
1331           -- Message Name : INV_QTYBTWN_LGTH
1332 	  FND_MESSAGE.set_name('INV','INV_QTYBTWN_LGTH');
1333 	  FND_MSG_PUB.Add;
1334 	  x_errorcode := 120;
1335           RETURN(FALSE);
1336        end if;
1337        /*-------------------------------------------------------
1338        | Check whether the serial numbers are matched
1339        | If not, check the last character of serial number is character
1340        | If yes, return error message
1341        +-------------------------------------*/
1342        -- XXX checks only one
1343        if L_f_ser_num <> L_t_ser_num then
1344           if ascii(substr(L_f_ser_num,LENGTH(L_f_ser_num),1)) < 48 and
1345              ascii(substr(L_f_ser_num,LENGTH(L_f_ser_num),1)) > 57  then
1346 	     FND_MESSAGE.set_name('INV','INV_QTYBTWN_LAST');
1347 	     FND_MSG_PUB.Add;
1348 	     x_errorcode := 121;
1349 	     RETURN (FALSE);
1350 	  end if;
1351        end if;
1352        -- Calculate the difference of serial numbers
1353        -- How many serial nos are there in the given range
1354        --
1355        IF (l_debug = 1) THEN
1356           mdebug('L_t_num_part='||L_t_num_part);
1357           mdebug('L_f_num_part='||L_f_num_part);
1358        END IF;
1359 
1360        -- Out variables
1361        X_Quantity :=
1362 	 nvl(to_number(L_t_num_part),0) - nvl(to_number(L_f_num_part),0) + 1;
1363 
1364        if (X_Quantity <= 0) then
1365         --  Message Name : INV_QTYBTWN_NUM
1366           FND_MESSAGE.set_name('INV','INV_QTYBTWN_NUM');
1367           FND_MSG_PUB.Add;
1368 	  x_errorcode := 122;
1369           RETURN (FALSE);
1370        end if;
1371        --
1372        /*--------------------------------------------------------------+
1373        | Check to make sure To serial number is greater than
1374        | From serial number.
1375        +--------------------------------------------------------------*/
1376 
1377        X_PREFIX := L_f_alp_part;
1378        X_FROM_NUMBER := L_f_num_part ;
1379        X_TO_NUMBER   := L_t_num_part;
1380 
1381        RETURN(TRUE);
1382 
1383  EXCEPTION
1384     WHEN OTHERS THEN
1385       x_errorcode := -1;
1386       RETURN(FALSE);
1387  END;
1388 END MTL_SERIAL_CHECK;