DBA Data[Home] [Help]

PACKAGE BODY: APPS.INV_DECIMALS_PUB

Source


1 PACKAGE BODY inv_decimals_pub AS
2 /* $Header: INVDECPB.pls 120.3 2005/07/12 02:05:58 varajago noship $ */
3 
4 
5 /*--------------------------------------------------------------------------+
6  |Procedure validate_compare_quantities(..)
7  |Returns the quantity converted from the first UOM in the second UOM.
8  |If quantities in 2 UOMs are already available, then this procedure will
9  |compare and validate these quantities based on conversion rates
10  |and UOM and decimal qty controls. This procedure may be used to validate
11  |scenarios where quatities are entered in dual UOMs. We want to make sure
12  |quantities are valid based on conversion, and conversion
13  |rate tolerances.
14  |
15  |Procedure validate_and_compare(
16  |p_api_version_number		IN	NUMBER, -- version # of API
17  |p_init_msg_list		IN	VARCHAR2, -- whether to initialize list
18  |p_inventory_item_id		IN	NUMBER, -- inventory_item_id
19  |p_organization_id		IN	NUMBER, -- organization_id
20  |p_lot_control_code		IN	NUMBER, -- item's lot control code
21  |p_lot_number			IN	VARCHAR2, -- lot number
22  |p_sub_lot_control_code	IN	NUMBER, --sub lot control code
23  |p_sublot_number		IN	VARCHAR2, -- sublot number
24  |p_from_quantity		IN	NUMBER, -- qty in first UOM
25  |p_from_uom_code		IN	VARCHAR2, -- UOM of fisrt qty
26  |p_to_uom_code			IN	VARCHAR2, -- UOM of second qty
27  |p_to_quantity_to_check	IN	NUMBER, -- qty in second UOM
28  |x_resultant_to_quantity OUT NOCOPY  NUMBER, -- calculated qty in second UOM
29  |x_comparison		 OUT NOCOPY  NUMBER,--Possible values are 1,0,-1,-99
30  |x_msg_count		 OUT NOCOPY  NUMBER, -- number of messages
31  |x_msg_data		 OUT NOCOPY  VARCHAR2, -- populated,if msg count = 1
32  |x_return_status	 OUT NOCOPY  VARCHAR2) -- return status
33  |
34  |Note: The comparisons are done in base UOM
35  | of the UOM class to which the first UOM belongs. x_comparison returns:
36  |-1		if from_quantity is less than to_quantity (A < B)
37  | 0		if from_quantity is equal to to_quantity (A = B)
38  | 1		if from_quantity is greater than to_quantity (A > B)
39  | -99	if the validations for the first/second quantity failed
40  | If the UOMs belong to different classes, then users can specify whether
41  | they want to use the effective interclass UOM conversion tolerance, say, T.
42  | CASE: p_use_interclass_tolerance = 1
43  | ------
44  | Q1 > Q2 if (Q1 - Q2) >= T
45  | Q1 = Q2 if ABS(Q1 - Q2) < T
46  | Q1 < Q2 if (Q1 - Q2 ) <= -T
47  |
48  |The output variable x_resultant_to_quantity will contain the converted
49  |quantity
50  |in the second UOM, using effective conversion rates.
51  |Usage: In a dual UOM scenario, this api will confirm whether quantities in
52  |the two UOMs are equal or not, based on x_comparison output variable.
53  +--------------------------------------------------------------------------*/
54 
55 -- Package Globals
56 -- a warning exception
57 	g_inv_warning	exception ;
58 	g_ret_warning	CONSTANT	VARCHAR2(1):= 'W';
59 
60 
61    g_package_name		CONSTANT	VARCHAR2(50) := 'INV_DECIMALS';
62    g_max_decimal_digits	CONSTANT	NUMBER := 9 ;
63    g_max_real_digits	CONSTANT	NUMBER := 10 ;
64    g_max_total_digits	CONSTANT	NUMBER := 19 ;
65 
66 Procedure validate_compare_quantities(
67 		p_api_version_number	IN	NUMBER,
68 		p_init_msg_list		IN	VARCHAR2 DEFAULT FND_API.G_FALSE,
69 		p_inventory_item_id	IN	NUMBER,
70 		p_organization_id	IN	NUMBER,
71 		p_lot_control_code	IN	NUMBER,
72 		p_lot_number		IN	VARCHAR2,
73  		p_sub_lot_control_code	IN	NUMBER,
74  		p_sublot_number		IN	VARCHAR2,
75 		p_from_quantity		IN	NUMBER,
76 		p_from_uom_code		IN	VARCHAR2,
77 		p_to_uom_code		IN	VARCHAR2,
78 		p_to_quantity_to_check	IN	NUMBER,
79 		x_resultant_to_quantity	OUT NOCOPY	NUMBER,
80 		x_valid_conversion	OUT NOCOPY	NUMBER,
81  		x_msg_count		OUT NOCOPY	NUMBER,
82  		x_msg_data		OUT NOCOPY	VARCHAR2,
83 		x_return_status		OUT NOCOPY	VARCHAR2) IS
84 
85 BEGIN
86 
87 null;
88 
89 end validate_compare_quantities ;
90 
91 
92 /*--------------------------------------------------------------------------+
93  |Function convert_UOM(..) return NUMBER ;
94  |Returns the quantity converted from the first unit into the second unit.
95  |If conversion is not possible, return status is failure.
96  |Function convert(
97  |p_api_version_number		IN	NUMBER,
98  |p_init_msg_list		IN	VARCHAR2, -- whether to initialize list
99  |p_inventory_item_id		IN	NUMBER, -- inventory_item_id
100  |p_organization_id		IN	NUMBER, -- organization_id
101  |p_lot_control_code		IN	NUMBER, -- item's lot control code
102  |p_lot_number			IN	VARCHAR2, -- lot number
103  |p_sub_lot_control_code	IN	NUMBER,
104  |p_sublot_number		IN	VARCHAR2,
105  |p_from_quantity		IN	NUMBER, -- qty in first UOM
106  |p_from_uom_code		IN	VARCHAR2, -- UOM of fisrt qty
107  |p_to_uom_code			IN	VARCHAR2, -- UOM of second qty
108  |x_msg_count		 OUT NOCOPY  NUMBER,
109  |x_msg_data		 OUT NOCOPY  VARCHAR2,
110  |x_return_status	 OUT NOCOPY  VARCHAR2)
111  |					  return NUMBER ;
112  |If there is an error, then -99 is returned.
113  |1) From_quantity must be an absolute value.
114  |2) From_quantity will then converted to base UOM in the class,
115  |3) Then converted to base UOM of the
116  |   to_UOM class,
117  |4) Then converted to the quantity in to_UOM,
118  |5) Then rounded to 9 decimals
119  +--------------------------------------------------------------------------*/
120 
121 Function convert_UOM(
122 		p_api_version_number	IN	NUMBER,
123 		p_init_msg_list		IN	VARCHAR2 DEFAULT FND_API.G_FALSE,
124 		p_inventory_item_id	IN	NUMBER,
125 		p_organization_id	IN	NUMBER,
126 		p_lot_control_code	IN	NUMBER,
127 		p_lot_number		IN	VARCHAR2,
128 		p_sub_lot_control_code	IN	NUMBER,
129  		p_sublot_number		IN	VARCHAR2,
130 		p_from_quantity		IN	NUMBER,
131 		p_from_uom_code		IN	VARCHAR2,
132 		p_to_uom_code		IN	VARCHAR2,
133  		x_msg_count		OUT NOCOPY	NUMBER,
134  		x_msg_data		OUT NOCOPY	VARCHAR2,
135 		x_return_status		OUT NOCOPY	VARCHAR2) return NUMBER IS
136 
137 BEGIN
138 
139 return 0;
140 
141 end convert_uom ;
142 
143 
144 /*--------------------------------------------------------------------------+
145  | get_uom_properties(..)
146  | This procedure is used to interrogate the UOM.
147  | It returns:
148  | uom class, base uom.
149  | if the UOM is not found, the return status indicates this.
150  | Procedure get_uom_properties(
151  | p_api_version_number	IN	NUMBER,
152  | p_init_msg_list	IN	VARCHAR2,
153  | p_uom_code		IN	VARCHAR2,
154  | x_uom_class	 OUT NOCOPY  VARCHAR2,
155  | x_base_uom	 OUT NOCOPY  VARCHAR2,
156  | x_msg_count	 OUT NOCOPY  NUMBER,
157  | x_msg_data	 OUT NOCOPY  VARCHAR2,
158  | x_return_status OUT NOCOPY  VARCHAR2);
159  +--------------------------------------------------------------------------*/
160 
161 
162 Procedure get_uom_properties(
163   p_api_version_number	IN	NUMBER,
164   p_init_msg_list	IN	VARCHAR2 DEFAULT FND_API.G_FALSE,
165   p_uom_code		IN	VARCHAR2,
166   x_uom_class		OUT NOCOPY	VARCHAR2,
167   x_base_uom		OUT NOCOPY	VARCHAR2,
168   x_msg_count		OUT NOCOPY	NUMBER,
169   x_msg_data		OUT NOCOPY	VARCHAR2,
170   x_return_status	OUT NOCOPY	VARCHAR2) IS
171 
172 BEGIN
173 
174 null;
175 
176 end get_uom_properties ;
177 
178 
179 
180 /*-------------------------------------------------------------------------+
181  | Procedure compare_quantities(..)
182  | Procedure compare_quantities(
183  |	p_api_version_number		IN	NUMBER,
184  |	p_init_msg_list			IN	VARCHAR2,
185  | 	p_inventory_item_id		IN	NUMBER,
186  | 	p_organization_id		IN	NUMBER,
187  |	p_lot_control_code		IN	NUMBER,
188  | 	p_lot_number			IN	VARCHAR2,
189  |	p_sub_lot_control_code		IN	NUMBER,
190  |	p_sublot_number			IN	VARCHAR2,
191  | 	p_fisrt_qauantity		IN	NUMBER,
192  |	p_first_uom			IN	VARCHAR2,
193  |	p_second_quantity		IN	NUMBER,
194  | 	p_second_uom			IN	VARCHAR2,
195  |	p_use_interclass_tolerance	IN	VARCHAR2, -- Yes = 1, 2 = No
196  |	x_comaprison_result	 OUT NOCOPY  NUMBER,
197  |	x_msg_count		 OUT NOCOPY  NUMBER,
198  |	x_msg_data		 OUT NOCOPY  VARCHAR2,
199  |	x_return_status		 OUT NOCOPY  VARCHAR2);
200  |
201  | This procedure compares the quantities A and B and returns result in the
202  | output variable x_comparison_result. The comparisons are done in base UOM
203  | of the UOM class to which the first UOM belongs:
204  |-1		if quantity A is less than quantity B (A < B)
205  | 0		if quantity A is equal to quantity B (A = B)
206  | 1		if quantity A is greater than quantity B (A > B)
207  | If the UOMs belong to different classes, then users can specify whether
208  | they want to use interclass UOM conversion tolerance, say, T.
209  | CASE: p_use_interclass_tolerance = 1
210  | ------
211  | Q1 > Q2 if (Q1 - Q2) >= T
212  | Q1 = Q2 if ABS(Q1 - Q2) < T
213  | Q1 < Q2 if (Q1 - Q2 ) <= -T
214  +------------------------------------------------------------------------*/
215 
216  Procedure compare_quantities(
217 	p_api_version_number		IN	NUMBER,
218 	p_init_msg_list			IN	VARCHAR2 DEFAULT FND_API.G_FALSE,
219  	p_inventory_item_id		IN	NUMBER,
220  	p_organization_id		IN	NUMBER,
221 	p_lot_control_code		IN	NUMBER,
222 	p_lot_number			IN	VARCHAR2,
223 	p_sub_lot_control_code		IN	NUMBER,
224  	p_sublot_number			IN	VARCHAR2,
225  	p_fisrt_qauantity		IN	NUMBER,
226 	p_first_uom			IN	VARCHAR2,
227 	p_second_quantity		IN	NUMBER,
228  	p_second_uom			IN	VARCHAR2,
229 	p_use_interclass_tolerance	IN	VARCHAR2,
230 	x_comaprison_result		OUT NOCOPY	NUMBER,
231  	x_msg_count			OUT NOCOPY	NUMBER,
232  	x_msg_data			OUT NOCOPY	VARCHAR2,
233 	x_return_status			OUT NOCOPY	VARCHAR2) IS
234 
235 BEGIN
236 
237 null;
238 
239 end compare_quantities ;
240 
241 
242 
243 /*-----------------------------------------------------------------------+
244  | Procedure Validate_Quantity(
245  |	p_item_id			IN	NUMBER,
246  |	p_organization_id		IN	NUMBER,
247  |	p_input_quantity		IN	NUMBER,
248  |	p_UOM_code			IN	VARCHAR2,
249  |	x_output_quantity	 OUT NOCOPY  NUMBER,
250  |	x_primary_quantity	 OUT NOCOPY  NUMBER,
251  |	x_return_status		 OUT NOCOPY  VARCHAR2);
252  |
253  | Validates and returns the quantity in this manner (the caller does not need
254  | to adjust the result):
255  | This routine checks to make sure that the input quantity precision does not exceed
256  | the decimal precision. Max Precision is: 10 digits before the decimal point and
257  | 9 digits after the decimal point.
258  | The routine also makes sure that if the item is serial number controlled, then
259  | the quantity in primary UOM is an integer number.
260  | The routine also makes sure that if the item's indivisible_flag is set to yes,
261  | then the item quantity is an integer in the primary UOM.
262  | The routine also checks if the profile, INV:DETECT TRUNCATION, is set to yes
263  | the item quantity in primary UOM also obeys max precision and that it is not zero
264  | if the input quantity was not zero.
265  | The procedure retruns a correct output quantity in the transaction UOM, returns the
266  | the primary quantity (in priamry UOM, of course), and returns a status of success,failure
267  | or warning.
268  |
269  +-------------------------------------------------------------------------*/
270 
271 Procedure Validate_Quantity(
272 	p_item_id			IN	NUMBER,
273 	p_organization_id		IN	NUMBER,
274 	p_input_quantity		IN	NUMBER,
275 	p_UOM_code			IN	VARCHAR2,
276 	x_output_quantity		OUT NOCOPY	NUMBER,
277 	x_primary_quantity		OUT NOCOPY	NUMBER,
278 	x_return_status			OUT NOCOPY	VARCHAR2) IS
279 
280   -- Constants
281      c_api_version_number CONSTANT NUMBER  	:= 1.0 ;
282      c_api_name 	  CONSTANT VARCHAR2(50):= 'VALIDATE_QUANTITY';
283 
284   -- Variables
285      l_qty_string		VARCHAR2(50);
286      l_decimal_len 		NUMBER; -- number of decimal digits
287      l_real_len			NUMBER; -- number of digits before decimal point
288      l_total_len		NUMBER; -- total number of digits
289      l_uom_class		VARCHAR2(50); -- uom class name
290      l_base_uom			VARCHAR2(50); -- base uom in class
291      l_primary_uom		VARCHAR2(10); -- primary uom of item
292      l_highest_factor		NUMBER; -- biggest factor in class w.r.t uom
293      l_lowest_factor		NUMBER; -- lowest factor in class w.r.t. uom
294      l_conv_factor		NUMBER;
295      l_exp_factor		NUMBER;
296      l_decimal_profile		VARCHAR2(240);
297      l_serial_control		NUMBER ;
298      l_do_conversion		NUMBER := 1;
299      l_raise_warning		NUMBER := 0;
300      l_indivisible_flag		VARCHAR2(10):= 'N';
301 
302 BEGIN
303 
304   -- initialize return status to success
305      x_return_status := fnd_api.g_ret_sts_success;
306 
307  -- now make sure that # of decimal digits does not exceed g_max_decimal_digits
308     if ( p_input_quantity <> ROUND(p_input_quantity, g_max_decimal_digits)) then
309        fnd_message.set_name('INV', 'MAX_DECIMAL_LENGTH');
310        x_output_quantity := ROUND(p_input_quantity, g_max_decimal_digits);
311        l_raise_warning := 1 ;
312     else
313        if (x_output_quantity IS NULL) then
314            x_output_quantity := p_input_quantity;
315        end if;
316     end if;
317 
318   -- Now make sure that the length of real part of number doesn't exceed
319   -- g_max_real_digits
320     if ( trunc(abs(p_input_quantity)) > (POWER(10,g_max_real_digits) - 1) ) then
321        fnd_message.set_name('INV', 'MAX_REAL_LENGTH');
322        raise fnd_api.g_exc_error;
323      end if;
324 
325   -- now that in the given UOM the item quantity obeys the decimal precision rules
326   -- we can now make sure that when converted to primary qty, decimal precision
327   -- rules will still be obeyed.
328 
329 
330   -- get the item's primary uom, serial_number_control_code, and the item's indivisible flag
331 
332      SELECT primary_uom_code, serial_number_control_code, NVL(indivisible_flag,'N')
333      INTO l_primary_uom, l_serial_control, l_indivisible_flag
334      FROM mtl_system_items
335      WHERE inventory_item_id = p_item_id
336      AND organization_id = p_organization_id ;
337 
338      -- if the primary uom is same as input uom, then nothing more to validate
339      if ( l_primary_uom = p_uom_code) then
340        x_primary_quantity := p_input_quantity ;
341        l_do_conversion := 0;
342      end if;
343 
344      if ( l_do_conversion = 1 ) then
345        -- get the conversion rate. call inv_convert.uom_convert procedure.
346        -- NOTE: this convert routines ROUNDS (not truncates) to precision specified
347        l_conv_factor := inv_convert.inv_um_convert(
348         item_id		=> p_item_id,
349         precision	=> g_max_decimal_digits +2,
350         from_quantity   =>  p_input_quantity,
351         from_unit       => p_uom_code,
352         to_unit         => l_primary_uom,
353         from_name	=> null,
354         to_name	        => null);
355 
356        x_primary_quantity := l_conv_factor;
357 
358         -- Begin fix 2256336
359        IF x_primary_quantity <> TRUNC(x_primary_quantity) AND l_indivisible_flag = 'Y' THEN
360        l_conv_factor := inv_convert.inv_um_convert(
361         item_id         => p_item_id,
362         precision       => g_max_decimal_digits +2,
363         from_quantity   => 1,
364         from_unit       => l_primary_uom,
365         to_unit         => p_uom_code,
366         from_name       => null,
367         to_name         => null);
368         IF l_conv_factor <> 0 THEN
369          x_primary_quantity := p_input_quantity/l_conv_factor ;
370         END IF;
371        END IF;
372         -- End fix 2256336
373 
374 
375      -- check if the profile detect_truncation is set. If yes, then make sure primary qty
376      -- also does not break decimal precision rules.
377      fnd_profile.get('INV_DETECT_TRUNCATION',l_decimal_profile);
378 
379      if ( l_decimal_profile = '1' ) then -- '1'= yes, '2' = no
380 
381        if ( x_primary_quantity <> ROUND(x_primary_quantity,g_max_decimal_digits) ) then
382          fnd_message.set_name('INV', 'PRI_MAX_DECIMAL_LENGTH');
383 	 raise fnd_api.g_exc_error;
384        end if;
385 
386     -- Now make sure that the length of real part of number doesn't exceed
387     -- g_max_real_digits
388        if ( trunc(abs(x_primary_quantity)) > ( POWER(10,g_max_real_digits) - 1) ) then
389          fnd_message.set_name('INV', 'PRI_MAX_REAL_LENGTH');
390          raise fnd_api.g_exc_error;
391        end if;
392 
393      -- now check if the quantity in primary UOM is zero
394        if ( (x_primary_quantity = 0) AND (p_input_quantity <> 0) ) then
395          fnd_message.set_name('INV', 'PRI_QTY_IS_ZERO');
396          raise fnd_api.g_exc_error ;
397        end if;
398 
399      end if;
400 
401     end if;
402 
403     -- if item has indivisible flag set, then make sure that quantity is integer in
404     -- primary UOM
405 
406        if (( l_indivisible_flag = 'Y' ) AND ( Round(x_primary_quantity,(g_max_decimal_digits-1)) <> TRUNC(x_primary_quantity)) ) then
407          fnd_message.set_name('INV', 'DIVISIBILITY_VIOLATION');
408 	 raise fnd_api.g_exc_error ;
409        end if;
410 
411     -- if item is serial number controlled, make the qty in primary UOM is integer
412     -- Assumption: Whenever an item is unser serial number control, teh quantity must be
413     -- integer in primary uom. Even if specific serial may not be required at the time, the
414     -- qty of a serial number should be integer in primary uom.
415 
416        if ( (l_serial_control > 1 ) AND ( x_primary_quantity <> TRUNC(x_primary_quantity)) ) then
417          fnd_message.set_name('INV', 'SERIAL_QTY_VIOLATION');
418 	 raise fnd_api.g_exc_error ;
419        end if;
420 
421        if ( l_raise_warning = 1 ) then
422          raise g_inv_warning ;
423        end if;
424 
425  EXCEPTION
426        when fnd_api.g_exc_error then
427          x_return_status := fnd_api.g_ret_sts_error ;
428 
429        when fnd_api.g_exc_unexpected_error then
430          x_return_status := fnd_api.g_ret_sts_unexp_error;
431 
432        when g_inv_warning then
433 	 x_return_status := g_ret_warning ;
434 
435        when others then
436          x_return_status := fnd_api.g_ret_sts_unexp_error;
437 
438          if (fnd_msg_pub.check_msg_level
439            (fnd_msg_pub.g_msg_lvl_unexp_error))then
440            fnd_msg_pub.add_exc_msg(g_package_name,c_api_name);
441          end if;
442 
443 end validate_quantity ;
444 
445 /*-----------------------------------------------------------------------+
446  | Procedure Validate_Quantity(
447  |      p_item_id                       IN      NUMBER,
448  |      p_organization_id               IN      NUMBER,
449  |      p_input_quantity                IN      NUMBER,
450  |      p_UOM_code                      IN      VARCHAR2,
451  |      p_max_decimal_digits            IN      NUMBER,
452  |      x_output_quantity               OUT NOCOPY      NUMBER,
453  |      x_primary_quantity              OUT NOCOPY      NUMBER,
454  |      x_return_status                 OUT NOCOPY      VARCHAR2);
455  |
456  | This procedure overloads validate_quantity with one more parameter p_max_decimal_digits
457  | to adjust max precision. If the value of p_max_decimal_digits is null, then default
458  | it to g_max_decimal_digits. Other works the same as the above Validate_Quantity procedure.
459  +-------------------------------------------------------------------------*/
460 
461 Procedure Validate_Quantity(
462         p_item_id                       IN      NUMBER,
463         p_organization_id               IN      NUMBER,
464         p_input_quantity                IN      NUMBER,
465         p_UOM_code                      IN      VARCHAR2,
466         p_max_decimal_digits            IN      NUMBER,
467         p_primary_uom                   IN      VARCHAR2,
468         p_indivisible_flag              IN      VARCHAR2,
469         x_output_quantity               OUT NOCOPY   NUMBER,
470         x_primary_quantity              OUT NOCOPY   NUMBER,
471         x_return_status                 OUT NOCOPY   VARCHAR2) IS
472 
473   -- Constants
474      c_api_version_number CONSTANT NUMBER       := 1.0 ;
475      c_api_name           CONSTANT VARCHAR2(50):= 'VALIDATE_QUANTITY';
476 
477   -- Variables
478      l_qty_string               VARCHAR2(50);
479      l_decimal_len              NUMBER; -- number of decimal digits
480      l_real_len                 NUMBER; -- number of digits before decimal point
481      l_total_len                NUMBER; -- total number of digits
482      l_uom_class                VARCHAR2(50); -- uom class name
483      l_base_uom                 VARCHAR2(50); -- base uom in class
484      l_primary_uom              VARCHAR2(10) := p_primary_uom; -- primary uom of item
485      l_highest_factor           NUMBER; -- biggest factor in class w.r.t uom
486      l_lowest_factor            NUMBER; -- lowest factor in class w.r.t. uom
487      l_conv_factor              NUMBER;
488      l_exp_factor               NUMBER;
489      l_decimal_profile          VARCHAR2(240);
490      l_serial_control           NUMBER := 1;
491      l_do_conversion            NUMBER := 1;
492      l_raise_warning            NUMBER := 0;
493      l_indivisible_flag         VARCHAR2(10):= NVL(p_indivisible_flag, 'N');
494      l_max_decimal_digits       NUMBER := p_max_decimal_digits;
495 
496 BEGIN
497 
498   -- initialize return status to success
499      x_return_status := fnd_api.g_ret_sts_success;
500 
501   -- put the default = g_max_decimal_digits if l_max_decimal_digits is null
502      if (l_max_decimal_digits IS NULL) then
503          l_max_decimal_digits := g_max_decimal_digits;
504      end if;
505 
506   -- now make sure that # of decimal digits does not exceed l_max_decimal_digits
507     if ( p_input_quantity <> ROUND(p_input_quantity, l_max_decimal_digits)) then
508        fnd_message.set_name('INV', 'MAX_DECIMAL_LENGTH');
509        x_output_quantity := ROUND(p_input_quantity, l_max_decimal_digits);
510        l_raise_warning := 1 ;
511      else
512        if (x_output_quantity IS NULL) then
513            x_output_quantity := p_input_quantity;
514        end if;
515      end if;
516 
517   -- Now make sure that the length of real part of number doesn't exceed
518   -- g_max_real_digits
519     if ( trunc(abs(p_input_quantity)) > (POWER(10,g_max_real_digits) - 1) ) then
520        fnd_message.set_name('INV', 'MAX_REAL_LENGTH');
521        raise fnd_api.g_exc_error;
522      end if;
523 
524   -- now that in the given UOM the item quantity obeys the decimal precision rules
525   -- we can now make sure that when converted to primary qty, decimal precision
526   -- rules will still be obeyed.
527 
528 
529   -- get the item's primary uom, serial_number_control_code, and the item's indivisible flag
530   IF (p_item_id IS NOT NULL) then
531      SELECT primary_uom_code, serial_number_control_code, NVL(indivisible_flag,'N')
532      INTO l_primary_uom, l_serial_control, l_indivisible_flag
533      FROM mtl_system_items
534      WHERE inventory_item_id = p_item_id
535      AND organization_id = p_organization_id ;
536   END IF;
537 
538      -- if the primary uom is same as input uom, then nothing more to validate
539      if ( l_primary_uom = p_uom_code) then
540        x_primary_quantity := p_input_quantity ;
541        l_do_conversion := 0;
542      end if;
543 
544      if ( l_do_conversion = 1 ) then
545        -- get the conversion rate. call inv_convert.uom_convert procedure.
546        -- NOTE: this convert routines ROUNDS (not truncates) to precision specified
547        l_conv_factor := inv_convert.inv_um_convert(
548         item_id         => p_item_id,
549         precision       => l_max_decimal_digits +2,
550         from_quantity   => p_input_quantity,
551         from_unit       => p_uom_code,
552         to_unit         => l_primary_uom,
553         from_name       => null,
554         to_name         => null);
555 
556        x_primary_quantity := l_conv_factor ;
557 
558 
559      -- check if the profile detect_truncation is set. If yes, then make sure primary qty
560      -- also does not break decimal precision rules.
561      fnd_profile.get('INV_DETECT_TRUNCATION',l_decimal_profile);
562 
563      if ( l_decimal_profile = '1' ) then -- '1'= yes, '2' = no
564 
565        if ( x_primary_quantity <> ROUND(x_primary_quantity,l_max_decimal_digits) ) then
566          fnd_message.set_name('INV', 'PRI_MAX_DECIMAL_LENGTH');
567          raise fnd_api.g_exc_error;
568        end if;
569 
570     -- Now make sure that the length of real part of number doesn't exceed
571     -- g_max_real_digits
572        if ( trunc(abs(x_primary_quantity)) > ( POWER(10,g_max_real_digits) - 1) ) then
573          fnd_message.set_name('INV', 'PRI_MAX_REAL_LENGTH');
574          raise fnd_api.g_exc_error;
575        end if;
576 
577      -- now check if the quantity in primary UOM is zero
578        if ( (x_primary_quantity = 0) AND (p_input_quantity <> 0) ) then
579          fnd_message.set_name('INV', 'PRI_QTY_IS_ZERO');
580          raise fnd_api.g_exc_error ;
581        end if;
582 
583      end if;
584 
585     end if;
586 
587     -- if item has indivisible flag set, then make sure that quantity is integer in
588     -- primary UOM
589 
590        if (( l_indivisible_flag = 'Y' ) AND ( Round(x_primary_quantity,(l_max_decimal_digits-1)) <> TRUNC(x_primary_quantity)) ) then
591          fnd_message.set_name('INV', 'DIVISIBILITY_VIOLATION');
592          raise fnd_api.g_exc_error ;
593        end if;
594 
595     -- if item is serial number controlled, make the qty in primary UOM is integer
596     -- Assumption: Whenever an item is unser serial number control, teh quantity must be
597     -- integer in primary uom. Even if specific serial may not be required at the time, the
598     -- qty of a serial number should be integer in primary uom.
599 
600        if ( (l_serial_control > 1 ) AND ( x_primary_quantity <> TRUNC(x_primary_quantity)) ) then
601          fnd_message.set_name('INV', 'SERIAL_QTY_VIOLATION');
602          raise fnd_api.g_exc_error ;
603        end if;
604 
605        if ( l_raise_warning = 1 ) then
606          raise g_inv_warning ;
607        end if;
608 
609  EXCEPTION
610        when fnd_api.g_exc_error then
611          x_return_status := fnd_api.g_ret_sts_error ;
612 
613        when fnd_api.g_exc_unexpected_error then
614          x_return_status := fnd_api.g_ret_sts_unexp_error;
615 
616        when g_inv_warning then
617          x_return_status := g_ret_warning ;
618 
619        when others then
620          x_return_status := fnd_api.g_ret_sts_unexp_error;
621 
622          if (fnd_msg_pub.check_msg_level
623            (fnd_msg_pub.g_msg_lvl_unexp_error))then
624            fnd_msg_pub.add_exc_msg(g_package_name,c_api_name);
625          end if;
626 
627 end Validate_Quantity;
628 
629 
630 
631 function get_primary_quantity(
632 		p_organization_id	IN	NUMBER,
633 		p_inventory_item_id	IN	NUMBER,
634 		p_uom			IN	VARCHAR2,
635 		p_quantity		IN	NUMBER) return number IS
636 
637  -- local variables
638   l_primary_uom		VARCHAR2(10);
639 BEGIN
640      -- if input qty is null, assume 0, in which case we return 0 as converted
641      -- qty also
642      if ( ( p_quantity IS NULL ) OR (p_quantity = 0) ) then
643        return 0;
644      end if;
645 
646      SELECT primary_uom_code
647      INTO l_primary_uom
648      FROM mtl_system_items
649      WHERE inventory_item_id = p_inventory_item_id
650      AND organization_id = p_organization_id ;
651 
652 return( inv_convert.inv_um_convert(
653       item_id		=> p_inventory_item_id,
654       precision		=> 9,
655       from_quantity     => p_quantity,
656       from_unit         => p_uom,
657       to_unit           => l_primary_uom,
658       from_name		=> null,
659       to_name	        => null) );
660 end get_primary_quantity ;
661 
662 
663 end INV_DECIMALS_PUB;