DBA Data[Home] [Help]

PACKAGE BODY: APPS.INV_CONVERT

Source


1 PACKAGE BODY inv_convert AS
2 /* $Header: INVUMCNB.pls 120.2.12010000.2 2008/07/29 13:47:55 ptkumar ship $ */
3    -- Bug #  3144743
4    -- Put away Performance  Issue
5 
6       g_u_uom_rate          number;
7       g_u_from_unit         varchar2(10);
8       g_u_to_unit           varchar2(10);
9       g_u_item_id           varchar2(10);
10 
11       g_v_uom_rate          number;
12       g_v_from_unit         varchar2(10);
13       g_v_to_unit           varchar2(10);
14       g_v_item_id           varchar2(10);
15 
16       g_w_uom_rate          number;
17       g_w_from_unit         varchar2(10);
18       g_w_to_unit           varchar2(10);
19       g_w_item_id           varchar2(10);
20 
21       g_pkg_name CONSTANT VARCHAR2(30) := 'INV_CONVERT';
22       g_pkg_version CONSTANT VARCHAR2(100) := '$Header: INVUMCNB.pls 120.2.12010000.2 2008/07/29 13:47:55 ptkumar ship $';
23 
24    PROCEDURE inv_um_conversion (
25       from_unit         varchar2,
26       to_unit           varchar2,
27       item_id           number,
28       uom_rate    out nocopy	number )
29     IS
30 
31 BEGIN
32 
33     inv_um_conversion (
34                      from_unit,
35                      to_unit,
36                      item_id,
37                      NULL,
38                      NULL,
39                      uom_rate);
40 
41 
42 END inv_um_conversion;
43 
44 
45    PROCEDURE inv_um_conversion (
46       from_unit         varchar2,
47       to_unit           varchar2,
48       item_id           number,
49       lot_number        varchar2,
50       organization_id   number,
51       uom_rate    out nocopy 	number )
52     IS
53 
54 	/*
55 	** declare variables that are referenced in the cursor definitions
56 	*/
57 
58     from_class              varchar2(10);
59     to_class                varchar2(10);
60 
61    /*===============================================
62       Joe DiIorio 09/2004 INVCONV
63       Added variable to use lot_number in cursor
64       lot_interclass_conversions.
65      ===============================================*/
66     p_lot_number           MTL_LOT_NUMBERS.LOT_NUMBER%TYPE;
67     p_organization_id      NUMBER;
68 
69     -- Bug 2899727. Since there is no join between t and f,
70     -- leads to a cartesian product.
71     -- So, splitting the cursor into two different sqls.
72 
73     /***
74     cursor standard_conversions is
75         select  t.conversion_rate      std_to_rate,
76                 t.uom_class            std_to_class,
77                 f.conversion_rate      std_from_rate,
78                 f.uom_class            std_from_class
79         from  mtl_uom_conversions t,
80               mtl_uom_conversions f
81         where t.inventory_item_id in (item_id, 0)
82         and   t.uom_code = to_unit
83         and   nvl(t.disable_date, trunc(sysdate) + 1) > trunc(sysdate)
84         and   f.inventory_item_id in (item_id, 0)
85         and   f.uom_code = from_unit
86         and   nvl(f.disable_date, trunc(sysdate) + 1) > trunc(sysdate)
87         order by t.inventory_item_id desc,
88                  f.inventory_item_id desc;
89 
90       std_rec standard_conversions%rowtype;
91 
92       *****/
93 
94       cursor from_standard_conversions is
95 	 select  conversion_rate      std_from_rate,
96 	         uom_class            std_from_class
97 	   from  mtl_uom_conversions
98 	   where inventory_item_id in (item_id, 0)
99 	   and   uom_code = from_unit
100 	   and   nvl(disable_date, trunc(sysdate) + 1) > trunc(sysdate)
101 	   order by inventory_item_id desc;
102 
103     from_std_rec from_standard_conversions%rowtype;
104 
105     cursor to_standard_conversions is
106        select  conversion_rate      std_to_rate,
107 	       uom_class            std_to_class
108 	 from  mtl_uom_conversions
109 	 where inventory_item_id in (item_id, 0)
110 	 and   uom_code = to_unit
111 	 and   nvl(disable_date, trunc(sysdate) + 1) > trunc(sysdate)
112 	 order by inventory_item_id desc;
113 
114     to_std_rec to_standard_conversions%rowtype;
115 
116 
117     cursor interclass_conversions is
118         select decode(to_uom_class, to_class, 1, 2) to_flag,
119                decode(from_uom_class, from_class, 1, to_class, 2, 0) from_flag,
120                conversion_rate rate
121         from   mtl_uom_class_conversions
122         where  inventory_item_id = item_id
123         and    to_uom_class in (from_class, to_class)
124         and    nvl(disable_date, trunc(sysdate) + 1) > trunc(sysdate);
125 
126     class_rec interclass_conversions%rowtype;
127 
128 
129    /*===============================================
130       Joe DiIorio 09/2004 INVCONV
131       Cursor added for lot specific interclass./
132      ===============================================*/
133 
134     cursor lot_interclass_conversions is
135         select decode(to_uom_class, to_class, 1, 2) to_flag,
136                decode(from_uom_class, from_class, 1, to_class, 2, 0) from_flag,
137                conversion_rate rate
138         from   mtl_lot_uom_class_conversions
139         where  inventory_item_id = item_id
140         and    organization_id = p_organization_id
141         and    lot_number = p_lot_number
142         and    to_uom_class in (from_class, to_class)
143         and    nvl(disable_date, trunc(sysdate) + 1) > trunc(sysdate);
144 
145    /*===============================================
146       Added record type for the above  cursor.
147      ===============================================*/
148     lot_class_rec      lot_interclass_conversions%rowtype;
149 
150     invalid_conversion      exception;
151 
152     type conv_tab is table of number
153          index by binary_integer;
154 
155     type class_tab is table of varchar2(10)
156          index by binary_integer;
157 
158     interclass_rate_tab     conv_tab;
159     from_class_flag_tab     conv_tab;
160     to_class_flag_tab       conv_tab;
161     from_rate_tab           conv_tab;
162     to_rate_tab             conv_tab;
163     from_class_tab          class_tab;
164     to_class_tab            class_tab;
165 
166     std_index               number;
167     class_index             number;
168 
169     from_rate               number := 1;
170     to_rate                 number := 1;
171     interclass_rate         number := 1;
172     to_class_rate           number := 1;
173     from_class_rate         number := 1;
174     msgbuf                  varchar2(200);
175 
176 begin
177 
178     /*
179     ** Conversion between between two UOMS.
180     **
181     ** 1. The conversion always starts from the conversion defined, if exists,
182     **    for an specified item.
183     ** 2. If the conversion id not defined for that specific item, then the
184     **    standard conversion, which is defined for all items, is used.
185     ** 3. When the conversion involves two different classes, then
186     **    interclass conversion is activated.
187     */
188 
189 
190     /*
191     ** If from and to units are the same, conversion rate is 1.
192     ** Go immediately to the end of the procedure to exit.
193     */
194 
195 
196     if (from_unit = to_unit) then
197 
198 	uom_rate := 1;
199 	goto  procedure_end;
200 
201     end if;
202 
203     /*=======================================
204       Joe DiIorio 09/2004 INVCONV
205       Copy input variables.
206       =====================================*/
207     p_lot_number := lot_number;
208     p_organization_id := organization_id;
209 
210     /*
211     ** Get item specific or standard conversions
212     */
213 
214     open from_standard_conversions;
215 
216     std_index := 0;
217 
218     loop
219 
220         fetch from_standard_conversions into from_std_rec;
221         exit when from_standard_conversions%notfound;
222 
223         std_index := std_index + 1;
224 
225         from_rate_tab(std_index) := from_std_rec.std_from_rate;
226         from_class_tab(std_index) := from_std_rec.std_from_class;
227 
228     end loop;
229 
230     close from_standard_conversions;
231 
232      if (std_index = 0) then
233 
234         /*
235         ** No conversions defined
236         */
237 
238             msgbuf := msgbuf||'Invalid standard conversion : ';
239             msgbuf := msgbuf||'From UOM code: '||from_unit||' ';
240             msgbuf := msgbuf||'To UOM code: '||to_unit||' ';
241             raise invalid_conversion;
242 
243     else
244 
245         /*
246         ** Conversions are ordered. Item specific conversions will be
247         ** returned first.
248         */
249 
250         from_class := from_class_tab(1);
251         from_rate := from_rate_tab(1);
252 
253     end if;
254 
255     open to_standard_conversions;
256 
257     std_index := 0;
258 
259     loop
260 
261         fetch to_standard_conversions into to_std_rec;
262         exit when to_standard_conversions%notfound;
263 
264         std_index := std_index + 1;
265 
266         to_rate_tab(std_index) := to_std_rec.std_to_rate;
267         to_class_tab(std_index) := to_std_rec.std_to_class;
268 
269     end loop;
270 
271     close to_standard_conversions;
272 
273     if (std_index = 0) then
274 
275         /*
276         ** No conversions defined
277         */
278 
279             msgbuf := msgbuf||'Invalid standard conversion : ';
280             msgbuf := msgbuf||'From UOM code: '||from_unit||' ';
281             msgbuf := msgbuf||'To UOM code: '||to_unit||' ';
282             raise invalid_conversion;
283 
284     else
285 
286         /*
287         ** Conversions are ordered. Item specific conversions will be
288         ** returned first.
289         */
290 
291         to_class := to_class_tab(1);
292         to_rate := to_rate_tab(1);
293 
294     end if;
295 
296     /******
297 
298     -- BUG 2899727. Commenting this portion of the code. The check is
299     -- being done after both the cursons above.
300 
301     --if (std_index = 0) then
302 
303     --    /*
304     --    ** No conversions defined
305     --    */
306 
307     --       msgbuf := msgbuf||'Invalid standard conversion : ';
308     --       msgbuf := msgbuf||'From UOM code: '||from_unit||' ';
309     --       msgbuf := msgbuf||'To UOM code: '||to_unit||' ';
310     --       raise invalid_conversion;
311 
312     --else
313 
314     --   /*
315     --   ** Conversions are ordered. Item specific conversions will be
316     --  ** returned first.
317     --   */
318 
319     --   from_class := from_class_tab(1);
320     --  to_class := to_class_tab(1);
321     --   from_rate := from_rate_tab(1);
322     --   to_rate := to_rate_tab(1);
323 
324     -- end if;
325     -- End bug 2899727.
326 
327     if (from_class <> to_class) then
328       -- Bug 5447516 If item_id is 0 raise an error as intercalss conversions can be
329       -- defined only at item level.
330       if item_id = 0 then
331         raise invalid_conversion;
332       end if;
333         class_index := 0;
334 
335         /*=======================================
336            Joe DiIorio 09/2004 INVCONV
337            If there is a lot number try and get
338            the lot specific conversion first.
339           =====================================*/
340 
341         IF (lot_number is NOT NULL AND organization_id IS NOT NULL) THEN
342             open lot_interclass_conversions;
343             LOOP
344               FETCH lot_interclass_conversions INTO lot_class_rec;
345               EXIT WHEN lot_interclass_conversions%NOTFOUND;
346               class_index := class_index + 1;
347               to_class_flag_tab(class_index) := lot_class_rec.to_flag;
348               from_class_flag_tab(class_index) := lot_class_rec.from_flag;
349               interclass_rate_tab(class_index) := lot_class_rec.rate;
350             END LOOP;
351             close lot_interclass_conversions;
352 
353         END IF;
354 
355 
356         /*
357         ** Load interclass conversion tables
358         ** If two rows are returned, it implies that there is no direct
359         ** conversion between them.
360         ** If one row is returned, then it may imply that there is a direct
361         ** conversion between them or one class is not defined in the
362         ** class conversion table.
363         */
364 
365         /*  check interclass first      */
366 
367         IF (class_index = 0) THEN
368             open interclass_conversions;
369 
370             loop
371 
372                 fetch interclass_conversions into class_rec;
373                 exit when interclass_conversions%notfound;
374 
375                 class_index := class_index + 1;
376 
377                 to_class_flag_tab(class_index) := class_rec.to_flag;
378                 from_class_flag_tab(class_index) := class_rec.from_flag;
379                 interclass_rate_tab(class_index) := class_rec.rate;
380 
381             end loop;
382 
383             close interclass_conversions;
384 
385         END IF;
386 
387 
388 
389         if (class_index = 2) then
390 
391             if (to_class_flag_tab(1) = 1) then
392 
393                 to_class_rate := interclass_rate_tab(1);
394                 from_class_rate := interclass_rate_tab(2);
395 
396             else
397 
398                 to_class_rate := interclass_rate_tab(2);
399                 from_class_rate := interclass_rate_tab(1);
400 
401             end if;
402 
403 --Bug 2907403
404             interclass_rate := from_class_rate/to_class_rate;
405 
406         elsif ((class_index = 1) and
407                  (to_class_flag_tab(1) = from_class_flag_tab(1) )) then
408 
409 
410             if (to_class_flag_tab(1) = 1) then
411 
412                 to_class_rate := interclass_rate_tab(1);
413                 from_class_rate := 1;
414 
415             else
416 
417                 to_class_rate := 1;
418                 from_class_rate := interclass_rate_tab(1);
419 
420             end if;
421 
422 
423             interclass_rate := from_class_rate/to_class_rate;
424 
425         else
426 
427             /*
428             ** No interclass conversion is defined
429             */
430 
431             msgbuf := msgbuf||'Invalid Interclass conversion : ';
432             msgbuf := msgbuf||'From UOM code: '||from_unit||' ';
433             msgbuf := msgbuf||'To UOM code: '||to_unit||' ';
434             raise invalid_conversion;
435 
436 
437         end if;
438 
439 
440     end if;
441 
442 
443     /*
444     ** conversion rates are defaulted to '1' at the start of the procedure
445     ** so seperate calculations are not required for standard/interclass
446     ** conversions
447     */
448 
449     uom_rate := (from_rate * interclass_rate) / to_rate;
450 
451     /*
452     ** Put a label and a null statement over here so that you can
453     ** the goto statements can branch here.
454     */
455 
456     <<procedure_end>>
457 
458     null;
459 
460 exception
461 
462     when others then
463   --     raise_application_error(-20001, sqlerrm||'---'||msgbuf);
464          uom_rate := -99999;
465 END inv_um_conversion;
466 
467 
468     FUNCTION  inv_um_convert (
469       item_id           	number,
470       precision			number,
471       from_quantity     	number,
472       from_unit         	varchar2,
473       to_unit           	varchar2,
474       from_name			varchar2,
475       to_name			varchar2) RETURN number IS
476 
477 
478 uom_rate                        NUMBER;
479 BEGIN
480     uom_rate := inv_um_convert (
481                      item_id,
482                      NULL,
483                      NULL,
484                      precision,
485                      from_quantity,
486                      from_unit,
487                      to_unit,
488                      from_name,
489                      to_name);
490 
491     RETURN uom_rate;
492 
493 EXCEPTION
494 
495     when others then
496        return (-99999);
497 END inv_um_convert;
498 
499 
500    /*=======================================
501       Joe DiIorio 09/2004 INVCONV
502       Created overloaded version to accept
503       lot number.
504      =====================================*/
505 
506     FUNCTION  inv_um_convert (
507       item_id           	number,
508       lot_number        	varchar2,
509       organization_id          	number,
510       precision			number,
511       from_quantity     	number,
512       from_unit         	varchar2,
513       to_unit           	varchar2,
514       from_name			varchar2,
515       to_name			varchar2) RETURN number IS
516 
517 
518 	/*
519 	** declare variables that are passed to inv_uom_conversion
520 	*/
521 
522 	uom_rate	number;
523 	msgbuf          varchar2(200);
524 	from_qty_num    number;
525 	fm_unt		varchar2(3);
526 	to_unt		varchar2(3);
527 	eff_precision	number;
528 
529 BEGIN
530 
531 	/* Call the inv_uom_conversion procedure to calculate the uom_rate
532 	** and return. If from_quantity is not null, the function
533 	** assumes that to_quantity is the desired result, and this is
534 	** what is returned. Precision is defaulted to 2 decimals, unless
535 	** a different value is provided by caller of function.
536 	** This function previously calculated the conversion rate in the
537  	** body of the function itself. This was replaced by the present
538 	** procedure call because of a PL/SQL bug which caused memory leaks
539 	** while using tables in functions. Refer to bug 191321 for details.
540 	*/
541 
542 	if ( from_unit IS NULL and to_unit IS NULL ) then
543           SELECT uom_code INTO fm_unt FROM mtl_units_of_measure
544           WHERE  unit_of_measure = from_name;
545 
546 	  SELECT uom_code INTO to_unt FROM mtl_units_of_measure
547           WHERE  unit_of_measure = to_name;
548         else
549           fm_unt := from_unit;
550 	  to_unt := to_unit;
551 	end if;
552 
553       /*=====================================
554          Joe DiIorio 09/2004 INVCONV
555          Added lot_number to parameter list.
556         =====================================*/
557 
558 	inv_um_conversion(fm_unt, to_unt, item_id, lot_number, organization_id, uom_rate);
559         if ( uom_rate = -99999 ) then
560           return(-99999);
561 	end if;
562 	if ( from_quantity IS NOT NULL ) then
563 	  uom_rate := from_quantity * uom_rate;
564 	end if;
565 
566 
567 	/** Default precision for inventory was 6 decimals
568 	  Changed the default precision to 5 since INV supports a standard
569 	  precision of 5 decimal places.
570 	*/
571         if (precision IS NULL) then
572           eff_precision := 5 ;
573 	else
574 	  eff_precision := precision ;
575         end if;
576 	uom_rate := round(uom_rate, eff_precision);
577 
578 	RETURN uom_rate;
579 
580 EXCEPTION
581 
582     when others then
583   --     raise_application_error(-20001, sqlerrm||'---'||msgbuf);
584        return (-99999);
585 END inv_um_convert;
586 
587 
588   FUNCTION  inv_um_convert_new (
589       item_id           	number,
590       precision			number,
591       from_quantity     	number,
592       from_unit         	varchar2,
593       to_unit           	varchar2,
594       from_name			varchar2,
595       to_name			varchar2,
596       capacity_type             varchar2) RETURN number IS
597 
598 uom_rate                        NUMBER;
599 
600 BEGIN
601     uom_rate := inv_um_convert_new (
602                      item_id,
603                      NULL,
604                      NULL,
605                      precision,
606                      from_quantity,
607                      from_unit,
608                      to_unit,
609                      from_name,
610                      to_name,
611                      capacity_type);
612 
613     RETURN uom_rate;
614 
615 EXCEPTION
616 
617     when others then
618   --     raise_application_error(-20001, sqlerrm||'---'||msgbuf);
619        return (-99999);
620 END inv_um_convert_new;
621 
622 
623   FUNCTION  inv_um_convert_new (
624       item_id           	number,
625       lot_number        	varchar2,
626       organization_id         	number,
627       precision			number,
628       from_quantity     	number,
629       from_unit         	varchar2,
630       to_unit           	varchar2,
631       from_name			varchar2,
632       to_name			varchar2,
633       capacity_type             varchar2) RETURN number IS
634 
635 
636 	/*
637 	** declare variables that are passed to inv_uom_conversion
638 	*/
639 
640 	uom_rate	number;
641 	msgbuf          varchar2(200);
642 	from_qty_num    number;
643 	fm_unt		varchar2(3);
644 	to_unt		varchar2(3);
645 	eff_precision	number;
646         l_capacity      VARCHAR2(1); -- 'W' , 'V' ,'U'
647 
648 BEGIN
649 
650 	/* Call the inv_uom_conversion procedure to calculate the uom_rate
651 	** and return. If from_quantity is not null, the function
652 	** assumes that to_quantity is the desired result, and this is
653 	** what is returned. Precision is defaulted to 2 decimals, unless
654 	** a different value is provided by caller of function.
655 	** This function previously calculated the conversion rate in the
656  	** body of the function itself. This was replaced by the present
657 	** procedure call because of a PL/SQL bug which caused memory leaks
658 	** while using tables in functions. Refer to bug 191321 for details.
659 	*/
660 
661 	if ( from_unit IS NULL and to_unit IS NULL ) then
662           SELECT uom_code INTO fm_unt FROM mtl_units_of_measure
663           WHERE  unit_of_measure = from_name;
664 
665 	  SELECT uom_code INTO to_unt FROM mtl_units_of_measure
666           WHERE  unit_of_measure = to_name;
667         else
668           fm_unt := from_unit;
669 	  to_unt := to_unit;
670 	end if;
671 
672          -- bug 3144743
673          -- cache the following values from_uom, to_uom and the uom_rate
674          -- for better performance
675          l_capacity := capacity_type;
676 
677          if l_capacity = 'U' then
678             if     (nvl(g_u_from_unit, 'XYZ')  = fm_unt )
679                and (nvl(g_u_to_unit, 'XYZ')   = to_unit)
680                and (nvl(g_u_item_id ,-99999) = item_id)
681                and (nvl(g_u_uom_rate, -99999) <> -99999)  then
682 
683                uom_rate := g_u_uom_rate;
684              else
685 	       inv_um_conversion(fm_unt, to_unt, item_id, lot_number, organization_id, uom_rate);
686 	       g_u_from_unit  := fm_unt;
687 	       g_u_to_unit    := to_unit;
688                g_u_uom_rate   := uom_rate;
689                g_u_item_id := item_id;
690 	     end if;
691         elsif  l_capacity = 'V' then
692             if     (nvl(g_v_from_unit, 'XYZ')  = fm_unt )
693                and (nvl(g_v_to_unit, 'XYZ')   = to_unit)
694                and (nvl(g_v_item_id ,-99999) = item_id)
695                and (nvl(g_v_uom_rate, -99999) <> -99999)  then
696 
697                uom_rate := g_v_uom_rate;
698              else
699                inv_um_conversion(fm_unt, to_unt, item_id, lot_number, organization_id, uom_rate);
700                g_v_from_unit  := fm_unt;
701                g_v_to_unit    := to_unit;
702                g_v_uom_rate   := uom_rate;
703                g_v_item_id := item_id;
704              end if;
705         elsif  l_capacity = 'W' then
706             if     (nvl(g_w_from_unit, 'XYZ')  = fm_unt )
707                and (nvl(g_w_to_unit, 'XYZ')   = to_unit)
708                and (nvl(g_w_item_id ,-99999) = item_id)
709                and (nvl(g_w_uom_rate, -99999) <> -99999)  then
710 
711                uom_rate := g_w_uom_rate;
712              else
713                inv_um_conversion(fm_unt, to_unt, item_id, lot_number, organization_id, uom_rate);
714                g_w_from_unit  := fm_unt;
715                g_w_to_unit    := to_unit;
716                g_w_uom_rate   := uom_rate;
717                g_w_item_id    := item_id;
718              end if;
719         end if;
720 
721         if ( uom_rate = -99999 ) then
722           return(-99999);
723 	end if;
724 	if ( from_quantity IS NOT NULL ) then
725 	  uom_rate := from_quantity * uom_rate;
726 	end if;
727 
728 
729 	/** Default precision for inventory was 6 decimals
730 	  Changed the default precision to 5 since INV supports a standard
731 	  precision of 5 decimal places.
732 	*/
733         if (precision IS NULL) then
734           eff_precision := 5 ;
735 	else
736 	  eff_precision := precision ;
737         end if;
738 	uom_rate := round(uom_rate, eff_precision);
739 
740 	RETURN uom_rate;
741 
742 EXCEPTION
743 
744     when others then
745   --     raise_application_error(-20001, sqlerrm||'---'||msgbuf);
746        return (-99999);
747 END inv_um_convert_new;
748 
749 
750 FUNCTION validate_item_uom (p_uom_code IN VARCHAR2,
751 			    p_item_id  IN NUMBER,
752 			    p_organization_id IN NUMBER)
753   return BOOLEAN IS
754 
755 
756      l_primary_uom_code varchar(3) := null;
757      l_allowed_units     number := null;
758 
759      l_uom_code         varchar2(3) := null;
760      l_uom_class        varchar2(10) := null;
761 
762      Cursor c_msi is
763 	select PRIMARY_UOM_CODE, ALLOWED_UNITS_LOOKUP_CODE
764 	  from mtl_system_items msi,
765 	  MTL_UNITS_OF_MEASURE MTLUOM2
766 	  where msi.ORGANIZATION_ID = p_organization_id AND
767 	  msi.INVENTORY_ITEM_ID = p_item_id  AND
768 	  MTLUOM2.uom_code = msi.PRIMARY_UOM_CODE AND
769 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE);
770 
771 
772      cursor c_std_cvr_sameClass is
773 	select MTLUOM2.uom_code, MTLUCV.uom_class
774 	  from  MTL_UNITS_OF_MEASURE MTLUOM2,
775 	  MTL_UOM_CONVERSIONS  MTLUCV,
776 	  MTL_UOM_CLASSES      MTLCLS
777 	  where
778 	  MTLUOM2.uom_code = p_uom_code  AND
779 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
780 	  MTLUCV.inventory_item_id=0 AND
781 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
782 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
783 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
784 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
785 	  MTLUCV.uom_class = (select MTLPRI1.uom_class
786 			      from MTL_UNITS_OF_MEASURE MTLPRI1
787 			      where MTLPRI1.uom_code = l_primary_uom_code AND
788 			      NVL(MTLPRI1.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE)
789 			      );
790 
791      cursor c_item_cvr_sameClass is
792 	select MTLUOM2.uom_code, MTLUCV.uom_class
793 	  from  MTL_UNITS_OF_MEASURE MTLUOM2,
794 	  MTL_UOM_CONVERSIONS  MTLUCV,
795 	  MTL_UOM_CLASSES      MTLCLS
796 	  where MTLUOM2.uom_code = p_uom_code  AND
797 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
798 	  MTLUCV.inventory_item_id = p_item_id AND
799 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
800 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
801 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
802 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE);
803 
804 
805      cursor c_complex is
806 
807 	select MTLUOM2.uom_code, MTLUOM2.uom_class
808 	  from   MTL_UNITS_OF_MEASURE MTLUOM2,
809 	  MTL_UOM_CONVERSIONS  MTLUCV,
810 	  MTL_UOM_CLASSES      MTLCLS
811 	  where
812 	  MTLUOM2.uom_code = p_uom_code  AND
813 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
814 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
815 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
816 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
817 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
818 	  l_allowed_units in (1,3) AND MTLUCV.inventory_item_id = p_item_id
819 	  UNION ALL
820 	  select MTLUOM2.uom_code, MTLUOM2.uom_class
821 	  from   MTL_UNITS_OF_MEASURE MTLUOM2,
822 	  MTL_UOM_CONVERSIONS  MTLUCV,
823 	  MTL_UOM_CLASSES      MTLCLS
824 	  where
825 	  MTLUOM2.uom_code = p_uom_code  AND
826 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
827 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
828 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
829 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
830 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
831 	  l_allowed_units in (1,3) AND MTLUCV.inventory_item_id=0 AND
832 	  MTLUCV.uom_class = (select MTLPRI1.uom_class
833 			      from MTL_UNITS_OF_MEASURE MTLPRI1
834 			      where MTLPRI1.uom_code = l_primary_uom_code
835 			      )
836 	  UNION ALL
837 	  select MTLUOM2.uom_code, MTLUOM2.uom_class
838 	  from   MTL_UNITS_OF_MEASURE MTLUOM2,
839 	  MTL_UOM_CONVERSIONS  MTLUCV,
840 	  MTL_UOM_CLASSES      MTLCLS
841 	  where
842 	  MTLUOM2.uom_code = p_uom_code  AND
843 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
844 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
845 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
846 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
847 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
848 	  l_allowed_units in (1,3) AND MTLUCV.inventory_item_id=0 AND
849 	  exists(
850 		 select 'UOM_CLASS conversion exists for the class of UOM supplied'
851 		 from MTL_UOM_CLASS_CONVERSIONS MTLUCC1
852 		 where
853 		 MTLUCC1.to_uom_class = MTLUCV.uom_class AND
854 		 MTLUCC1.inventory_item_id = p_item_id AND
855 		 NVL(MTLUCC1.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE)
856 		 )
857 	  UNION ALL
858 	  select MTLUOM2.uom_code, MTLUOM2.uom_class
859 	  from   MTL_UNITS_OF_MEASURE MTLUOM2,
860 	  MTL_UOM_CONVERSIONS  MTLUCV,
861 	  MTL_UOM_CLASSES      MTLCLS
862 	  where
863 	  MTLUOM2.uom_code = p_uom_code  AND
864 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
865 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
866 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
867 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
868 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
869 	  l_allowed_units in (2,3) AND MTLUCV.inventory_item_id=0 AND
870 	  exists(
871 		 select 'UOM_CLASS conversion exists for the class of UOM supplied'
872 		 from MTL_UOM_CLASS_CONVERSIONS MTLUCC
873 		 where
874 		 MTLUCC.to_uom_class = MTLUCV.uom_class AND
875 		 MTLUCC.INVENTORY_ITEM_ID = p_item_id  AND
876               NVL(MTLUCC.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE)
877 		 )
878 	  UNION ALL
879 	  select MTLUOM2.uom_code, MTLUOM2.uom_class
880 	  from   MTL_UNITS_OF_MEASURE MTLUOM2,
881 	  MTL_UOM_CONVERSIONS  MTLUCV,
882 	  MTL_UOM_CLASSES      MTLCLS
883 	  where
884 	  MTLUOM2.uom_code = p_uom_code  AND
885 	  MTLUCV.uom_code  = MTLUOM2.uom_code AND
886 	  MTLCLS.uom_class = MTLUOM2.uom_class AND
887 	  NVL(MTLCLS.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
888 	  NVL(MTLUOM2.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
889 	  NVL(MTLUCV.DISABLE_DATE,TRUNC(SYSDATE)+1) > TRUNC(SYSDATE) AND
890 	  l_allowed_units in (2,3) AND MTLUCV.inventory_item_id=0 AND
891 	  MTLUCV.uom_class = (select MTLPRI.uom_class
892 			      from MTL_UNITS_OF_MEASURE MTLPRI
893 			      where MTLPRI.uom_code = l_primary_uom_code
894 			      );
895 
896 
897 
898 BEGIN
899 
900    IF (p_uom_code IS NULL
901        OR p_item_id IS NULL
902        OR p_organization_id IS NULL) THEN
903 
904       return(FALSE);
905    END IF;
906 
907    /* To improve performance, we will check for the most common cases first:
908    - The UOM_CODE supplied is the same as the PRIMARY_UOM_CODE of the item.
909      - The UOM_CODE supplied is in the same UOM_CLASS as the PRIMARY_UOM_CODE
910      and there is a conversion entry for it.
911      Then, if we still dont get a hit, we will test for the more complex cases,
912      like interclass conversions.
913 
914      Get the primary_uom_code for the item. Also, get the allowed conversions
915      (standard, item only, or both) in case, we need it later.
916      */
917      open c_msi;
918    fetch c_msi into l_primary_uom_code, l_allowed_units;
919 
920    IF c_msi%ISOPEN THEN
921       close c_msi;
922    END IF;
923 
924    /* If the uom_code supplied is same as item primary_uom_code then
925       uom_code is valid. Return success.
926    */
927      IF p_uom_code = l_primary_uom_code THEN
928 
929 	return(TRUE);
930      END IF;
931 
932   /* If only standard conversion is allowed, then check for UOM_CODE in
933      the same UOM_CLASS as the PRIMARY_UOM_CODE as the item
934   */
935   open c_std_cvr_sameClass;
936   fetch c_std_cvr_sameClass into l_uom_code, l_uom_class;
937   IF c_std_cvr_sameClass%FOUND THEN
938 
939      IF c_std_cvr_sameClass%ISOPEN THEN
940         close c_std_cvr_sameClass;
941      END IF;
942      return(TRUE);
943   END IF;
944 
945   /* If only item conversion is allowed, then check for UOM_CODE in
946      the same UOM_CLASS as the PRIMARY_UOM_CODE as the item
947   */
948   open c_item_cvr_sameClass;
949   fetch c_item_cvr_sameClass into l_uom_code, l_uom_class;
950   IF c_item_cvr_sameClass%FOUND THEN
951 
952      IF c_item_cvr_sameClass%ISOPEN THEN
953         close c_item_cvr_sameClass;
954      END IF;
955 
956      return(TRUE);
957   END IF;
958 
959   /* If UOM_CODE supplied is not in same class as item PRIMARY_UOM_CODE,
960      then check more complex case i.e. inter-class.
961      This sql takes care of all cases.
962   */
963   open c_complex;
964   fetch c_complex into l_uom_code, l_uom_class;
965   IF c_complex%FOUND THEN
966 
967      IF c_complex%ISOPEN THEN
968         close c_complex;
969      END IF;
970 
971      return(TRUE);
972   END IF;
973 
974   /* If we are here, then we did not find a match for the UOM_CODE supplied.
975      Therefore, UOM_CODE is not valid. return failure.
976   */
977   return (FALSE);
978 
979 EXCEPTION
980 
981 WHEN OTHERS THEN
982  IF c_msi%ISOPEN THEN
983     close c_msi;
984   END IF;
985 
986  IF c_item_cvr_sameClass%ISOPEN THEN
987     close c_item_cvr_sameClass;
988  END IF;
989 
990  IF c_complex%ISOPEN THEN
991     close c_complex;
992  END IF;
993 
994  IF c_std_cvr_sameClass%ISOPEN THEN
995     close c_std_cvr_sameClass;
996  END IF;
997 
998  RAISE;
999 
1000 END validate_item_uom;
1001 
1002 
1003 
1004 PROCEDURE print_debug( p_message VARCHAR2, p_procname VARCHAR2 := NULL, p_level NUMBER := 9) IS
1005 BEGIN
1006   --dbms_output.put_line(p_message);
1007   inv_log_util.trace(
1008     p_message => p_message
1009   , p_module  => g_pkg_name||'.'||p_procname
1010   , p_level   => p_level);
1011 END print_debug;
1012 
1013 PROCEDURE pick_uom_convert(
1014       p_org_id                  NUMBER,
1015       p_item_id                 NUMBER,
1016       p_sub_code                VARCHAR2,
1017       p_loc_id                  NUMBER,
1018       p_alloc_uom               VARCHAR2,
1019       p_alloc_qty               NUMBER,
1020       x_pick_uom       OUT NOCOPY     VARCHAR2,
1021       x_pick_qty       OUT NOCOPY     NUMBER,
1022       x_uom_string     OUT NOCOPY     VARCHAR2,
1023       x_return_status  OUT NOCOPY     VARCHAR2,
1024       x_msg_data       OUT NOCOPY     VARCHAR2,
1025       x_msg_count      OUT NOCOPY     NUMBER) IS
1026 
1027       l_loc_uom VARCHAR2(3):= null;
1028       l_uom_string VARCHAR2(20) := null;
1029       l_api_name    CONSTANT VARCHAR2(30) := 'PICK_UOM_CONVERT';
1030       l_debug                NUMBER       := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
1031 
1032   begin
1033 
1034     -- Initialize API return status to success
1035     x_return_status  := fnd_api.g_ret_sts_success;
1036 
1037 
1038     IF ( l_debug = 1 ) THEN
1039       print_debug(l_api_name || ' Entered ' || g_pkg_version, 1);
1040       print_debug('p_org_id   => '|| p_org_id||' p_item_id=>'||p_item_id||' p_sub_code=>'||p_sub_code||' p_loc_id=>'||p_loc_id ,4);
1041       print_debug('p_alloc_uom => '||p_alloc_uom||' p_alloc_qty=>'||p_alloc_qty , 4);
1042     END IF;
1043 
1044     if (p_loc_id IS NOT NULL) THEN
1045        begin
1046            SELECT pick_uom_code, inv_ui_item_lovs.get_conversion_rate(pick_uom_code, p_org_Id, p_item_Id)
1047            INTO   l_loc_uom, l_uom_string
1048            FROM   mtl_item_locations
1049            WHERE  organization_id = p_org_id
1050            AND    subinventory_code = p_sub_code
1051            AND    inventory_location_id = p_loc_id;
1052        exception
1053            WHEN OTHERS THEN
1054              IF (l_debug = 1) THEN
1055                print_debug(l_api_name ||' Error In deriving Locator Level Pick UOM', 1);
1056                IF ( SQLCODE IS NOT NULL ) THEN
1057                   print_debug('SQL error: ' || SQLERRM(SQLCODE), 1);
1058                END IF;
1059              END IF;
1060              x_pick_uom := p_alloc_uom;
1061              x_pick_qty := p_alloc_qty;
1062              x_return_status := 'E1'; --error in getting loc pick uom
1063              return;
1064        end;
1065     end if;
1066 
1067     if (l_loc_uom IS NULL) THEN
1068        begin
1069            SELECT pick_uom_code, inv_ui_item_lovs.get_conversion_rate(pick_uom_code,
1070                                    p_org_Id,
1071                                    p_item_Id)
1072            INTO   l_loc_uom, l_uom_string
1073            FROM   MTL_SECONDARY_INVENTORIES
1074            WHERE  secondary_inventory_name = p_sub_code
1075            AND    organization_id = p_org_id;
1076        exception
1077            WHEN OTHERS THEN
1078              IF (l_debug = 1) THEN
1079                print_debug(l_api_name ||' Error In deriving SubInventory Level Pick UOM', 1);
1080                IF ( SQLCODE IS NOT NULL ) THEN
1081                   print_debug('SQL error: ' || SQLERRM(SQLCODE), 1);
1082                END IF;
1083              END IF;
1084              x_pick_uom := p_alloc_uom;
1085              x_pick_qty := p_alloc_qty;
1086              x_return_status := 'E2'; --error in getting sub pick uom
1087              return;
1088        end;
1089     end if;
1090     if (l_loc_uom IS NULL) THEN
1091            x_pick_uom := p_alloc_uom;
1092            x_pick_qty := p_alloc_qty;
1093            x_return_status := 'W1'; --no loc level or sub level pick uom defined
1094            return;
1095     else
1096        --call the uom convert routine
1097            x_pick_qty := inv_um_convert(p_item_id,
1098                                        null,
1099                                        p_alloc_qty,
1100                                        p_alloc_uom,
1101                                        l_loc_uom,
1102                                        null,
1103                                        null);
1104         --return value of x_out_qty should be integer, if not return the in_qty and in_uom value
1105            if (trunc(x_pick_qty) = x_pick_qty AND x_pick_qty > 0) THEN
1106                    x_pick_uom := l_loc_uom;
1107                    x_uom_string := l_uom_string;
1108                    x_return_status := 'S'; --success
1109            else
1110                    x_pick_uom := p_alloc_uom;
1111                    x_pick_qty := p_alloc_qty;
1112                    x_return_status := 'W2'; --could not convert the value in integer
1113            end if;
1114            return;
1115     end if;
1116  end pick_uom_convert;
1117 
1118 -- Functions checks if quantities entered for dual uom
1119 -- items are within deviation range.
1120 
1121 FUNCTION within_deviation(p_organization_id IN number,
1122 p_inventory_item_id   IN number,
1123 p_lot_number          IN varchar2,
1124 p_precision           IN number,
1125 p_quantity            IN number,
1126 p_uom_code1           IN varchar2,
1127 p_quantity2           IN number,
1128 p_uom_code2           IN varchar2,
1129 p_unit_of_measure1    IN varchar2,
1130 p_unit_of_measure2    IN varchar2)
1131 
1132 RETURN NUMBER IS
1133 
1134 DEV_LOW_ERROR         EXCEPTION;
1135 DEV_HIGH_ERROR        EXCEPTION;
1136 INVALID_ITEM          EXCEPTION;
1137 INCORRECT_FIXED_VALUE EXCEPTION;
1138 INVALID_UOM_CONV      EXCEPTION;
1139 
1140 l_converted_qty           NUMBER;
1141 l_high_boundary           NUMBER;
1142 l_low_boundary            NUMBER;
1143 
1144 
1145 /*========================================
1146    Cursor to retrieve uom code.
1147   ========================================*/
1148 
1149 CURSOR c_get_uom_code (p_unit VARCHAR2) IS
1150 SELECT uom_code
1151 FROM   mtl_units_of_measure
1152 WHERE  unit_of_measure = p_unit;
1153 
1154 l_uom_code1          MTL_UNITS_OF_MEASURE.UOM_CODE%TYPE;
1155 l_uom_code2          MTL_UNITS_OF_MEASURE.UOM_CODE%TYPE;
1156 x_precision          NUMBER;
1157 l_debug              PLS_INTEGER := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
1158 l_procname           VARCHAR2 (20) := 'within_deviation';
1159 BEGIN
1160 
1161  FND_MSG_PUB.INITIALIZE;
1162 
1163  if (l_debug = 1) then
1164     print_debug('p_organization_id  : '||p_organization_id  , l_procname);
1165     print_debug('p_inventory_item_id: '||p_inventory_item_id, l_procname);
1166     print_debug('p_lot_number       : '||p_lot_number       , l_procname);
1167     print_debug('p_precision        : '||p_precision        , l_procname);
1168     print_debug('p_quantity         : '||p_quantity         , l_procname);
1169     print_debug('p_uom_code1        : '||p_uom_code1        , l_procname);
1170     print_debug('p_quantity2        : '||p_quantity2        , l_procname);
1171     print_debug('p_uom_code2        : '||p_uom_code2        , l_procname);
1172     print_debug('p_unit_of_measure1 : '||p_unit_of_measure1 , l_procname);
1173     print_debug('p_unit_of_measure2 : '||p_unit_of_measure2 , l_procname);
1174  end if;
1175 
1176 
1177 /*=============================================
1178    Must have a precision value.
1179   ===========================================*/
1180 x_precision := nvl(p_precision,5);
1181 
1182 /*=============================================
1183   Get Item Info.  Used Cache if available.
1184   ===========================================*/
1185 
1186 
1187 IF NOT (INV_CACHE.set_item_rec(p_organization_id, p_inventory_item_id)) THEN
1188    RAISE INVALID_ITEM;
1189 END IF;
1190 
1191 /*=============================================
1192   Determine if the Deviation Check is Required.
1193   =============================================*/
1194 
1195 IF (INV_CACHE.item_rec.tracking_quantity_ind = 'PS' or
1196     INV_CACHE.item_rec.ont_pricing_qty_source = 'S') THEN
1197    /*===================================================
1198       Get uom codes when units_of_measure are sent in.
1199      ===================================================*/
1200    IF (p_unit_of_measure1 IS NOT NULL) THEN
1201        OPEN c_get_uom_code (p_unit_of_measure1);
1202        FETCH c_get_uom_code INTO l_uom_code1;
1203        CLOSE c_get_uom_code;
1204        OPEN c_get_uom_code (p_unit_of_measure2);
1205        FETCH c_get_uom_code INTO l_uom_code2;
1206        CLOSE c_get_uom_code;
1207    ELSE
1208        l_uom_code1 := p_uom_code1;
1209        l_uom_code2 := p_uom_code2;
1210    END IF;
1211 
1212 
1213    /*===============================
1214         Convert qty 1 to qty2.
1215      ===============================*/
1216    l_converted_qty := inv_um_convert(p_inventory_item_id, p_lot_number,
1217                       p_organization_id, x_precision, p_quantity,
1218                       l_uom_code1, l_uom_code2, NULL, NULL);
1219    if (l_debug = 1) then
1220       print_debug('l_converted_sec_qty: '||l_converted_qty , l_procname);
1221    end if;
1222 
1223    IF (l_converted_qty = -99999) THEN
1224       RAISE INVALID_UOM_CONV;
1225    END IF;
1226 
1227    /*====================================
1228       If the secondary default is fixed
1229       make sure the quantities match.
1230      ====================================*/
1231    IF (INV_CACHE.item_rec.secondary_default_ind = 'F' AND
1232          p_quantity2 <> l_converted_qty) THEN
1233       RAISE INCORRECT_FIXED_VALUE;
1234    END IF;
1235 
1236    /*=================================
1237       Compute upper/lower boundaries.
1238      =================================*/
1239 
1240    l_high_boundary :=
1241 l_converted_qty * (1 + (INV_CACHE.item_rec.dual_uom_deviation_high/100));
1242    l_low_boundary  :=
1243 l_converted_qty * (1 - (INV_CACHE.item_rec.dual_uom_deviation_low/100));
1244 
1245    if (l_debug = 1) then
1246       print_debug('Is '||p_quantity2 ||' between '|| l_low_boundary ||' and '||l_high_boundary ||'?', l_procname);
1247    end if;
1248 
1249    /*=============================================================
1250       Check if qty2  is within boundaries allowing for precision.
1251      =============================================================*/
1252 
1253    IF ((l_low_boundary - p_quantity2) > power(10,-(x_precision-1)) ) THEN
1254       RAISE DEV_LOW_ERROR;
1255    END IF;
1256    IF ((p_quantity2 - l_high_boundary) > power(10,-(x_precision-1)) ) THEN
1257       RAISE DEV_HIGH_ERROR;
1258    END IF;
1259 
1260 END IF;
1261 
1262 RETURN G_TRUE;
1263 
1264 
1265 
1266 EXCEPTION
1267     WHEN INVALID_ITEM THEN
1268        FND_MESSAGE.SET_NAME('INV','INV_INVALID_ITEM');
1269        FND_MSG_PUB.ADD;
1270        RETURN G_FALSE;
1271     WHEN INCORRECT_FIXED_VALUE THEN
1272        FND_MESSAGE.SET_NAME('INV','INV_INCORRECT_FIXED_VALUE');
1273        FND_MSG_PUB.ADD;
1274        RETURN G_FALSE;
1275     WHEN INVALID_UOM_CONV THEN
1276        FND_MESSAGE.SET_NAME('INV','INV_INVALID_UOM_CONV');
1277        FND_MESSAGE.SET_TOKEN ('VALUE1',l_uom_code1);
1278        FND_MESSAGE.SET_TOKEN ('VALUE2',l_uom_code2);
1279        FND_MSG_PUB.ADD;
1280        RETURN G_FALSE;
1281     WHEN DEV_LOW_ERROR THEN
1282        FND_MESSAGE.SET_NAME('INV','INV_DEVIATION_LO_ERR');
1283        FND_MSG_PUB.ADD;
1284        RETURN G_FALSE;
1285     WHEN DEV_HIGH_ERROR THEN
1286        FND_MESSAGE.SET_NAME('INV','INV_DEVIATION_HI_ERR');
1287        FND_MSG_PUB.ADD;
1288        RETURN G_FALSE;
1289     WHEN OTHERS THEN
1290        RETURN G_FALSE;
1291 
1292 
1293 END within_deviation;
1294 
1295 --Added for bug 6761510 for caching of uom conversion
1296 FUNCTION inv_um_convert(p_item_id       IN NUMBER,
1297                         p_from_uom_code IN VARCHAR2,
1298                         p_to_uom_code   IN VARCHAR2) RETURN NUMBER
1299    IS
1300 
1301       l_conversion_rate NUMBER;
1302       l_debug              NUMBER      := NVL(fnd_profile.VALUE('INV_DEBUG_TRACE'), 0);
1303       l_api_name    CONSTANT VARCHAR2(30) := 'inv_um_convert';
1304 
1305    BEGIN
1306       IF (p_from_uom_code = p_to_uom_code) THEN
1307          -- No conversion necessary
1308          l_conversion_rate := 1;
1309       ELSE
1310          -- Check if the conversion rate for the item/from UOM/to UOM combination is cached
1311          IF (g_item_uom_conversion_tb.EXISTS(p_item_id) AND
1312             g_item_uom_conversion_tb(p_item_id).EXISTS(p_from_uom_code) AND
1313             g_item_uom_conversion_tb(p_item_id)(p_from_uom_code).EXISTS(p_to_uom_code)) THEN
1314             -- Conversion rate is cached so just use the value
1315             l_conversion_rate := g_item_uom_conversion_tb(p_item_id)(p_from_uom_code)(p_to_uom_code);
1316          ELSE
1317             -- Conversion rate is not cached so query and store the value
1318             inv_convert.inv_um_conversion(from_unit => p_from_uom_code,
1319                                           to_unit   => p_to_uom_code,
1320                                           item_id   => p_item_id,
1321                                           uom_rate  => l_conversion_rate);
1322             IF (l_conversion_rate > 0) THEN
1323                -- Store the conversion rate and also the reverse conversion.
1324                -- Do this only if the conversion rate returned is valid, i.e. not negative.
1325                -- {{
1326                -- Test having an exception when retrieving the UOM conversion rate. }}
1327                g_item_uom_conversion_tb(p_item_id)(p_from_uom_code)(p_to_uom_code) := l_conversion_rate;
1328                g_item_uom_conversion_tb(p_item_id)(p_to_uom_code)(p_from_uom_code) := 1 /l_conversion_rate;
1329             END IF;
1330          END IF;
1331       END IF;
1332 
1333       -- Return the conversion rate retrieved
1334       RETURN l_conversion_rate;
1335 
1336    EXCEPTION
1337    WHEN OTHERS THEN
1338       IF l_debug = 1 THEN
1339          print_debug(l_api_name || 'Exception in inv_um_convert ' || sqlcode || ', ' || sqlerrm, 1);
1340       END IF;
1341       -- If an exception occurs, return a negative value.
1342       -- The calling program should interpret this as an exception in retrieving
1343       -- the UOM conversion rate.
1344       RETURN -999;
1345 END inv_um_convert;
1346 
1347 
1348 END inv_convert;