DBA Data[Home] [Help]

PACKAGE BODY: APPS.MST_AUDIT_REP_EXCP

Source


1 PACKAGE BODY MST_AUDIT_REP_EXCP AS
2 /* $Header: MSTEAREB.pls 115.27 2004/05/05 21:40:19 jansanch noship $ */
3 
4   --global variables
5   distScaleFactor NUMBER;
6   avgDrvSpeed NUMBER;
7 	tp_time_uom VARCHAR2(3);
8   tp_distance_uom VARCHAR2(3);
9 	tp_dimension_uom VARCHAR2(3);
10 	tp_volume_uom VARCHAR2(3);
11   user_id NUMBER(15);
12 	tp_plan_id NUMBER;
13 	msg_seq_num NUMBER;
14 
15   PROCEDURE MissingLatLongCoordExcptn (plan_idIn NUMBER, userIdIn NUMBER) IS
16 		excptnId NUMBER;
17     dummyThreshold NUMBER;
18   BEGIN
19 	 	-- Delete previous occurrences of this exception in mst_exceptions and the details table
20 	 	DELETE FROM mst_exception_details
21 		WHERE plan_id = plan_idIn
22 			AND exception_type = 704;
23 
24   	DELETE FROM mst_exceptions
25 		WHERE plan_id = plan_idIn
26 			AND exception_type = 704;
27 
28 		--check if exception appears in mst_excep_preferences (it does not have a threshold but
29     --if it is enabled there should be an entry in that table with a dummy value for threshold).
30 		dummyThreshold := getExceptionThreshold(704,userIdIn);
31     --if no threshold found it means exception is disabled, so exit procedure
32     IF dummyThreshold  = -999 THEN
33       debug_output('exception calculation disabled');
34 			RETURN;
35     END IF;
36 
37 		--Create fresh entry for exception and keep exception_id for updates in details table
38 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
39                                 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
40 																CREATION_DATE)
41 												VALUES (mst_exceptions_s.nextval, plan_idIn, 700, 704, 0, userIdIn,
42 																userIdIn,-1,sysdate, sysdate);
43 
44 		SELECT exception_id INTO excptnId
45 		FROM mst_exceptions
46 		WHERE plan_id = plan_idIn
47 			AND exception_type = 704;
48 
49 		INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
50 																			 location_id,
51 																			 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
52 																			 CREATION_DATE, STATUS)
53 	  SELECT mst_exception_details_s.nextval, excptnId , plan_idIn, 704,
54 					 location_id,
55 					 userIdIn, userIdIn,-1,sysdate, sysdate, 3
56 		FROM (SELECT distinct wsh_location_id as location_id
57 				  FROM WSH_LOCATIONS loc,
58 							 MST_DELIVERY_DETAILS det
59 					WHERE det.plan_id = plan_idIn
60 						AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
61 						AND	( det.ship_from_location_id = loc.wsh_location_id
62 								 OR det.ship_to_location_id = loc.wsh_location_id)
63 						AND ( latitude is null OR longitude is null)
64 					UNION
65 					SELECT distinct wsh_location_id as location_id
66 					FROM FTE_LOCATION_PARAMETERS param,
67 							 WSH_LOCATIONS loc
68 					WHERE loc.wsh_location_id = param.location_id
69 						AND ( param.consolidation_allowed = 'Y'
70 								OR param.deconsolidation_allowed = 'Y'
71 								OR param.crossdocking_allowed = 'Y')
72 						AND ( loc.latitude is null OR loc.longitude is null));
73 
74 		--update count of this exception in mst_exceptions
75 		UPDATE mst_exceptions
76 		SET EXCEPTION_COUNT = (	select count(*)
77 														from mst_exception_details det
78 														where det.exception_id = excptnId)
79 		WHERE EXCEPTION_id = excptnId;
80 
81 		--in case no exception of this type was generate delete entry in mst_exceptions table
82 		DELETE FROM mst_exceptions
83 		WHERE exception_count = 0 and exception_id = excptnId;
84 
85 		COMMIT;
86 	END MissingLatLongCoordExcptn;
87 
88 
89 
90 
91 	PROCEDURE MissingDistanceDataExcptn (plan_idIn NUMBER, userIdIn NUMBER) IS
92 		excptnId NUMBER;
93     dummyThreshold NUMBER;
94 		distanceEnginePresent VARCHAR(10);
95   BEGIN
96 	 	-- Delete previous occurrences of this exception in mst_exceptions and the details table
97 	 	DELETE FROM mst_exception_details
98 		WHERE plan_id = plan_idIn
99 			AND exception_type = 900;
100 
101   	DELETE FROM mst_exceptions
102 		WHERE plan_id = plan_idIn
103 			AND exception_type = 900;
104 
105 		--Determine if distance engine is present (if it is not then no exception of this type should be generated)
106 		distanceEnginePresent := fnd_profile.value('MST_MILEAGE_ENGINE_AVAIL');
107 		IF distanceEnginePresent <> 'Y' THEN
108 			debug_output('No mileage engine present, no check for this exception. MST_MILEAGE_ENGINE_AVAIL=' || distanceEnginePresent);
109 			RETURN;
110 		END IF;
111 
112 
113 		--check if exception appears in mst_excep_preferences (it does not have a threshold but
114     --if it is enabled there should be an entry in that table with a dummy value for threshold).
115 		dummyThreshold := getExceptionThreshold(900,userIdIn);
116     --if no threshold found it means exception is disabled, so exit procedure
117     IF dummyThreshold  = -999 THEN
118       debug_output('exception calculation disabled');
119 			RETURN;
120     END IF;
121 
122 		--Create fresh entry for exception and keep exception_id for updates in details table
123 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
124                                 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
125 																CREATION_DATE)
126 												VALUES (mst_exceptions_s.nextval, plan_idIn, 900, 900, 0, userIdIn,
127 																userIdIn,-1,sysdate, sysdate);
128 
129 		SELECT exception_id INTO excptnId
130 		FROM mst_exceptions
131 		WHERE plan_id = plan_idIn
132 			AND exception_type = 900;
133 
134 
135 		--find ship_from or ship_to locations whose zip-code does not appear in the distance table
136 		INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
137 																			 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
138 																			 CREATION_DATE, STATUS,
139 																			 delivery_detail_id, delivery_id)
140 		SELECT mst_exception_details_s.nextval, excptnId , plan_idIn, 900,
141 			     userIdIn, userIdIn,-1,sysdate, sysdate,3,
142 					 delivery_detail_id, delivery_id
143 	  FROM ( SELECT DISTINCT det.delivery_detail_id AS delivery_detail_id, da.delivery_id AS delivery_id
144 					 FROM MST_DELIVERY_DETAILS det,
145 				 				MST_DELIVERY_ASSIGNMENTS da,
146 				 				WSH_REGION_LOCATIONS origReg,
147 				 				WSH_REGION_LOCATIONS destReg
148 					 WHERE det.PLAN_ID = plan_idIn
149 						AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
150 						AND det.delivery_detail_id = da.delivery_detail_id (+)
151 						AND da.parent_delivery_detail_id is null
152 						AND origReg.location_id = det.ship_from_location_id
153 						AND destReg.location_id = det.ship_to_location_id
154 
155 						--FTE_LOCATION_MILEAGES is distance table
156 						--key is <origin_id, destination_id,IDENTIFIER_TYPE>. Origin and destination are FK to WSH_REGIONS.
157             --IDENTIFIER_TYPE can be city or state (Anuj)
158 		  			AND NOT EXISTS (SELECT DISTANCE
159 														FROM FTE_LOCATION_MILEAGES
160 														WHERE origReg.region_id = origin_id
161 															AND destReg.region_id = destination_id));
162 
163 
164 		--update count of this exception in mst_exceptions
165 		UPDATE mst_exceptions
166 		SET EXCEPTION_COUNT = (	select count(*)
167 														from mst_exception_details det
168 														where det.exception_id = excptnId)
169 		WHERE EXCEPTION_id = excptnId;
170 
171 		--in case no exception of this type was generated delete entry in mst_exceptions table
172 		DELETE FROM mst_exceptions
173 		WHERE exception_count = 0 and exception_id = excptnId;
174 
175 		commit;
176 	END MissingDistanceDataExcptn;
177 
178 
179 
180   --Delivery lines with zero pieces, cube or weight
181 	PROCEDURE DL_with_zero_values (plan_idIn NUMBER, userIdIn NUMBER) IS
182   	excptnId NUMBER;
183     dummyThreshold NUMBER;
184   BEGIN
185   		--Delete previous occurrences of this exception in mst_exceptions and the details table
186     	DELETE FROM mst_exception_details
187   		WHERE plan_id = plan_idIn
188   			AND exception_type = 219;
189 
190     	DELETE FROM mst_exceptions
191   		WHERE plan_id = plan_idIn
192   			AND exception_type = 219;
193 
194   		--check if exception appears in mst_excep_preferences (it does not have a threshold but
195       --if it is enabled there should be an entry in that table with a dummy value for threshold).
196   		dummyThreshold := getExceptionThreshold(219,userIdIn);
197       --if no threshold found it means exception is disabled, so exit procedure
198       IF dummyThreshold  = -999 THEN
199         debug_output('exception calculation disabled');
200   			RETURN;
201       END IF;
202 
203   		--Create fresh entry for exception and keep exception_id for updates in details table
204   		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
205                                   created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
206   																CREATION_DATE)
207   												VALUES (mst_exceptions_s.nextval, plan_idIn, 200, 219, 0, userIdIn,
208   																userIdIn,-1,sysdate, sysdate);
209 
210   		SELECT exception_id INTO excptnId
211   		FROM mst_exceptions
212   		WHERE plan_id = plan_idIn
213   			AND exception_type = 219;
214 
215 
216   		--check highest level delivery lines for zero values in pieces, weight and volume
217   		INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
218   																			 delivery_detail_id, delivery_id,
219   																			 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
220   																			 CREATION_DATE, STATUS)
221   		SELECT mst_exception_details_s.nextval, excptnId , det.plan_id, 219,
222 						 det.delivery_detail_id, da.delivery_id,
223              userIdIn, userIdIn,-1,sysdate, sysdate,3
224   		FROM MST_DELIVERY_DETAILS det,
225   				 MST_DELIVERY_ASSIGNMENTS da
226   		WHERE det.plan_id = plan_idIn
227 				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
228   			AND det.delivery_detail_id = da.delivery_detail_id (+)
229   			AND da.parent_delivery_detail_id is null
230   			AND (	det.NET_WEIGHT = 0 OR det.NET_WEIGHT IS NULL
231   						OR det.VOLUME = 0 OR det.VOLUME IS NULL
232   						OR det.REQUESTED_QUANTITY = 0);
233 
234 
235   		--check for all items associated to delivery lines to see if they have zero cube or weight
236 /*
237   		INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
238   																			 delivery_detail_id,  delivery_id,
239   																			 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
240   																			 CREATION_DATE,STATUS)
241   		SELECT mst_exception_details_s.nextval, excptnId , det.plan_id,219,
242 						 det.delivery_detail_id, da.delivery_id,
243              userIdIn, userIdIn,-1,sysdate, sysdate,3
244   		FROM MST_DELIVERY_DETAILS det,
245   				 MTL_SYSTEM_ITEMS it,
246 					 MST_DELIVERY_ASSIGNMENTS da
247   		WHERE det.plan_id = plan_idIn
248 				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
249 				AND det.delivery_detail_id = da.delivery_detail_id (+)
250   			AND it.inventory_item_id = det.inventory_item_id
251   			AND it.organization_id = det.organization_id
252   			AND (	it.unit_volume = 0 OR it.unit_volume IS NULL
253   						OR it.unit_weight = 0 OR it.unit_weight IS NULL);
254   */
255 
256   		--update count of this exception in mst_exceptions
257   		UPDATE mst_exceptions
258   		SET EXCEPTION_COUNT = (	select count(*)
259   														from mst_exception_details det
260   														where det.exception_id = excptnId)
261   		WHERE EXCEPTION_id = excptnId;
262 
263 			--in case no exception of this type was generated delete entry in mst_exceptions table
264 			DELETE FROM mst_exceptions
265 			WHERE exception_count = 0 and exception_id = excptnId;
266 
267   		commit;
268   END DL_with_zero_values;
269 
270 
271 	PROCEDURE DimensionViolForPieceExcptn (plan_idIn NUMBER, userIdIn NUMBER) IS
272 		excptnId NUMBER; -- used to get the parent exception id when inserting records in exception details.
273 		deliveryId NUMBER;
274 --		total NUMBER; -- used to count occurrences of vehicles with infinite length, height and width.
275 		length NUMBER;
276 		width NUMBER;
277 		height NUMBER;
278 		maxDimV NUMBER; --maximum dimension of (length, widht, height) of biggest vehicle
279 		midDimV NUMBER; --volume (length * width * height) of the biggest vehicle
280 		minDimV NUMBER; --minimum dimension of (length, widht, height) of biggest vehicle
281 		maxDimP NUMBER; --maximum dimension of (length, widht, height) for the piece
282 		midDimP NUMBER; --volume (length * width * height) for the piece
283 		minDimP NUMBER; --minimum dimension of (length, widht, height) for the piece
284 		vehicle_dimension_uom_code VARCHAR2(3); -- UOM of length, width and height of vehicle
285 		p_conv_found BOOLEAN;
286 		p_conv_rate NUMBER;
287 		thresholdPct NUMBER;
288 
289 		--Allows access to the relevant pieces and their dimensions.
290 		CURSOR c_pieces IS
291 			SELECT det.delivery_detail_id,
292 						 IT.UNIT_LENGTH, IT.UNIT_WIDTH, IT.UNIT_HEIGHT, it.DIMENSION_UOM_CODE, it.inventory_item_id
293 			FROM 	MST_DELIVERY_DETAILS DET,
294 						MTL_SYSTEM_ITEMS IT
295 			WHERE IT.INVENTORY_ITEM_ID = DET.INVENTORY_ITEM_ID
296 				AND det.organization_id = it.organization_id
297 		    AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
298 				AND det.plan_id = plan_idIn;
299 
300 	BEGIN
301 		--clean previous exceptions of this type
302   	DELETE FROM mst_exception_details
303 		WHERE plan_id = plan_idIn
304 			AND exception_type = 902;
305 
306   	DELETE FROM mst_exceptions
307 		WHERE plan_id = plan_idIn
308 			AND exception_type = 902;
309 
310 		--get the threshold from mst_excep_preferences
311 		thresholdPct := getExceptionThreshold(902,userIdIn);
312     debug_output('thresholdPct='||thresholdPct);
313     --if no threshold found it means exception is disabled, so exit procedure
314     IF thresholdPct  = -999 THEN
315       debug_output('exception calculation disabled');
316 			RETURN;
317     END IF;
318 
319 		--find dimensions of vehicle with biggest volume
320 		BEGIN
321 			SELECT
322 				NVL(CONV_TO_UOM(vt.usable_length, si.dimension_uom_code, tp_dimension_uom, si.inventory_item_id),-99),
323 				NVL(CONV_TO_UOM(vt.usable_width, si.dimension_uom_code, tp_dimension_uom, si.inventory_item_id),-99),
324 				NVL(CONV_TO_UOM(vt.usable_height, si.dimension_uom_code, tp_dimension_uom, si.inventory_item_id),-99)
325 			INTO length, width, height
326 			FROM fte_vehicle_types vt,
327 					 mtl_system_items_b si
328 			WHERE vt.inventory_item_id = si.inventory_item_id
329 				AND vt.organization_id = si.organization_id
330 				AND vt.usable_length is not null
331 				AND vt.usable_width is not null
332 				AND vt.usable_height is not null
333 				AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
334     														 	 FROM wsh_carriers carr, wsh_carrier_services serv,
335 																				wsh_carrier_vehicle_types carrVeh
336 																	 WHERE carr.carrier_id = serv.carrier_id
337 																		AND serv.mode_of_transport like 'TRUCK'
338 																		AND carrVeh.carrier_id = carr.carrier_id)
339 				AND NVL(CONV_TO_UOM(si.internal_volume, si.volume_uom_code, tp_volume_uom, si.inventory_item_id),0) =
340 						(SELECT MAX(NVL(CONV_TO_UOM(si2.internal_volume, si2.volume_uom_code, tp_volume_uom, si2.inventory_item_id),0))
341 						 FROM fte_vehicle_types vt2,
342 								  mtl_system_items_b si2
343 						 WHERE vt2.inventory_item_id = si2.inventory_item_id
344 						   AND vt2.organization_id = si2.organization_id
345 							 AND vt2.usable_length is not null
346 							 AND vt2.usable_width is not null
347 							 AND vt2.usable_height is not null
348 							 AND vt2.vehicle_type_id IN (SELECT distinct vehicle_type_id
349     														 					FROM wsh_carriers carr, wsh_carrier_services serv,
350 																							wsh_carrier_vehicle_types carrVeh
351 																				 	WHERE carr.carrier_id = serv.carrier_id
352 																				 		AND serv.mode_of_transport like 'TRUCK'
353 																						AND carrVeh.carrier_id = carr.carrier_id))
354 			  AND ROWNUM = 1;  --we need to pick one vehicle
355 
356 	    EXCEPTION
357       	WHEN NO_DATA_FOUND THEN
358 					length := -99;
359 				  width := -99;
360 					height := -99;
361     END;
362 
363 
364 		--determine how many rows in fte_vehicle_types contain null in at least one of the dimension fields
365 --		SELECT COUNT(*) INTO total
366 --		FROM fte_vehicle_types vt,
367 --				mtl_system_items_b si
368 --		WHERE vt.inventory_item_id = si.inventory_item_id
369 --			AND vt.organization_id = si.organization_id
370 --			AND (usable_length IS NULL
371 --					OR usable_width IS NULL
372 --					OR usable_height IS NULL
373 --					OR dimension_uom_code IS NULL);
374 
375 		--if there is at least one record in vehicle_types with null (=-99) in one of its dimensions then assume
376 		--that vehicle has infinite capacity. Consequently, no exception of this type will be generated
377 		--On the other hand, if that count is zero then we check for the exception
378 --		IF total > 0 THEN
379 
380     debug_output('length='||length || ', width=' || width || ', height=' || height );
381     --We do not insert a row if count = 0
382 		IF length <> -99 AND width <> -99 AND height <> -99 THEN
383 			--Find max, med, and min of the three dimensions
384 			IF length > width AND length > height THEN
385 				maxDimV := length;
386 				SELECT GREATEST(width, height) INTO midDimV FROM dual;
387 				SELECT LEAST(width, height) INTO minDimV FROM dual;
388 			ELSE
389 				IF width > height THEN
390 					maxDimV := width;
391 					SELECT GREATEST(length, height) INTO midDimV FROM dual;
392 					SELECT LEAST(length, height) INTO minDimV FROM dual;
393 				ELSE
394 					maxDimV := height;
395 					SELECT GREATEST(width, length) INTO midDimV FROM dual;
396 					SELECT LEAST(width, length) INTO minDimV FROM dual;
397 				END IF;
398 			END IF;
399 
400       debug_output('maxDimV='||maxDimV || ', midDimV=' || midDimV || ', minDimV=' || minDimV );
401 
402 	    --insert entry in mst_exceptions
403 			INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
404 			                            created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
405 																  CREATION_DATE)
406 													VALUES (mst_exceptions_s.nextval, plan_idIn, 900, 902, 0,userIdIn,
407 																userIdIn,-1,sysdate, sysdate);
408 
409 			SELECT exception_id INTO excptnId
410 			FROM mst_exceptions
411 			WHERE plan_id = plan_idIn
412 				AND exception_type = 902;
413 
414 			FOR c1rec IN c_pieces LOOP
415 
416 				--Find max, med, and min of the three dimensions
417 				IF c1rec.UNIT_LENGTH > c1rec.UNIT_WIDTH AND c1rec.UNIT_LENGTH > c1rec.UNIT_HEIGHT THEN
418 					maxDimP := c1rec.UNIT_LENGTH;
419 					SELECT GREATEST(c1rec.UNIT_WIDTH, c1rec.UNIT_HEIGHT) INTO midDimP FROM dual;
420 					SELECT LEAST(c1rec.UNIT_WIDTH, c1rec.UNIT_HEIGHT) INTO minDimP FROM dual;
421 				ELSE
422 					IF c1rec.UNIT_WIDTH > c1rec.UNIT_HEIGHT THEN
423 					maxDimP := c1rec.UNIT_WIDTH;
424 					SELECT GREATEST(c1rec.UNIT_LENGTH, c1rec.UNIT_HEIGHT) INTO midDimP FROM dual;
425 					SELECT LEAST(c1rec.UNIT_LENGTH, c1rec.UNIT_HEIGHT) INTO minDimP FROM dual;
426 					ELSE
427 						maxDimP := c1rec.UNIT_HEIGHT;
428 						SELECT GREATEST(c1rec.UNIT_WIDTH, c1rec.UNIT_LENGTH) INTO midDimP FROM dual;
429 						SELECT LEAST(c1rec.UNIT_WIDTH, c1rec.UNIT_LENGTH) INTO minDimP FROM dual;
430 					END IF;
431 				END IF;
432 
433 				GET_UOM_CONVERSION_RATES(c1rec.dimension_uom_code,
434 																 tp_dimension_uom,
435 																 c1rec.inventory_item_id,
436 																 p_conv_found,
437 																 p_conv_rate);
438 				IF p_conv_found = true THEN
439 					maxDimP := maxDimP * p_conv_rate;
440 					minDimP := minDimP * p_conv_rate;
441 					midDimP := midDimP * p_conv_rate;
442 
443           IF 100*((maxDimP/maxDimV)-1)>thresholdPct
444 							OR  100*((minDimP/minDimV)-1)>thresholdPct
445 				  		OR  100*((midDimP/midDimV)-1)>thresholdPct THEN
446 							--obtain delivery_id
447               BEGIN
448   							SELECT da.delivery_id
449 		  					INTO deliveryId
450 				  			FROM mst_delivery_assignments da,
451 						  			 mst_delivery_details det
452   							WHERE det.delivery_detail_id = da.delivery_detail_id (+)
453 		  								AND det.plan_id = plan_idIn
454                       AND c1rec.delivery_detail_id = det.delivery_detail_id;
455                 EXCEPTION
456                   WHEN NO_DATA_FOUND THEN
457                     debug_output('delivery_detail_id could not be associated to delivery_id');
458                     deliveryId := NULL;
459                   WHEN TOO_MANY_ROWS THEN
460                     debug_output('delivery_detail_id associated to more than one delivery_id');
461                     deliveryId := NULL;
462               END;
463 
464               debug_output('delivery_detail_id=' || c1rec.delivery_detail_id || ', maxDimP='||maxDimP || ', midDimP=' || midDimP || ', minDimP=' || minDimP );
465 
466               --insert exceptions detected into mst_exception_details
467               INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id,
468                                                  exception_type, delivery_detail_id,
469                                                  delivery_id, number1, number2, number3, char1,
470                                                  created_by, last_updated_by, LAST_UPDATE_LOGIN,
471                                                  LAST_UPDATE_DATE, CREATION_DATE, STATUS)
472                                          VALUES (mst_exception_details_s.nextval, excptnId, plan_idIn,
473                                                  902, c1rec.delivery_detail_id,
474                                                  deliveryId, length, width, height, tp_dimension_uom,
475                                                  userIdIn, userIdIn,-1,sysdate, sysdate, 3);
476           END IF;
477         END IF;
478       END LOOP;
479 
480 			--update count of this exception in mst_exceptions
481 			UPDATE mst_exceptions
482 			SET EXCEPTION_COUNT = (	select count(*)
483 															from mst_exception_details det
484 															where det.exception_id = excptnId)
485 			WHERE EXCEPTION_id = excptnId;
486 
487   		--in case no exception of this type was generated delete entry in mst_exceptions table
488 		  DELETE FROM mst_exceptions
489   		WHERE exception_count = 0 and exception_id = excptnId;
490 		END IF;
491 
492 		COMMIT;
493 	END DimensionViolForPieceExcptn;
494 
495 
496 
497 	PROCEDURE WgtVolViolForPieceExcptn (plan_idIn NUMBER, userIdIn NUMBER) IS
498 		excptnId NUMBER; -- used to get the parent exception id when inserting records in exception details.
499 		maxVolumeV NUMBER; -- volume of the biggest vehicle available
500 		maxWeightV NUMBER; -- weight of the biggest vehicle available
501 		exceptionFlag BOOLEAN;
502 		tp_volume_uom VARCHAR2(3);
503 		tp_weight_uom VARCHAR2(3);
504 		thresholdPct NUMBER;
505 
506 --	  --Obtain pieces to check
507 --		CURSOR c_pieces IS
508 --			SELECT DELIVERY_DETAIL_ID,  det.inventory_item_id,
509 --						net_weight, si.unit_length, si.unit_width, si.unit_height,
510 --						requested_quantity, si.weight_uom_code, si.dimension_uom_code
511 --			FROM 	MST_DELIVERY_DETAILS det,
512 --						MTL_SYSTEM_ITEMS si
513 --			WHERE det.PLAN_ID = plan_idIn
514 --				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
515 --				AND det.requested_quantity = 1
516 --				AND det.inventory_item_id = si.inventory_item_id
517 --				AND det.organization_id = si.organization_id;
518 
519 	  --According to HLD (6/12/03) we need to check total weight and volume in delivery line for
520     --those delivery lines which consist of a package or pallet, or contain quantity = 1.
521 	  --Obtain delivery lines to be checked (weight and volume converted to tp uom)
522 		CURSOR c_pieces (tp_vol_uom VARCHAR2, tp_wgt_uom VARCHAR2) IS
523 			SELECT det.delivery_detail_id,  da.delivery_id,
524 						NVL(det.net_weight,0) weight,
525 						NVL(det.volume,0) volume
526 			FROM 	MST_DELIVERY_DETAILS det,
527 						MTL_SYSTEM_ITEMS si,
528 						MST_DELIVERY_ASSIGNMENTS da
529 			WHERE det.PLAN_ID = plan_idIn
530 				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
531 				AND det.delivery_detail_id = da.delivery_detail_id (+)
532 				AND (det.requested_quantity = 1 OR det.container_flag = 1)
533 				AND det.inventory_item_id = si.inventory_item_id
534 				AND det.organization_id = si.organization_id;
535 
536 		maxVolVehTypeId NUMBER;
537 		maxWgtVehTypeId NUMBER;
538 
539 	BEGIN
540 		--clean previous exceptions of this type
541   	DELETE FROM mst_exception_details
542 		WHERE plan_id = plan_idIn
543 			AND exception_type = 903;
544 
545   	DELETE FROM mst_exceptions
546 		WHERE plan_id = plan_idIn
547 			AND exception_type = 903;
548 
549 		--get the threshold from mst_excep_preferences
550     thresholdPct := getExceptionThreshold(903,userIdIn);
551     debug_output('thresholdPct='||thresholdPct);
552     --if no threshold found it means exception is disabled, so exit procedure
553     IF thresholdPct  = -999 THEN
554       debug_output('exception calculation disabled');
555 			RETURN;
556     END IF;
557 
558 		--get tp uoms from mst_plans
559 		SELECT weight_uom, volume_uom
560 		INTO   tp_weight_uom, tp_volume_uom
561 		FROM mst_plans
562 		WHERE plan_id = plan_idIn;
563 
564 
565 		--find vehicle with the biggest volume
566 		SELECT MAX(NVL(CONV_TO_UOM(si.internal_volume, si.volume_uom_code, tp_volume_uom, si.inventory_item_id),0)) as volume
567 		INTO maxVolumeV
568 		FROM fte_vehicle_types vt,
569 				 mtl_system_items_b si
570 		WHERE vt.inventory_item_id = si.inventory_item_id
571 		  AND vt.organization_id = si.organization_id
572 			AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
573     														 FROM wsh_carriers carr, wsh_carrier_services serv, wsh_carrier_vehicle_types carrVeh
574 																 WHERE carr.carrier_id = serv.carrier_id
575 																  AND serv.mode_of_transport like 'TRUCK'
576 																	AND carrVeh.carrier_id = carr.carrier_id);
577 
578 
579 		--find vehicle with the biggest weight
580 		SELECT MAX(NVL(CONV_TO_UOM(si.maximum_load_weight, si.weight_uom_code,tp_weight_uom, si.inventory_item_id),0)) as load_weight
581 		INTO maxWeightV
582 		FROM fte_vehicle_types vt,
583 				mtl_system_items_b si
584 		WHERE vt.inventory_item_id = si.inventory_item_id
585 			AND vt.organization_id = si.organization_id
586 			AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
587     														 FROM wsh_carriers carr, wsh_carrier_services serv, wsh_carrier_vehicle_types carrVeh
588 																 WHERE carr.carrier_id = serv.carrier_id
589 																  AND serv.mode_of_transport like 'TRUCK'
590 																	AND carrVeh.carrier_id = carr.carrier_id);
591 
592 
593 		debug_output('maxVolume = ' || maxVolumeV || ' ' || tp_volume_uom || ' (veh id=' || maxVolVehTypeId || ')' );
594  		debug_output('maxWeight = ' || maxWeightV || ' ' || tp_weight_uom || ' (veh id=' || maxWgtVehTypeId || ')' );
595 
596 	  --insert entry in mst_exceptions
597 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
598 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
599 																CREATION_DATE)
600 													VALUES (mst_exceptions_s.nextval, plan_idIn, 900, 903, 0, userIdIn,
601 																userIdIn,-1,sysdate, sysdate);
602 
603 
604 		SELECT exception_id INTO excptnId
605 		FROM mst_exceptions
606 		WHERE plan_id = plan_idIn
607 			AND exception_type = 903;
608 
609 		FOR piece IN c_pieces(tp_volume_uom,tp_weight_uom) LOOP
610 			exceptionFlag := false;
611 
612 			IF maxVolumeV > 0 THEN
613 				IF 100*((piece.volume/maxVolumeV)-1) > thresholdPct THEN
614 					exceptionFlag := true;
615 					--debug_output('Exception volume!!');
616 				END IF;
617 			END IF;
618 
619 			IF maxWeightV > 0 THEN
620 				IF 100*((piece.weight/maxWeightV)-1) > thresholdPct THEN
621 					exceptionFlag := true;
622 					--debug_output('Exception weight!!');
623 				END IF;
624 			END IF;
625 
626 			--if maxVolumeV = 0  or maxWeightV = 0 then we assume it is infinite and no exceptions is generated
627 			IF exceptionFlag = true THEN
628    			debug_output('delivery_detail_id = ' || TO_CHAR(piece.delivery_detail_id) || ', volume = ' || piece.volume || ', weight = ' || piece.weight);
629 
630 				--insert exception detected into mst_exception_details
631 				INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
632 																					 delivery_detail_id, delivery_id,
633 																					 number1, number2,
634 																					 char1, char2,
635 																					 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
636 																					 CREATION_DATE, STATUS)
637 																	 VALUES (mst_exception_details_s.nextval, excptnId , plan_idIn, 903,
638 																					 piece.delivery_detail_id, piece.delivery_id,
639 																					 maxWeightV, maxVolumeV,
640 																					 tp_weight_uom, tp_volume_uom,
641 																					 userIdIn, userIdIn,-1,sysdate, sysdate,3);
642 			END IF;
643 		END LOOP;
644 
645 		--update count of this exception in mst_exceptions
646 		UPDATE mst_exceptions
647 		SET EXCEPTION_COUNT = (	select count(*)
648 														from mst_exception_details det
649 														where det.exception_id = excptnId)
650 		WHERE EXCEPTION_id = excptnId;
651 
652   	--in case no exception of this type was generated delete entry in mst_exceptions table
653     DELETE FROM mst_exceptions
654     WHERE exception_count = 0 and exception_id = excptnId;
655 
656 		commit;
657 	END WgtVolViolForPieceExcptn;
658 
659 
660 	PROCEDURE WgtVolViolForDLExcptn (plan_idIn NUMBER, userIdIn NUMBER) IS
661 		excptnId NUMBER; -- used to get the parent exception id when inserting records in exception details.
662 		maxVolumeV NUMBER; -- volume of the biggest vehicle available
663 		maxWeightV NUMBER; -- weight of the biggest vehicle available
664 		exceptionFlag BOOLEAN;
665 		tp_weight_uom VARCHAR2(3);
666 		tp_volume_uom VARCHAR2(3);
667     thresholdPct NUMBER;
668 
669 		CURSOR c_DL (tp_vol_uom VARCHAR2, tp_wgt_uom VARCHAR2) IS
670 			SELECT det.delivery_detail_id,  da.delivery_id,
671 						 NVL(det.net_weight,0) weight,
672 						 NVL(det.volume,0) volume
673 			FROM 	MST_DELIVERY_DETAILS det,
674 						MTL_SYSTEM_ITEMS si,
675 						MST_DELIVERY_ASSIGNMENTS da
676 			WHERE det.PLAN_ID = plan_idIn
677 				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
678 				AND det.delivery_detail_id = da.delivery_detail_id (+)
679 				AND det.requested_quantity > 1
680 				AND det.inventory_item_id = si.inventory_item_id
681 				AND det.organization_id = si.organization_id;
682 
683 	BEGIN
684 		--clean previous exceptions of this type
685   	DELETE FROM mst_exception_details
686 		WHERE plan_id = plan_idIn
687 			AND exception_type = 904;
688 
689   	DELETE FROM mst_exceptions
690 		WHERE plan_id = plan_idIn
691 			AND exception_type = 904;
692 
693     --get the threshold from mst_excep_preferences
694 	  thresholdPct := getExceptionThreshold(904,userIdIn);
695     debug_output('thresholdPct='||thresholdPct);
696     --if no threshold found it means exception is disabled, so exit procedure
697     IF thresholdPct  = -999 THEN
698       debug_output('exception calculation disabled');
699 			RETURN;
700     END IF;
701 
702 
703 		--get tp uoms from mst_plans
704 		SELECT weight_uom, volume_uom
705 		INTO   tp_weight_uom, tp_volume_uom
706 		FROM mst_plans
707 		WHERE plan_id = plan_idIn;
708 
709 
710 /* Debug query
711  SELECT si.internal_volume as volume,  si.volume_uom_code, VEHICLE_TYPE_ID, vt.inventory_item_id , vt.organization_id
712                 FROM fte_vehicle_types vt,
713                      mtl_system_items_b si
714                 WHERE vt.inventory_item_id = si.inventory_item_id
715                         AND vt.organization_id = si.organization_id
716                         AND vt.vehicle_type_id in (select distinct vehicle_type_id
717                                                    from wsh_carriers carr, wsh_carrier_services serv, WSH_CARRIER_VEHICLE_TYPES carrVeh
718                                                     where carr.carrier_id = serv.carrier_id
719                                                     and serv.mode_of_transport like 'TRUCK'
720                                                     and carrVeh.carrier_id = carr.carrier_id)
721                         AND si.internal_volume  =
722                                         (SELECT MAX(si.internal_volume) as volume
723                                         FROM fte_vehicle_types vt,
724                                                          mtl_system_items_b si
725                                         WHERE vt.inventory_item_id = si.inventory_item_id
726                                         AND vt.organization_id = si.organization_id
727                                         AND vt.vehicle_type_id in (select distinct vehicle_type_id
728                                                                    from wsh_carriers carr, wsh_carrier_services serv, WSH_CARRIER_VEHICLE_TYPES carrVeh
729                                                                    where carr.carrier_id = serv.carrier_id
730                                                                     and serv.mode_of_transport like 'TRUCK'
731                                                                     and carrVeh.carrier_id = carr.carrier_id))
732                         AND ROWNUM = 1;
733 */
734 
735 		--find vehicle with the biggest volume
736 		SELECT MAX(NVL(CONV_TO_UOM(si.internal_volume, si.volume_uom_code, tp_volume_uom, si.inventory_item_id),0)) as volume
737 		INTO maxVolumeV
738 		FROM fte_vehicle_types vt,
739 				 mtl_system_items_b si
740 		WHERE vt.inventory_item_id = si.inventory_item_id
741 		  AND vt.organization_id = si.organization_id
742 			AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
743     														 FROM wsh_carriers carr, wsh_carrier_services serv, wsh_carrier_vehicle_types carrVeh
744 																 WHERE carr.carrier_id = serv.carrier_id
745 																  AND serv.mode_of_transport like 'TRUCK'
746 																	AND carrVeh.carrier_id = carr.carrier_id);
747 
748 
749 		--find vehicle with the biggest weight
750 		SELECT MAX(NVL(CONV_TO_UOM(si.maximum_load_weight, si.weight_uom_code,tp_weight_uom, si.inventory_item_id),0)) as load_weight
751 		INTO maxWeightV
752 		FROM fte_vehicle_types vt,
753 				mtl_system_items_b si
754 		WHERE vt.inventory_item_id = si.inventory_item_id
755 			AND vt.organization_id = si.organization_id
756 			AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
757     														 FROM wsh_carriers carr, wsh_carrier_services serv, wsh_carrier_vehicle_types carrVeh
758 																 WHERE carr.carrier_id = serv.carrier_id
759 																  AND serv.mode_of_transport like 'TRUCK'
760 																	AND carrVeh.carrier_id = carr.carrier_id);
761 
762 
763 		debug_output('maxVolume = ' || maxVolumeV || ' ' || tp_volume_uom || ', maxWeight = ' || maxWeightV || ' ' || tp_weight_uom);
764 
765 	  --insert entry in mst_exceptions
766 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
767 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
768 																CREATION_DATE)
769 													VALUES (mst_exceptions_s.nextval, plan_idIn, 900, 904, 0, userIdIn,
770 																userIdIn,-1,sysdate, sysdate);
771 
772 		SELECT exception_id INTO excptnId
773 		FROM mst_exceptions
774 		WHERE plan_id = plan_idIn
775 			AND exception_type = 904;
776 
777 		FOR deliveryLine IN c_DL(tp_volume_uom, tp_weight_uom) LOOP
778 
779 			exceptionFlag := false;
780 			IF maxVolumeV > 0 THEN
781 				-- debug_output('volumeDL ' || TO_CHAR(deliveryLine.volume));
782 				IF 100*((deliveryLine.volume/maxVolumeV)-1) > thresholdPct THEN
783 					exceptionFlag := true;
784 					-- debug_output('Exception volume!!');
785 				END IF;
786 			END IF;
787 
788 			IF maxWeightV > 0 THEN
789         -- debug_output('weightDL ' || TO_CHAR(deliveryLine.weight));
790 				IF 100*((deliveryLine.weight/maxWeightV)-1) > thresholdPct THEN
791 					exceptionFlag := true;
792 					-- debug_output('Exception weight!!');
793 				END IF;
794 			END IF;
795 
796 			IF exceptionFlag = true THEN
797 				--insert exception detected into mst_exception_details
798    			debug_output('delivery_detail_id = ' || TO_CHAR(deliveryLine.DELIVERY_DETAIL_ID) || ', volume = ' || deliveryLine.volume || ', weight = ' || deliveryLine.weight);
799 
800 				INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
801 																					 delivery_detail_id, delivery_id,
802 																					 number1, number2, char1, char2,
803 																					 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
804 																					 CREATION_DATE, STATUS)
805 																	 VALUES (mst_exception_details_s.nextval, excptnId , plan_idIn, 904,
806 																					 deliveryLine.DELIVERY_DETAIL_ID, deliveryLine.delivery_id,
807 																					 maxWeightV, maxVolumeV, tp_weight_uom, tp_volume_uom,
808 																					 userIdIn, userIdIn,-1,sysdate, sysdate, 3);
809 			END IF;
810 		END LOOP;
811 
812 
813 		--update count of this exception in mst_exceptions
814 		UPDATE mst_exceptions
815 		SET EXCEPTION_COUNT = (	select count(*)
816 														from mst_exception_details det
817 														where det.exception_id = excptnId)
818 		WHERE EXCEPTION_id = excptnId;
819 
820 		--in case no exception of this type was generated delete entry in mst_exceptions table
821 	  DELETE FROM mst_exceptions
822  		WHERE exception_count = 0 and exception_id = excptnId;
823 
824 		commit;
825 	END WgtVolViolForDLExcptn;
826 
827 
828 
829 
830 	PROCEDURE WgtVolViolForFirmDelivExcptn (plan_idIn NUMBER, userIdIn NUMBER) IS
831 		excptnId NUMBER; -- used to get the parent exception id when inserting records in exception details.
832 		maxVolumeV NUMBER; -- volume of the biggest vehicle available
833 		maxWeightV NUMBER; -- weight of the biggest vehicle available
834 		exceptionFlag BOOLEAN;
835 		tp_weight_uom VARCHAR2(3);
836 		tp_volume_uom VARCHAR2(3);
837     thresholdPct NUMBER;
838 
839 		CURSOR c_firmDel IS
840 			SELECT delivery_id, NVL(gross_weight,0) weight, NVL(volume,0) volume
841 			FROM 	MST_DELIVERIES
842 			WHERE PLAN_ID = plan_idIn
843 				AND (PLANNED_FLAG <> 2
844 						 OR PRESERVE_GROUPING_FLAG <> 2
845 						 OR KNOWN_TE_FIRM_STATUS <> 3);
846 	BEGIN
847 		--clean previous exceptions of this type
848   	DELETE FROM mst_exception_details
849 		WHERE plan_id = plan_idIn
850 			AND exception_type = 905;
851 
852   	DELETE FROM mst_exceptions
853 		WHERE plan_id = plan_idIn
854 			AND exception_type = 905;
855 
856     --get the threshold from mst_excep_preferences
857 	  thresholdPct := getExceptionThreshold(905,userIdIn);
858     debug_output('thresholdPct='||thresholdPct);
859     --if no threshold found it means exception is disabled, so exit procedure
860     IF thresholdPct  = -999 THEN
861       debug_output('exception calculation disabled');
862 			RETURN;
863     END IF;
864 
865 
866 		--get tp uoms from mst_plans
867 		SELECT weight_uom, volume_uom
868 		INTO   tp_weight_uom, tp_volume_uom
869 		FROM mst_plans
870 		WHERE plan_id = plan_idIn;
871 
872 		--find vehicle with the biggest volume
873 		SELECT MAX(NVL(CONV_TO_UOM(si.internal_volume, si.volume_uom_code, tp_volume_uom, si.inventory_item_id),0)) as volume
874 		INTO maxVolumeV
875 		FROM fte_vehicle_types vt,
876 				 mtl_system_items_b si
877 		WHERE vt.inventory_item_id = si.inventory_item_id
878 		  AND vt.organization_id = si.organization_id
879 			AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
880     														 FROM wsh_carriers carr, wsh_carrier_services serv, wsh_carrier_vehicle_types carrVeh
881 																 WHERE carr.carrier_id = serv.carrier_id
882 																  AND serv.mode_of_transport like 'TRUCK'
883 																	AND carrVeh.carrier_id = carr.carrier_id);
884 
885 
886 		--find vehicle with the biggest weight
887 		SELECT MAX(NVL(CONV_TO_UOM(si.maximum_load_weight, si.weight_uom_code,tp_weight_uom, si.inventory_item_id),0)) as load_weight
888 		INTO maxWeightV
889 		FROM fte_vehicle_types vt,
890 				mtl_system_items_b si
891 		WHERE vt.inventory_item_id = si.inventory_item_id
892 			AND vt.organization_id = si.organization_id
893 			AND vt.vehicle_type_id IN (SELECT distinct vehicle_type_id
894     														 FROM wsh_carriers carr, wsh_carrier_services serv, wsh_carrier_vehicle_types carrVeh
895 																 WHERE carr.carrier_id = serv.carrier_id
896 																  AND serv.mode_of_transport like 'TRUCK'
897 																	AND carrVeh.carrier_id = carr.carrier_id);
898 
899 
900 		debug_output('maxVolume = ' || maxVolumeV || ' ' || tp_volume_uom || ', maxWeight = ' || maxWeightV || ' ' || tp_weight_uom);
901 
902 	  --insert entry in mst_exceptions
903 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
904 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
905 																CREATION_DATE)
906 													VALUES (mst_exceptions_s.nextval, plan_idIn, 900, 905, 0, userIdIn,
907 																userIdIn,-1,sysdate, sysdate);
908 
909 		SELECT exception_id INTO excptnId
910 		FROM mst_exceptions
911 		WHERE plan_id = plan_idIn
912 			AND exception_type = 905;
913 
914 		FOR delivery IN c_firmDel LOOP
915 			debug_output('deliv=' || TO_CHAR(delivery.delivery_id) ||
916 									 ', volume=' || TO_CHAR(delivery.volume) ||
917 									 ', weight=' || TO_CHAR(delivery.weight));
918 			exceptionFlag := false;
919 			IF maxVolumeV > 0 THEN
920 				IF 100*((delivery.volume/maxVolumeV)-1) > thresholdPct THEN
921 					exceptionFlag := true;
922 					--debug_output('Exception volume!!');
923 				END IF;
924 			END IF;
925 
926 			IF maxWeightV > 0 THEN
927 				IF 100*((delivery.weight/maxWeightV)-1) > thresholdPct THEN
928 					exceptionFlag := true;
929 					--debug_output('Exception weight!!');
930 				END IF;
931 			END IF;
932 
933 			IF exceptionFlag = true THEN
934 				--insert exception detected into mst_exception_details
935    			debug_output('delivery_id = ' || TO_CHAR(delivery.DELIVERY_ID) || ', volume = ' || delivery.volume || ', weight = ' || delivery.weight);
936 
937 				INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
938 																					 delivery_id,
939 																					 number1, number2, char1, char2,
940 																					 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
941 																					 CREATION_DATE, STATUS)
942 																	 VALUES (mst_exception_details_s.nextval, excptnId , plan_idIn, 905,
943 																					 delivery.delivery_id,
944 																					 maxWeightV, maxVolumeV, tp_weight_uom, tp_volume_uom,
945 																					 userIdIn, userIdIn,-1,sysdate, sysdate, 3);
946 			END IF;
947 		END LOOP;
948 
949 
950 		--update count of this exception in mst_exceptions
951 		UPDATE mst_exceptions
952 		SET EXCEPTION_COUNT = (	select count(*)
953 														from mst_exception_details det
954 														where det.exception_id = excptnId)
955 		WHERE EXCEPTION_id = excptnId;
956 
957 		--in case no exception of this type was generated delete entry in mst_exceptions table
958 	  DELETE FROM mst_exceptions
959  		WHERE exception_count = 0 and exception_id = excptnId;
960 
961 		commit;
962 	END WgtVolViolForFirmDelivExcptn;
963 
964 
965 
966 	PROCEDURE InsufficientIntransitTimeExptn (plan_idIn NUMBER, userIdIn NUMBER) IS
967 		excptnId NUMBER;
968 		requiredTransitTimeInHrs NUMBER;
969 		availTimeInDays NUMBER;
970 		distance NUMBER;
971 
972 		--According to Anuj doing the join without using the source_location_code is safe. However, in the case
973 		--in the future we need to do that join then we will need an index on that column, since it takes a
974     --considerable amount of time to perform this query adding those two conditions.
975 		CURSOR cursor_DL IS
976 			SELECT distinct delivery_id, det.delivery_detail_id,
977 						 det.ship_from_location_id ship_from_location_id,
978 						 det.ship_to_location_id ship_to_location_id,
979 						 latest_acceptable_date, earliest_pickup_date
980 			FROM MST_DELIVERY_DETAILS det,
981 					 MST_DELIVERY_ASSIGNMENTS da,
982 					 WSH_LOCATIONS loc1,
983 					 WSH_LOCATIONS loc2
984 			WHERE det.plan_id = plan_idIn
985 				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
986 				AND det.delivery_detail_id = da.delivery_detail_id (+)
987     		AND parent_delivery_detail_id is null
988 			  AND loc1.wsh_location_id = det.ship_from_location_id
989 			  AND loc2.wsh_location_id = det.ship_to_location_id;
990 
991 		--Auxiliary data structures to cache all the data to insert in exception_details
992 		TYPE delivery_id_t IS TABLE OF MST_DELIVERIES.DELIVERY_ID%TYPE INDEX BY BINARY_INTEGER;
993 		TYPE delivery_detail_id_t IS TABLE OF MST_DELIVERY_DETAILS.DELIVERY_DETAIL_ID%TYPE INDEX BY BINARY_INTEGER;
994 		TYPE distance_t IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
995 		TYPE time_t IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
996 
997 		all_details_delivery_id delivery_id_t;
998 		all_details_delivery_detail_id delivery_detail_id_t;
999 		all_details_distance distance_t;
1000 		all_details_time time_t;
1001 		all_details_availTime time_t;
1002 		j NUMBER;
1003     thresholdInHrs NUMBER;
1004 		planStartDate DATE;
1005 
1006 	BEGIN
1007 		--Delete previous occurrences of this exception in mst_exceptions and the details table
1008 	 	DELETE FROM mst_exception_details
1009 		WHERE plan_id = plan_idIn
1010 			AND exception_type = 104;
1011 
1012   	DELETE FROM mst_exceptions
1013 		WHERE plan_id = plan_idIn
1014 			AND exception_type = 104;
1015 
1016 		--get the threshold from mst_excep_preferences
1017 		thresholdInHrs := getExceptionThreshold(104,userIdIn);
1018     debug_output('thresholdInHrs=' ||thresholdInHrs);
1019     --if no threshold found it means exception is disabled, so exit procedure
1020     IF thresholdInHrs  = -999 THEN
1021       debug_output('exception calculation disabled');
1022 			RETURN;
1023     END IF;
1024 
1025 		--current date is plan_start_date (not sysdate)
1026 		--SELECT plan_start_date into planStartDate
1027 		SELECT start_date into planStartDate
1028 		FROM mst_plans
1029 	  WHERE plan_id = plan_idIn;
1030 
1031 		--Create fresh entry for exception and keep exception_id for updates in details table
1032 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
1033 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1034 																CREATION_DATE)
1035 												VALUES (mst_exceptions_s.nextval, plan_idIn, 100, 104, 0, userIdIn,
1036 																userIdIn,-1,sysdate, sysdate);
1037 
1038 		SELECT exception_id INTO excptnId
1039 		FROM mst_exceptions
1040 		WHERE plan_id = plan_idIn
1041 			AND exception_type = 104;
1042 
1043 		j := 0;
1044 		FOR delivLine IN cursor_DL LOOP
1045 			requiredTransitTimeInHrs := GET_MINIMUM_TRANSIT_TIME(delivLine.ship_from_location_id, delivLine.ship_to_location_id, plan_idIn);
1046 
1047 			debug_output('delivery_detail_id=' || delivLine.delivery_detail_id || 'reqTransitTime=' || requiredTransitTimeInHrs);
1048 
1049 			IF delivLine.earliest_pickup_date < planStartDate THEN
1050 				IF delivLine.latest_acceptable_date < planStartDate THEN
1051 					availTimeInDays := 0;
1052 				ELSE
1053 					availTimeInDays := delivLine.latest_acceptable_date - planStartDate;
1054 				END IF;
1055 			ELSE
1056 				availTimeInDays := delivLine.latest_acceptable_date - delivLine.earliest_pickup_date;
1057 			END IF;
1058 
1059 			debug_output('availTransitTime=' || availTimeInDays*24);
1060 
1061 			-- ****************** check for ocurrence of the exception ***********************
1062 			IF ((availTimeInDays*24 + thresholdInHrs) < (requiredTransitTimeInHrs)) THEN
1063 					--determine distance for this O-D pair
1064 			  BEGIN
1065           --FTE_LOCATION_MILEAGES is distance table
1066           --key is <origin_id, destination_id,IDENTIFIER_TYPE>. Origin and destination are FK to WSH_REGIONS.
1067           --IDENTIFIER_TYPE can be city or state (Anuj)
1068           --select MIN distance because we might have more than one entry in distance table. Take the one with minimum distance for now.
1069           --Should we use distance_level profile to choose which one?
1070           SELECT MIN(lm.distance)
1071           INTO distance
1072       		FROM FTE_LOCATION_MILEAGES lm,
1073       				 WSH_REGION_LOCATIONS origReg,
1074       				 WSH_REGION_LOCATIONS destReg
1075       		WHERE origReg.location_id = delivLine.ship_from_location_id
1076       			AND destReg.location_id = delivLine.ship_to_location_id
1077             AND origReg.region_id = origin_id
1078       			AND destReg.region_id = destination_id;
1079           EXCEPTION
1080             WHEN NO_DATA_FOUND THEN
1081               distance := -9999;
1082       	END;
1083 
1084   			debug_output('delivery_detail_id=' || delivLine.delivery_detail_id || ', distance=' || distance
1085                      || ', requiredTransitTimeInHrs='||requiredTransitTimeInHrs || ', availTimeInHrs=' ||  availTimeInDays * 24);
1086 
1087 				all_details_delivery_id(j) := delivLine.delivery_id;
1088 				all_details_delivery_detail_id(j) := delivLine.delivery_detail_id;
1089 			  all_details_distance(j) := distance;
1090 				all_details_time(j) := requiredTransitTimeInHrs;
1091 				all_details_availTime(j) := availTimeInDays * 24;
1092 				j := j + 1;
1093 			END IF;
1094 		END LOOP;
1095 
1096 		--bulk add all exception_details
1097     --This is used to improve performance (using this insert inside the loop makes the procedure
1098     --take minutes to execute, compared to seconds in this way in test data).
1099 		IF j > 0 THEN
1100 			FORALL k IN all_details_delivery_id.FIRST..all_details_delivery_id.LAST
1101 				INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
1102 																					 delivery_id, delivery_detail_id,
1103 																					 number1, number2,
1104 																					 number3,
1105 																					 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1106 																					 CREATION_DATE, STATUS)
1107 																	 VALUES (mst_exception_details_s.nextval, excptnId , plan_IdIn, 104,
1108 																					 all_details_delivery_id(k), all_details_delivery_detail_id(k),
1109 																				   all_details_distance(k), all_details_time(k),
1110 																					 all_details_availTime(k),
1111  																					 userIdIn, userIdIn,-1,sysdate, sysdate, 3);
1112 		END IF;
1113 
1114 		--update count of this exception in mst_exceptions
1115 		UPDATE mst_exceptions
1116 		SET EXCEPTION_COUNT = (	select count(*)
1117 														from mst_exception_details det
1118 														where det.exception_id = excptnId)
1119 		WHERE EXCEPTION_id = excptnId;
1120 
1121     --in case no exception of this type was generated delete entry in mst_exceptions table
1122 	  DELETE FROM mst_exceptions
1123  		WHERE exception_count = 0 and exception_id = excptnId;
1124   	commit;
1125 
1126 	END InsufficientIntransitTimeExptn;
1127 
1128 
1129 	PROCEDURE PastDueOrdersExptn (plan_idIn NUMBER, userIdIn NUMBER) IS
1130 		excptnId NUMBER;
1131 		requiredTransitTimeInHrs NUMBER;
1132 		availTransitTimeInHrs NUMBER;
1133     thresholdInHrs NUMBER;
1134 
1135 		--highest level delivery lines that are past due.
1136 		CURSOR cursor_past_due_orders IS
1137 			SELECT DISTINCT da.delivery_id, det.delivery_detail_id,
1138 						 det.ship_from_location_id, det.ship_to_location_id,
1139 						 ((det.latest_acceptable_date - plan.start_date)*24) AS availTime
1140 			FROM MST_DELIVERY_DETAILS det,
1141 					 MST_DELIVERY_ASSIGNMENTS da,
1142 					 MST_PLANS plan
1143 			WHERE det.plan_id = plan_idIn
1144 				AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null   --added so we consider only input data from TE
1145 				AND det.delivery_detail_id = da.delivery_detail_id (+)
1146 				AND da.parent_delivery_detail_id is null
1147 				AND plan.plan_id = plan_idIn
1148 				AND (   (det.latest_acceptable_date + thresholdInHrs/24 < plan.start_date)
1149 				  	 OR (det.latest_pickup_date + thresholdInHrs/24 < plan.start_date) );
1150 	BEGIN
1151 		--Delete previous occurrences of this exception in mst_exceptions and the details table
1152 	 	DELETE FROM mst_exception_details
1153 		WHERE plan_id = plan_idIn
1154 			AND exception_type = 105;
1155 
1156   	DELETE FROM mst_exceptions
1157 		WHERE plan_id = plan_idIn
1158 			AND exception_type = 105;
1159 
1160 		--get the threshold from mst_excep_preferences
1161 		thresholdInHrs := getExceptionThreshold(105,userIdIn);
1162     debug_output('thresholdInHrs='||thresholdInHrs);
1163     --if no threshold found it means exception is disabled, so exit procedure
1164     IF thresholdInHrs  = -999 THEN
1165       debug_output('exception calculation disabled');
1166 			RETURN;
1167     END IF;
1168 
1169 
1170 		--Create fresh entry for exception and keep exception_id for updates in details table
1171 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
1172 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1173 																CREATION_DATE)
1174 												VALUES (mst_exceptions_s.nextval, plan_idIn, 100, 105, 0, userIdIn,
1175 																userIdIn,-1,sysdate, sysdate);
1176 
1177 		SELECT exception_id INTO excptnId
1178 		FROM mst_exceptions
1179 		WHERE plan_id = plan_idIn
1180 			AND exception_type = 105;
1181 
1182 
1183 		--store the details in mst_exception_details
1184 		FOR delivLine IN cursor_past_due_orders LOOP
1185 
1186 			requiredTransitTimeInHrs := GET_MINIMUM_TRANSIT_TIME(delivLine.ship_from_location_id, delivLine.ship_to_location_id, plan_idIn);
1187 
1188 			IF delivLine.availTime < 0 THEN
1189 				availTransitTimeInHrs := 0;
1190 			ELSE
1191 				availTransitTimeInHrs := delivLine.availTime;
1192 			END IF;
1193 
1194       debug_output('delivery_detail_id='||delivLine.delivery_detail_id || ', delivLine.availTime=' || delivLine.availTime ||
1195                    ', requiredTransitTimeInHrs=' || requiredTransitTimeInHrs);
1196 			INSERT INTO mst_exception_details (exception_detail_id, exception_id, plan_id, exception_type,
1197 																				 delivery_id, delivery_detail_id,
1198 																				 number2, number3,
1199 																				 created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1200 																				 CREATION_DATE, STATUS)
1201 																VALUES (mst_exception_details_s.nextval, excptnId , plan_IdIn, 105,
1202 																				delivLine.delivery_id, delivLine.delivery_detail_id,
1203 																				requiredTransitTimeInHrs, availTransitTimeInHrs,
1204 																				userIdIn, userIdIn,-1,sysdate, sysdate, 3);
1205 		END LOOP;
1206 
1207 		--update count of this exception in mst_exceptions
1208 		UPDATE mst_exceptions
1209 		SET EXCEPTION_COUNT = (	select count(*)
1210 														from mst_exception_details det
1211 														where det.exception_id = excptnId)
1212 		WHERE EXCEPTION_id = excptnId;
1213 
1214     --in case no exception of this type was generated delete entry in mst_exceptions table
1215 	  DELETE FROM mst_exceptions
1216  		WHERE exception_count = 0 and exception_id = excptnId;
1217   	commit;
1218 	END PastDueOrdersExptn;
1219 
1220 
1221 	--input:
1222   --  ship_from: location_id of origin
1223   --  ship_to: location_id of destination
1224 	--output:
1225   --  minimum transit time irrespective of mode/vehicle features (in tp_uom which represents hours)
1226 	FUNCTION GET_MINIMUM_TRANSIT_TIME(ship_from NUMBER, ship_to NUMBER, plan_idIn NUMBER) RETURN NUMBER IS
1227 		minimumTransitTime NUMBER;
1228 		tl_minimumTransitTime NUMBER;
1229 		Distance NUMBER;
1230 	  PI NUMBER;
1231 		HighwayDistance NUMBER;
1232 		lat_1 NUMBER;
1233 		lat_2 NUMBER;
1234 		lon_1 NUMBER;
1235 		lon_2 NUMBER;
1236 
1237 -- Anuj says FTE_LANES is not going to be populated by TE
1238 --		CURSOR c_LTLParcel_transit_times IS
1239 --			SELECT lane_id, carrier_id, mode_of_transportation_code, lanes.transit_time, lanes.transit_time_uom
1240 --			FROM WSH_REGION_LOCATIONS rl1,
1241 --					 WSH_REGION_LOCATIONS rl2,
1242 --					 FTE_LANES lanes
1243 --			WHERE rl1.location_id = ship_from
1244 --      	AND rl2.location_id = ship_to
1245 --				AND lanes.ORIGIN_ID = rl1.region_id
1246 --			  AND lanes.DESTINATION_ID = rl2.region_id;
1247 
1248 	BEGIN
1249 			--check LTL and Parcel
1250 			SELECT NVL(MIN(NVL(CONV_TO_UOM(sm.INTRANSIT_TIME,sm.TIME_UOM_CODE,tp_time_uom,0),99999)),99999)
1251 			INTO minimumTransitTime
1252 			FROM MTL_INTERORG_SHIP_METHODS sm,
1253 			     WSH_REGION_LOCATIONS rl1,
1254 		  	   WSH_REGION_LOCATIONS rl2
1255 			WHERE rl1.location_id = ship_from
1256 			  AND rl2.location_id = ship_to
1257 		  	AND (   ship_from = sm.from_location_id AND ship_to = sm.to_location_id
1258     				OR (ship_from = sm.from_location_id AND rl2.region_id = sm.to_region_id)
1259 	    	 		OR (rl1.region_id = sm.from_region_id AND ship_to = sm.to_location_id)
1260 	    		 	OR (rl1.region_id = sm.from_region_id AND rl2.region_id = sm.to_region_id));
1261 
1262 --			debug_output('minPCL_LTL_TransitTime=' || minimumTransitTime);
1263 
1264       --Check TL
1265       --FTE_LOCATION_MILEAGES is distance table
1266       --key is <origin_id, destination_id,IDENTIFIER_TYPE>. Origin and destination are FK to WSH_REGIONS.
1267       --IDENTIFIER_TYPE can be city or state (Anuj)
1268       --TRANSIT_TIME, TRANSIT_TIME_UOM are columns of interest here.
1269       BEGIN
1270         SELECT MIN(CONV_TO_UOM(distTable.transit_time,distTable.transit_time_uom,tp_time_uom,0))
1271         INTO tl_minimumTransitTime
1272         FROM FTE_LOCATION_MILEAGES distTable,
1273       			 WSH_REGION_LOCATIONS origReg,
1274           	 WSH_REGION_LOCATIONS destReg
1275         WHERE origReg.location_id = ship_from
1276           AND destReg.location_id = ship_to
1277           AND origReg.region_id = distTable.origin_id
1278           AND destReg.region_id = distTable.destination_id;
1279         EXCEPTION
1280           WHEN NO_DATA_FOUND THEN
1281              tl_minimumTransitTime := -23453;
1282              debug_output('no TL transit time in FTE_LOCATION_MILEAGES');
1283       END;
1284       IF tl_minimumTransitTime IS NULL THEN
1285         tl_minimumTransitTime := -23453;
1286         debug_output('TL transit time in FTE_LOCATION_MILEAGES is null after conversion');
1287       END IF;
1288 
1289 
1290 --      debug_output('origin=' || ship_from || ', destination=' || ship_to || ', tl_minimumTransitTime=' || tl_minimumTransitTime);
1291 --			IF no entry in dist. table THEN
1292       IF tl_minimumTransitTime = -23453 THEN
1293 				--we need to use lat/long method
1294 				BEGIN
1295 					SELECT NVL(latitude,0), NVL(longitude,0)
1296 					INTO lat_1, lon_1
1297 					FROM  WSH_LOCATIONS
1298 					WHERE wsh_location_id = ship_from;
1299 --					debug_output('ship_from=' || ship_from || ', lat=' || lat_1 || ', long=' || lon_1);
1300 			    EXCEPTION WHEN no_data_found then
1301 					debug_output('Error:  no entry in distance table and latitude/longitude is null for location_id = ' || ship_from);
1302 					RETURN 99999;
1303 				END;
1304 
1305 				BEGIN
1306 					SELECT NVL(latitude,0), NVL(longitude,0)
1307 					INTO lat_2, lon_2
1308 					FROM  WSH_LOCATIONS
1309 					WHERE wsh_location_id = ship_to;
1310 --					debug_output('ship_to=' || ship_to || ', lat=' || lat_2 || ', long=' || lon_2);
1311 
1312 			    EXCEPTION WHEN no_data_found then
1313 					debug_output('Error:  no entry in distance table and latitude/longitude is null for location_id = ' || ship_to);
1314 					RETURN 99999;
1315 				END;
1316 
1317 	  	  PI := 3.1415926;
1318 				Distance := 69.075 * 180/PI *
1319 										(ACOS ((SIN(PI /180*lat_1) * SIN(PI /180*lat_2)) +
1320 													 (COS(PI /180*lat_1) * COS(PI /180*lat_2) * COS(PI /180*ABS(lon_1 - lon_2)))
1321 										));
1322 				HighwayDistance := (1+distScaleFactor)*Distance;
1323 				tl_minimumTransitTime := HighwayDistance / avgDrvSpeed;
1324 --			  debug_output('HighwayDistance=' || HighwayDistance || ', Distance=' || Distance || ', distScaleFactor=' || distScaleFactor );
1325 			END IF;
1326 
1327 --			debug_output('min_TL_TransitTime=' || tl_minimumTransitTime);
1328 
1329 			IF tl_minimumTransitTime < minimumTransitTime THEN
1330 				minimumTransitTime := tl_minimumTransitTime;
1331 			END IF;
1332 
1333 		RETURN minimumTransitTime;
1334 	END GET_MINIMUM_TRANSIT_TIME;
1335 
1336 
1337 	PROCEDURE FacCalViolForPickUpExptn (plan_idIn NUMBER, userIdIn NUMBER) IS
1338 	  thresholdInHrs NUMBER;
1339 
1340 		--type used to cache association between location id and calendar code (getCalendar gets too expensive for this query)
1341 		TYPE calendar_map_type IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
1342 		calendar_lookup calendar_map_type;
1343 
1344 
1345 		CURSOR cursor_DL IS
1346 			SELECT det.delivery_detail_id, det.ship_from_location_id, da.delivery_id,
1347 						det.earliest_pickup_date, det.latest_pickup_date
1348 			FROM  MST_DELIVERY_DETAILS det,
1349 					  MST_DELIVERY_ASSIGNMENTS da
1350 			WHERE da.delivery_detail_id = det.delivery_detail_id (+)
1351 			 AND da.parent_delivery_detail_id is null
1352 			 AND det.plan_id = plan_idIn
1353 			 AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null;   --added so we consider only input data from TE
1354 
1355 
1356 		excptnId NUMBER;
1357 		exceptionFlag NUMBER;
1358 		delivDetail NUMBER;
1359 		delivId NUMBER;
1360 		openTime DATE;
1361 		closeTime DATE;
1362 		shipFrom NUMBER;
1363 		earliest_pickup_date DATE;
1364 		latest_pickup_date DATE;
1365 		start_open DATE;
1366 		end_open DATE;
1367 		seq_num NUMBER;
1368 
1369 		local_EPD DATE;
1370 		server_EPD DATE;
1371 		local_LPD DATE;
1372 		server_LPD DATE;
1373 		numberOfCalDays NUMBER;
1374 
1375 		calCode VARCHAR2(10);
1376 	BEGIN
1377 		--clean previous exceptions of this type
1378   	DELETE FROM mst_exception_details
1379 		WHERE plan_id = plan_idIn
1380 			AND exception_type = 404;
1381 
1382   	DELETE FROM mst_exceptions
1383 		WHERE plan_id = plan_idIn
1384 			AND exception_type = 404;
1385 
1386 		--get the threshold from mst_excep_preferences
1387     thresholdInHrs:= getExceptionThreshold(404,userIdIn);
1388     debug_output('thresholdInHrs='||thresholdInHrs || ', sysdate = ' || sysdate);
1389     --if no threshold found it means exception is disabled, so exit procedure
1390     IF thresholdInHrs = -999 THEN
1391       debug_output('exception calculation disabled');
1392 			RETURN;
1393     END IF;
1394 
1395 
1396 	  --insert entry in mst_exceptions
1397 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
1398 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1399 																CREATION_DATE)
1400 												VALUES (mst_exceptions_s.nextval,plan_idIn, 400, 404, 0, userIdIn,
1401 																userIdIn,-1,sysdate, sysdate);
1402 
1403 		SELECT exception_id INTO excptnId
1404 		FROM mst_exceptions
1405 		WHERE plan_id = plan_idIn
1406 			AND exception_type = 404;
1407 
1408 		--Obtain number of extra days to consider in plan (using snapshot's logic here) (6/6/2003)
1409 		numberOfCalDays := fnd_profile.value('MST_CALENDAR_EXTRA_DAYS');
1410 		IF numberOfCalDays is null THEN
1411 		  numberOfCalDays := 30;
1412 		END IF;
1413 
1414 
1415 		debug_output('starting cache of calendar codes');
1416 
1417 
1418 		--cache shipping calendar code and location id association
1419 		--Use  MST_SNAPSHOT_TASK_UTIL.getCalendar function to obtain calendar code
1420 		    --   Input : locationId, type = 'SHIPPING' or 'RECEIVING'
1421 		    --   Output: calendarCode
1422 		FOR delivLine IN cursor_DL LOOP
1423 			calendar_lookup(delivLine.ship_from_location_id) :=	MST_SNAPSHOT_TASK_UTIL.getCalendar(delivLine.ship_from_location_id, 'SHIPPING');
1424 	  END LOOP;
1425 
1426 
1427 		debug_output('starting deliv detail loop');
1428 
1429 	  --loop trough delivery details
1430 		OPEN cursor_DL;
1431 		LOOP
1432 			--get next row (delivery detail)
1433 		  FETCH cursor_DL INTO delivDetail, shipFrom, delivId,
1434 													 earliest_pickup_date, latest_pickup_date;
1435 			EXIT WHEN cursor_DL%NOTFOUND;
1436 
1437 			IF  earliest_pickup_date IS NOT NULL AND latest_pickup_date IS NOT NULL THEN
1438 				-- Adjust pickup time window to local time zone for ship_from facility (using Jin's function)
1439 				local_EPD := MST_GEOCODING.Get_local_time(shipFrom,earliest_pickup_date);
1440 				server_EPD := earliest_pickup_date;
1441 				local_LPD := MST_GEOCODING.Get_local_time(shipFrom,latest_pickup_date);
1442 				server_LPD := latest_pickup_date;
1443 /*
1444 				debug_output('local_EPD=' || to_char(local_EPD,'MM/DD/YYYY HH24:MI:SS') || ', server_EPD=' || to_char(server_EPD,'MM/DD/YYYY HH24:MI:SS') ||
1445 										 ', local_LPD=' || to_char(local_LPD,'MM/DD/YYYY HH24:MI:SS') || ', server_LPD=' || to_char(server_LPD,'MM/DD/YYYY HH24:MI:SS') );
1446 */
1447 			END IF;
1448 
1449 			calCode := calendar_lookup(shipFrom);
1450 
1451 /*
1452 			debug_output('checking delivery_detail_id=' || delivDetail ||
1453 									 ', cal_code=' || calCode || ', earliest_pkup_date=' || to_char(earliest_pickup_date,'MM/DD/YYYY HH24:MI:SS') ||
1454 									 ', latest_pickup_date=' || to_char(latest_pickup_date,'MM/DD/YYYY HH24:MI:SS') );
1455 */
1456 
1457 			IF calCode = '-23453' THEN
1458 				debug_output('NULL calendar for delivery_detail_id' || delivDetail);
1459 			ELSIF earliest_pickup_date IS NULL OR latest_pickup_date IS NULL THEN
1460 				debug_output('earliest_pickup_date IS NULL OR latest_pickup_date IS NULL');
1461 			ELSE
1462 
1463 				--Note: database stores dates in julian format, i.e. is a double whose unit is a day.
1464 				--This query allows access to the expanded windows of activity of the origin facility
1465   		  --Query based on what is currently being used in snapshot to populate calendars flat-file (6/6/2003)
1466 				BEGIN
1467 					SELECT 2 INTO exceptionFlag  --SYS_NO (no exception since there is at least one overlapping shift)
1468 					FROM DUAL
1469 					WHERE EXISTS
1470 						( SELECT  caldates.CALENDAR_DATE
1471 							FROM	BOM_CALENDAR_DATES caldates,
1472 									 	BOM_SHIFT_DATES  sdates,
1473 									 	BOM_SHIFT_TIMES bshift,
1474 									 	MST_PLANS plan
1475 							WHERE plan.plan_id = plan_idIn
1476 							 AND caldates.CALENDAR_CODE = sdates.CALENDAR_CODE (+)
1477 							 AND caldates.CALENDAR_DATE = sdates.SHIFT_DATE (+)
1478 							 AND sdates.CALENDAR_CODE = bshift.CALENDAR_CODE (+)
1479 							 AND sdates.SHIFT_NUM = bshift.SHIFT_NUM (+)
1480 							 AND caldates.SEQ_NUM  is not null
1481 							 AND sdates.SEQ_NUM(+)  is not null
1482 --							 AND caldates.CALENDAR_DATE between sysdate and plan.CUTOFF_DATE+numberOfCalDays
1483 							 AND caldates.CALENDAR_DATE between local_EPD-1 and local_LPD+1
1484 							 AND caldates.CALENDAR_CODE = calCode
1485 --check if any shift falls inside [EPD,LPD]
1486 					     AND ( 	( local_EPD <= (caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) AND
1487 					          	(caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) <= local_LPD)
1488 				           OR
1489 											( local_EPD <= (caldates.CALENDAR_DATE+bshift.TO_TIME/86400) AND
1490 					            (caldates.CALENDAR_DATE+bshift.TO_TIME/86400) <= local_LPD)
1491 --check if EPD or LPD falls inside any shift
1492 									 OR
1493 											( (caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) <= local_EPD AND
1494 					             local_EPD <= ( caldates.CALENDAR_DATE+bshift.TO_TIME/86400) )
1495 									 OR
1496 											( (caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) <= local_LPD AND
1497 					             local_LPD <= ( caldates.CALENDAR_DATE+bshift.TO_TIME/86400) )  ) );
1498 
1499 
1500 					EXCEPTION WHEN no_data_found then
1501 						exceptionFlag := 1; --SYS_YES (there is an exception since there is no overlapping shift)
1502 				END;
1503 
1504 				IF exceptionFlag = 1 THEN
1505 					debug_output('Exception detected, delivDet=' || delivDetail);
1506 
1507 					--insert exception detected into mst_exception_details
1508 					INSERT INTO mst_exception_details
1509 											 (exception_detail_id,exception_id, plan_id, exception_type,
1510 												delivery_detail_id, delivery_id,
1511 												date1, date2,
1512 												created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1513 												CREATION_DATE, STATUS)
1514 								VALUES (mst_exception_details_s.nextval, excptnId , plan_idIn, 404,
1515 												delivDetail, delivId,
1516 												server_EPD, server_LPD,
1517 												userIdIn, userIdIn,-1,sysdate, sysdate, 3);
1518 				END IF;
1519 			END IF;
1520 		END LOOP;
1521 		CLOSE cursor_DL;
1522 
1523 		--update count of this exception in mst_exceptions
1524 		UPDATE mst_exceptions
1525 		SET EXCEPTION_COUNT = (	select count(*)
1526 														from mst_exception_details det
1527 														where det.exception_id = excptnId)
1528 		WHERE EXCEPTION_id = excptnId;
1529 
1530     --in case no exception of this type was generated delete entry in mst_exceptions table
1531 	  DELETE FROM mst_exceptions
1532  		WHERE exception_count = 0 and exception_id = excptnId;
1533   	commit;
1534 
1535 	END FacCalViolForPickUpExptn;
1536 
1537 
1538 
1539 	PROCEDURE FacCalViolForDeliveryExptn (plan_idIn NUMBER, userIdIn NUMBER) IS
1540 	  thresholdInHrs NUMBER;
1541 
1542 		--type used to cache association between location id and calendar code (getCalendar gets too expensive for this query)
1543 		TYPE calendar_map_type IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
1544 		calendar_lookup calendar_map_type;
1545 
1546 		CURSOR cursor_DL IS
1547 			SELECT det.delivery_detail_id, det.ship_to_location_id, da.delivery_id,
1548 						 det.earliest_acceptable_date, det.latest_acceptable_date
1549 			FROM  MST_DELIVERY_DETAILS det,
1550 					  MST_DELIVERY_ASSIGNMENTS da
1551 			WHERE da.delivery_detail_id = det.delivery_detail_id (+)
1552 			 AND da.parent_delivery_detail_id is null
1553 			 AND det.plan_id = plan_idIn
1554 			 AND det.SPLIT_FROM_DELIVERY_DETAIL_ID is null;   --added so we consider only input data from TE
1555 
1556 		excptnId NUMBER;
1557 		exceptionFlag NUMBER;
1558 		delivDetail NUMBER;
1559 		delivId NUMBER;
1560 		openTime DATE;
1561 		closeTime DATE;
1562 		shipTo NUMBER;
1563 		earliest_acceptable_date DATE;
1564 		latest_acceptable_date DATE;
1565 		start_open DATE;
1566 		end_open DATE;
1567 
1568 		local_EDD DATE;
1569 		server_EDD DATE;
1570 		local_LDD DATE;
1571 		server_LDD DATE;
1572 		numberOfCalDays NUMBER;
1573 
1574 		calCode VARCHAR2(10);
1575 	BEGIN
1576 		--clean previous exceptions of this type
1577   	DELETE FROM mst_exception_details
1578 		WHERE plan_id = plan_idIn
1579 			AND exception_type = 405;
1580 
1581   	DELETE FROM mst_exceptions
1582 		WHERE plan_id = plan_idIn
1583 			AND exception_type = 405;
1584 
1585 
1586 		--get the threshold from mst_excep_preferences
1587     thresholdInHrs := getExceptionThreshold(405,userIdIn);
1588     debug_output('thresholdInHrs='||thresholdInHrs || ', sysdate = ' || sysdate);
1589     --if no threshold found it means exception is disabled, so exit procedure
1590     IF thresholdInHrs = -999 THEN
1591       debug_output('exception calculation disabled');
1592 			RETURN;
1593     END IF;
1594 
1595 
1596 	  --insert entry in mst_exceptions
1597 		INSERT INTO mst_exceptions (exception_id, plan_id, exception_group, exception_type, exception_count,
1598 			                          created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1599 																CREATION_DATE)
1600 												VALUES (mst_exceptions_s.nextval, plan_idIn, 400, 405, 0, userIdIn,
1601 																userIdIn,-1,sysdate, sysdate);
1602 
1603 		SELECT exception_id INTO excptnId
1604 		FROM mst_exceptions
1605 		WHERE plan_id = plan_idIn
1606 			AND exception_type = 405;
1607 
1608 
1609 		--Obtain number of extra days to consider in plan (using snapshot's logic here) (6/6/2003)
1610 		numberOfCalDays := fnd_profile.value('MST_CALENDAR_EXTRA_DAYS');
1611 		IF numberOfCalDays is null THEN
1612 		  numberOfCalDays := 30;
1613 		END IF;
1614 
1615 
1616 		debug_output('starting cache of calendar codes');
1617 
1618 
1619 		--cache receiving calendar code and location id association
1620 		FOR delivLine IN cursor_DL LOOP
1621 			calendar_lookup(delivLine.ship_to_location_id) :=	MST_SNAPSHOT_TASK_UTIL.getCalendar(delivLine.ship_to_location_id, 'RECEIVING');
1622 	  END LOOP;
1623 
1624 
1625 		debug_output('starting deliv detail loop');
1626 
1627 	  --loop trough delivery details
1628 		OPEN cursor_DL;
1629 		LOOP
1630 			--get next row (delivery detail)
1631 		  FETCH cursor_DL INTO delivDetail, shipTo, delivId,
1632 													 earliest_acceptable_date, latest_acceptable_date;
1633 			EXIT WHEN cursor_DL%NOTFOUND;
1634 
1635 			IF  earliest_acceptable_date IS NOT NULL AND latest_acceptable_date IS NOT NULL THEN
1636 				-- Adjust dropoff time window to local time zone for ship_to facility (using Jin's function)
1637 				local_EDD := MST_GEOCODING.Get_local_time(shipTo,earliest_acceptable_date);
1638 				server_EDD := earliest_acceptable_date;
1639 				local_LDD := MST_GEOCODING.Get_local_time(shipTo,latest_acceptable_date);
1640 				server_LDD := latest_acceptable_date;
1641 /*
1642 				debug_output('local_EDD=' || to_char(local_EDD,'MM/DD/YYYY HH24:MI:SS') || ', server_EDD=' || to_char(server_EDD,'MM/DD/YYYY HH24:MI:SS') ||
1643 									 ', local_LDD=' || to_char(local_LDD,'MM/DD/YYYY HH24:MI:SS') || ', server_LDD=' || to_char(server_LDD,'MM/DD/YYYY HH24:MI:SS') );
1644 */
1645 			END IF;
1646 
1647 			calCode := calendar_lookup(shipTo);
1648 
1649 /*
1650 			debug_output('checking delivery_detail_id=' || delivDetail ||
1651 									 ', cal_code=' || calCode || ', earliest_acceptable_date=' || to_char(earliest_acceptable_date,'MM/DD/YYYY HH24:MI:SS') ||
1652 									 ', latest_acceptable_date=' || to_char(latest_acceptable_date,'MM/DD/YYYY HH24:MI:SS') );
1653 */
1654 
1655 			IF calCode = '-23453' THEN
1656 				debug_output('NULL calendar for delivery_detail_id' || delivDetail);
1657 			ELSIF earliest_acceptable_date IS NULL OR latest_acceptable_date IS NULL THEN
1658 				debug_output('earliest_acceptable_date IS NULL OR latest_acceptable_date IS NULL');
1659 			ELSE
1660 
1661 
1662 				--Note: database stores dates in julian format, i.e. is a double whose unit is a day.
1663 				--This query allows access to the expanded windows of activity of the origin facility
1664   		  --Query based on what is currently being used in snapshot to populate calendars flat-file (6/6/2003)
1665 				BEGIN
1666 					SELECT 2 INTO exceptionFlag  --SYS_NO (no exception since there is at least one overlapping shift)
1667 					FROM DUAL
1668 					WHERE EXISTS
1669 						( SELECT  caldates.CALENDAR_DATE
1670 							FROM	BOM_CALENDAR_DATES caldates,
1671 									 	BOM_SHIFT_DATES  sdates,
1672 									 	BOM_SHIFT_TIMES bshift,
1673 									 	MST_PLANS plan
1674 							WHERE plan.plan_id = plan_idIn
1675 							 AND caldates.CALENDAR_CODE = sdates.CALENDAR_CODE (+)
1676 							 AND caldates.CALENDAR_DATE = sdates.SHIFT_DATE (+)
1677 							 AND sdates.CALENDAR_CODE = bshift.CALENDAR_CODE (+)
1678 							 AND sdates.SHIFT_NUM = bshift.SHIFT_NUM (+)
1679 							 AND caldates.SEQ_NUM  is not null
1680 							 AND sdates.SEQ_NUM(+)  is not null
1681 --							 AND caldates.CALENDAR_DATE between sysdate and plan.CUTOFF_DATE+numberOfCalDays
1682 							 AND caldates.CALENDAR_DATE between local_EDD-1 and local_LDD+1
1683 							 AND caldates.CALENDAR_CODE = calCode
1684 --check if any shift falls inside [EDD,LDD]
1685 					     AND ( 	( local_EDD <= (caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) AND
1686 					          	(caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) <= local_LDD)
1687 				           OR
1688 											( local_EDD <= (caldates.CALENDAR_DATE+bshift.TO_TIME/86400) AND
1689 					            (caldates.CALENDAR_DATE+bshift.TO_TIME/86400) <= local_LDD)
1690 --check if EDD or LDD falls inside any shift
1691 									 OR
1692 											( (caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) <= local_EDD AND
1693 					             local_EDD <= ( caldates.CALENDAR_DATE+bshift.TO_TIME/86400) )
1694 									 OR
1695 											( (caldates.CALENDAR_DATE+bshift.FROM_TIME/86400) <= local_LDD AND
1696 					             local_LDD <= ( caldates.CALENDAR_DATE+bshift.TO_TIME/86400) )  ) );
1697 
1698 					EXCEPTION WHEN no_data_found then
1699 						exceptionFlag := 1; --SYS_YES (there is an exception since there is no overlapping shift)
1700 					END;
1701 
1702 				IF exceptionFlag = 1 THEN
1703 					debug_output('Exception detected, delivDet=' || delivDetail);
1704 					--insert exception detected into mst_exception_details
1705 					INSERT INTO mst_exception_details
1706 										 (exception_detail_id, exception_id, plan_id, exception_type,
1707 											delivery_detail_id, delivery_id,
1708 											date1, date2,
1709 											created_by, last_updated_by, LAST_UPDATE_LOGIN,LAST_UPDATE_DATE,
1710 											CREATION_DATE, STATUS)
1711 							VALUES (mst_exception_details_s.nextval, excptnId , plan_idIn, 405,
1712 											delivDetail, delivId,
1713 											server_EDD, server_LDD,
1714 											userIdIn, userIdIn,-1,sysdate, sysdate, 3);
1715 				END IF;
1716 			END IF;
1717 		END LOOP;
1718 		CLOSE cursor_DL;
1719 
1720 		--update count of this exception in mst_exceptions
1721 		UPDATE mst_exceptions
1722 		SET EXCEPTION_COUNT = (	select count(*)
1723 														from mst_exception_details det
1724 														where det.exception_id = excptnId)
1725 		WHERE EXCEPTION_id = excptnId;
1726 
1727     --in case no exception of this type was generated delete entry in mst_exceptions table
1728 	  DELETE FROM mst_exceptions
1729  		WHERE exception_count = 0 and exception_id = excptnId;
1730   	commit;
1731 
1732 	END FacCalViolForDeliveryExptn;
1733 
1734 
1735 
1736 	FUNCTION CONV_TO_UOM(src_value NUMBER, src_uom_code VARCHAR2,
1737 	                     dest_uom_code VARCHAR2,
1738 	                     inventory_item_id NUMBER DEFAULT 0) RETURN NUMBER IS
1739 		p_conv_found BOOLEAN;
1740 	  p_conv_rate NUMBER;
1741 		dest_value NUMBER;
1742 	BEGIN
1743 		GET_UOM_CONVERSION_RATES(src_uom_code, dest_uom_code, inventory_item_id,
1744 														 p_conv_found, p_conv_rate);
1745 
1746 		IF p_conv_found = true THEN
1747 			dest_value := src_value * p_conv_rate;
1748 		ELSE
1749 			dest_value := NULL;
1750 		END IF;
1751 		RETURN dest_value;
1752 	END CONV_TO_UOM;
1753 
1754 	/*----------------------------------------------------+
1755 	| This procedure takes as input 2 uom codes in the    |
1756 	| same uom class or across classes and returns a      |
1757 	| conv_rate between them.                             |
1758 	| If a conversion is not found then it sets           |
1759 	| the output variable conv_found to FALSE             |
1760 	| and returns a conv_rate of 1.                       |
1761 	| Note: code based on                                 |
1762   |       MSC_X_UTIL.GET_UOM_CONVERSION_RATES           |
1763 	+-----------------------------------------------------*/
1764 
1765 	PROCEDURE GET_UOM_CONVERSION_RATES(p_uom_code IN VARCHAR2,
1766 	                                   p_dest_uom_code IN VARCHAR2,
1767 	                               		 p_inventory_item_id IN NUMBER DEFAULT 0,
1768 		 									   						 p_conv_found OUT NOCOPY BOOLEAN,
1769 	                                   p_conv_rate  OUT NOCOPY NUMBER) IS
1770 	l_uom_class VARCHAR2(10);
1771 	l_dest_uom_class VARCHAR2(10);
1772 	BEGIN
1773 
1774 
1775 		/*-------------------------------------------------------------+
1776 		| Rownum = 1 is used to account for the corner case APS bug    |
1777 		| when the same uom code points to different unit of measures  |
1778 		| in multiple instances. This can be removed when APS makes    |
1779 		| the fix to allow only 1 uom code in addition to unit of 	   |
1780 		| measure in MSC_UNITS_OF_MEASURE.							   |
1781 		+--------------------------------------------------------------*/
1782 
1783 		/*-----------------------------------------------------+
1784 		| Inventory Item Id = non zero is required only if 	   |
1785 		| we are doing conversions across uom classes		       |
1786 		+------------------------------------------------------*/
1787 
1788 		BEGIN
1789 			SELECT uom_class INTO l_uom_class
1790 			FROM mtl_units_of_measure
1791 			WHERE uom_code = p_uom_code
1792 				AND ROWNUM = 1;
1793 
1794 			EXCEPTION WHEN no_data_found then
1795 			p_conv_found := FALSE;
1796 			p_conv_rate := 1.0;
1797 			RETURN;
1798 		END;
1799 
1800 		BEGIN
1801 	    SELECT uom_class INTO l_dest_uom_class
1802 	    FROM mtl_units_of_measure
1803 	    WHERE uom_code = p_dest_uom_code
1804 				AND ROWNUM = 1;
1805 
1806 	    EXCEPTION WHEN no_data_found then
1807 	    p_conv_found := FALSE;
1808 	    p_conv_rate := 1.0;
1809 	    RETURN;
1810 		END;
1811 
1812 
1813 		IF (l_uom_class = l_dest_uom_class) THEN
1814 			BEGIN
1815 				SELECT muc1.conversion_rate/muc2.conversion_rate INTO p_conv_rate
1816 				FROM mtl_uom_conversions muc1,
1817 		    		 mtl_uom_conversions muc2
1818 				WHERE muc1.inventory_item_id = 0
1819 					AND muc2.inventory_item_id = 0
1820 					AND muc1.uom_class = muc2.uom_class
1821 					AND muc1.uom_class = l_uom_class
1822 					AND muc1.uom_code = p_uom_code
1823 					AND muc2.uom_code = p_dest_uom_code
1824 					AND ROWNUM = 1;
1825 
1826 				EXCEPTION when NO_DATA_FOUND then
1827 				p_conv_found := FALSE;
1828 				p_conv_rate := 1.0;
1829 				return;
1830 			END;
1831 
1832 		ELSE
1833 			BEGIN
1834 	    	SELECT muc.conversion_rate INTO p_conv_rate
1835 	      FROM mtl_uom_conversions_view muc
1836 	      WHERE muc.inventory_item_id = p_inventory_item_id
1837 	      	AND muc.primary_uom_code = p_uom_code
1838 	      	AND muc.uom_code = p_dest_uom_code
1839 					AND rownum = 1;
1840 
1841 				EXCEPTION when NO_DATA_FOUND then
1842 				--The following alternative was taken from Anuj's snapshot file (jansanch)
1843 			  BEGIN
1844    				SELECT muc.conversion_rate INTO p_conv_rate
1845 	     		FROM mtl_uom_conversions_view muc
1846 		     	WHERE muc.inventory_item_id = p_inventory_item_id
1847 	      		AND muc.primary_uom_code = p_dest_uom_code
1848   	    		AND muc.uom_code = p_uom_code
1849 						AND rownum = 1;
1850 					EXCEPTION when NO_DATA_FOUND then
1851 	      		p_conv_found := FALSE;
1852 		     		p_conv_rate := 1.0;
1853 	 	    		return;
1854 				END;
1855 			END;
1856 		END IF;
1857 
1858 		p_conv_found := TRUE;
1859 
1860 	END;
1861 
1862 
1863 	PROCEDURE testConv(source varchar2, dest varchar2) IS
1864 		p_conv_found BOOLEAN;
1865 		p_conv_rate NUMBER;
1866 	BEGIN
1867 
1868 			GET_UOM_CONVERSION_RATES(source,dest,0,p_conv_found,p_conv_rate);
1869 			IF p_conv_found = TRUE THEN
1870 				debug_output('found, conv_rate=' || TO_CHAR(p_conv_rate));
1871 			ELSE
1872 				debug_output('not found');
1873 			END IF;
1874 	END testConv;
1875 
1876   --returns thresold (first looks for user value, then for global value if no user value is defined)
1877   --if no entry appears in mst_excep_preferences returns -999 (this is equivalent to a disabled exception)
1878   FUNCTION getExceptionThreshold (exceptionType NUMBER, userIdIn NUMBER) RETURN NUMBER IS
1879 	  total NUMBER;
1880     threshold NUMBER;
1881 	BEGIN
1882 		--get the threshold from mst_excep_preferences
1883    BEGIN
1884      SELECT nvl(threshold_value,0) INTO threshold
1885      FROM mst_excep_preferences
1886      WHERE exception_type = exceptionType
1887        and user_id = -9999
1888        and ROWNUM = 1;
1889    EXCEPTION
1890    WHEN NO_DATA_FOUND THEN
1891      --exception is disabled
1892               threshold := -999;
1893    END;
1894     RETURN threshold;
1895 	END getExceptionThreshold;
1896 
1897 
1898   PROCEDURE initializeGlobalVariables(plan_idIn IN NUMBER, user_idIn IN NUMBER) IS
1899 		p_conv_found BOOLEAN;
1900 	  convRateTime NUMBER;
1901     convRateDistance NUMBER;
1902     lAvgHwayDist NUMBER;
1903     lDisConstant NUMBER;
1904     lDistanceUomCode VARCHAR2(3);
1905     lTimeUomCode VARCHAR2(3);
1906   BEGIN
1907 		tp_plan_id := plan_idIn;
1908 
1909     --get TP UOMs
1910 		SELECT p.TIME_UOM, p.DISTANCE_UOM, p.dimension_uom, p.volume_uom
1911     INTO tp_time_uom, tp_distance_uom, tp_dimension_uom, tp_volume_uom
1912     FROM MST_PLANS p
1913 		WHERE plan_id = plan_idIn;
1914     debug_output('tp_distance_uom=' || tp_distance_uom || ', tp_time_uom=' || tp_time_uom);
1915     debug_output('tp_dimension_uom=' || tp_dimension_uom || ', tp_volume_uom=' || tp_volume_uom);
1916 
1917     --Code adapted from snapshot "/mstdev/mst/11.5/src/snap/mstsplno.ppc" to obtain avg_driving_speed and distance_scale_factor
1918     BEGIN
1919       SELECT  nvl(wgp.AVG_HWAY_SPEED,'-99') , nvl(wgp.TL_HWAY_DIS_EMP_CONSTANT,'-99'), wgp.GU_DISTANCE_UOM, wgp.TIME_UOM
1920       INTO lAvgHwayDist, lDisConstant, lDistanceUomCode, lTimeUomCode
1921       FROM MST_PARAMETERS mgp,  WSH_GLOBAL_PARAMETERS wgp, MST_PARAMETERS mup
1922       WHERE mgp.user_id  = -9999
1923         and mup.user_id = user_idIn
1924         and rownum = 1;
1925     EXCEPTION
1926       WHEN NO_DATA_FOUND THEN
1927       BEGIN
1928         debug_output('first select gave no results in parameters query');
1929         SELECT nvl(wgp.AVG_HWAY_SPEED,'-99'), nvl(wgp.TL_HWAY_DIS_EMP_CONSTANT,'-99'), wgp.GU_DISTANCE_UOM, wgp.TIME_UOM
1930         INTO lAvgHwayDist, lDisConstant, lDistanceUomCode, lTimeUomCode
1931         FROM MST_PARAMETERS mgp, WSH_GLOBAL_PARAMETERS wgp
1932         WHERE mgp.user_id  = -9999
1933           and rownum = 1;
1934       EXCEPTION
1935         WHEN NO_DATA_FOUND THEN
1936           debug_output('second select gave no results in parameters query, assuming defaults');
1937           lAvgHwayDist := 59;
1938           lDisConstant := 0;
1939           lTimeUomCode := tp_time_uom;
1940           lDistanceUomCode := tp_distance_uom;
1941       END;
1942     END;
1943 
1944     debug_output('AvgHwayDist= ' || lAvgHwayDist || ',lDistanceUomCode=<' || lDistanceUomCode || '>,lTimeUomCode=' || lTimeUomCode || ', lDisConstant=' || lDisConstant);
1945     IF lDistanceUomCode <> tp_distance_uom AND lDistanceUomCode <> '-99' THEN
1946       GET_UOM_CONVERSION_RATES(lDistanceUomCode, tp_distance_uom, 0, p_conv_found, convRateDistance);
1947       IF p_conv_found = false THEN
1948         convRateDistance := 1;
1949       END IF;
1950     ELSE
1951       convRateDistance := 1;
1952     END IF;
1953     debug_output('convRateDistance=' || convRateDistance);
1954 
1955     IF lTimeUomCode <> tp_time_uom AND lTimeUomCode <> '-99' THEN
1956       GET_UOM_CONVERSION_RATES(lTimeUomCode, tp_time_uom, 0, p_conv_found, convRateTime);
1957       IF p_conv_found = false THEN
1958         convRateTime := 1;
1959       END IF;
1960     ELSE
1961       convRateTime := 1;
1962     END IF;
1963     debug_output('convRateTime=' || convRateTime);
1964 
1965     --set global variables for later use
1966     avgDrvSpeed := (lAvgHwayDist * convRateDistance)/convRateTime;
1967     distScaleFactor := lDisConstant;
1968 
1969  		debug_output('avgDrvSpeed = ' || avgDrvSpeed);
1970 		debug_output('distScaleFactor = ' || distScaleFactor);
1971     debug_output('----');
1972   END initializeGlobalVariables;
1973 
1974 	--Run all the exceptions in the audit report (each exception checks if it is enabled or not)
1975 	PROCEDURE runAuditReport(errbuf OUT NOCOPY VARCHAR2,
1976 												   retcode OUT NOCOPY NUMBER,
1977 													 plan_idIn IN NUMBER,
1978 													 snapshotIsCaller IN NUMBER DEFAULT 2) IS
1979 		planRows NUMBER;
1980     user_id NUMBER(15);
1981 
1982 		mst_state NUMBER;
1983 		mst_program NUMBER;
1984 		mst_request_id NUMBER;
1985 	  own_request_id NUMBER;
1986 	BEGIN
1987 		msg_seq_num  := 0;
1988 
1989 		SELECT count(*) into planRows
1990 		FROM mst_plans
1991 	  WHERE plan_id = plan_idIn;
1992 
1993 		IF planRows <> 1 THEN
1994 			SELECT 'no entry or too many entries in mst plans for plan ' || TO_CHAR(plan_idIn)
1995 			INTO errbuf
1996 			FROM dual;
1997 			retcode := 2;
1998 			RETURN;
1999 		END IF;
2000 
2001 
2002     --Obtain data from mst_plans
2003     SELECT created_by, state, program, request_id
2004 		INTO	user_id, mst_state, mst_program, mst_request_id
2005     FROM mst_plans
2006     WHERE plan_id = plan_idIn;
2007 
2008 		debug_output('MST_PLANS.state=' || mst_state);
2009 		debug_output('MST_PLANS.program=' || mst_program);
2010 		debug_output('MST_PLANS.request_id=' || mst_request_id);
2011 		debug_output('snapshotIsCaller=' || snapshotIsCaller);
2012 
2013 		--Determine if audit report can be run. Need to check if another instance of engine/snapshot/audit is running
2014 		--Obtain own request id
2015 		own_request_id := fnd_profile.value('CONC_REQUEST_ID');
2016 		IF own_request_id IS NULL THEN
2017 			debug_output('No CONC_REQUEST_ID present');
2018 		END IF;
2019 		debug_output('own_request_id=' || own_request_id);
2020 
2021 
2022 	IF mst_request_id <> own_request_id THEN
2023 		--Prevent audit report from running when data has not been snapshoted
2024 		IF mst_state IS NULL THEN
2025 			debug_output('Data needs to be snapshoted before running audit report');
2026 			SELECT 'Data needs to be snapshoted before running audit report'
2027 			INTO errbuf
2028 			FROM dual;
2029 			retcode := 3;
2030 			RETURN;
2031 		END IF;
2032 	ELSE
2033 		debug_output('mst_request_id == owd_request_id');
2034 	END IF;
2035 
2036 /*
2037 		IF mst_request_id <> own_request_id THEN
2038 			--IF state <> snapshot done AND state <> optimization done THEN exit
2039 			IF mst_state <> 1 AND mst_state <> 2 THEN
2040 				debug_output('Audit report cannot be run in current state, state = ' || TO_CHAR(mst_state));
2041 				SELECT 'Audit report cannot be run in current state, state = ' || TO_CHAR(mst_state)
2042 				INTO errbuf
2043 				FROM dual;
2044 				retcode := 3;
2045 				RETURN;
2046 			END IF;
2047 		ELSE
2048 			debug_output('mst_request_id == owd_request_id');
2049 		END IF;
2050 */
2051 
2052 		--update MST_PLANS signaling successful start of audit report
2053 		UPDATE MST_PLANS
2054 		SET state=4, program=8, request_id = own_request_id
2055 	  WHERE plan_id = plan_idIn;
2056 		COMMIT;
2057 
2058 		debug_output('Entering initializeGlobalVariables');
2059     initializeGlobalVariables(plan_idIn, user_id);
2060 		debug_output('Done with initializeGlobalVariables');
2061 
2062     debug_output('----');
2063 
2064 		debug_output('Entering MissingLatLongCoordExcptn');
2065 		MissingLatLongCoordExcptn(plan_idIn, user_id);
2066 		debug_output('Done with MissingLatLongCoordExcptn');
2067 
2068     debug_output('----');
2069 
2070 		debug_output('Entering MissingDistanceDataExcptn');
2071 		MissingDistanceDataExcptn(plan_idIn, user_id);
2072 		debug_output('Done with MissingDistanceDataExcptn');
2073 
2074     debug_output('----');
2075 
2076 		debug_output('Entering DimensionViolForPieceExcptn');
2077 		DimensionViolForPieceExcptn(plan_idIn,user_id);
2078 		debug_output('Done with DimensionViolForPieceExcptn');
2079 
2080     debug_output('----');
2081 
2082 		debug_output('Entering DL_with_zero_values');
2083 		DL_with_zero_values(plan_idIn,user_id);
2084 		debug_output('Done with DL_with_zero_values');
2085 
2086     debug_output('----');
2087 
2088 		debug_output('Entering WgtVolViolForPieceExcptn');
2089 		WgtVolViolForPieceExcptn(plan_idIn,user_id);
2090 		debug_output('Done with WgtVolViolForPieceExcptn');
2091 
2092     debug_output('----');
2093 
2094 		debug_output('Entering WgtVolViolForDLExcptn');
2095 		WgtVolViolForDLExcptn(plan_idIn,user_id);
2096 		debug_output('Done with WgtVolViolForDLExcptn');
2097 
2098     debug_output('----');
2099 
2100 		debug_output('Entering WgtVolViolForFirmDelivExcptn');
2101 		WgtVolViolForFirmDelivExcptn(plan_idIn,user_id);
2102 		debug_output('Done with WgtVolViolForFirmDelivExcptn');
2103 
2104     debug_output('----');
2105 
2106 		debug_output('Entering InsufficientIntransitTimeExptn');
2107 		InsufficientIntransitTimeExptn(plan_idIn,user_id);
2108 		debug_output('Done with InsufficientIntransitTimeExptn');
2109 
2110     debug_output('----');
2111 
2112 		debug_output('Entering PastDueOrdersExptn');
2113 		PastDueOrdersExptn(plan_idIn,user_id);
2114 		debug_output('Done with PastDueOrdersExptn');
2115 
2116     debug_output('----');
2117 
2118 		debug_output('Entering FacCalViolForPickUpExptn');
2119 		FacCalViolForPickUpExptn(plan_idIn,user_id);
2120 		debug_output('Done with FacCalViolForPickUpExptn');
2121 
2122     debug_output('----');
2123 
2124 		debug_output('Entering FacCalViolForDeliveryExptn');
2125 		FacCalViolForDeliveryExptn(plan_idIn,user_id);
2126 		debug_output('Done with FacCalViolForDeliveryExptn');
2127 
2128     commit;
2129 
2130 		--if snapshotIsCaller == 1 then update state to 1
2131 		IF snapshotIsCaller = 1 THEN
2132 			mst_state := 1;
2133 		END IF;
2134 
2135 		--update MST_PLANS signaling successful end of audit report
2136 		UPDATE MST_PLANS
2137 		SET state=mst_state, program=NULL
2138 	  WHERE plan_id = plan_idIn;
2139 		debug_output('Update MST_PLANS.program = NULL');
2140 		debug_output('Update MST_PLANS.state = ' || mst_state);
2141 		debug_output('Audit report finished successfully, exiting now...');
2142     commit;
2143 
2144 		errbuf := NULL;
2145 		retcode := 0;
2146 	END runAuditReport;
2147 
2148 
2149 	PROCEDURE debug_output(p_str in varchar2) IS
2150    var NUMBER;
2151   BEGIN
2152 --    fnd_file.put_line( FND_FILE.LOG, p_str);
2153 --dbms_output.put_line(p_str);
2154 
2155 /*
2156 Use following to create table for debug:
2157 	create table mst_audit_rep_excp_debug(pk number, plan_id number,message_seq_num number, date_message date,message varchar2(255));
2158 	create sequence mst_audit_rep_excp_debug_s;
2159 Then uncomment code to insert messages to that table
2160 */
2161 
2162 /*
2163 	  insert into mst_audit_rep_excp_debug(pk, plan_id,message_seq_num, date_message,message)
2164 					 values (mst_audit_rep_excp_debug_s.nextval, tp_plan_id, msg_seq_num, sysdate, p_str);
2165 	  msg_seq_num := msg_seq_num + 1;
2166 		commit;
2167 */
2168 	  var := 0;
2169   END debug_output;
2170 
2171 END MST_AUDIT_REP_EXCP;