1 PACKAGE BODY WMS_XDOCK_PEGGING_PUB AS
2 /* $Header: WMSXDCKB.pls 120.23.12010000.1 2008/07/28 18:38:31 appldev ship $ */
3
4
5 -- Global constants holding the package name and package version
6 g_pkg_name CONSTANT VARCHAR2(30) := 'WMS_XDOCK_PEGGING_PUB';
7 g_pkg_version CONSTANT VARCHAR2(100) := '$Header: WMSXDCKB.pls 120.23.12010000.1 2008/07/28 18:38:31 appldev ship $';
8
9 -- This is the global cache table used to store the crossdock criteria records
10 -- encountered during crossdock pegging. This is defined solely in the package body
11 -- so only the procedures and functions in this package can access it directly.
12 -- Set, Get, Delete, and Clear functions will be provided for outside callers.
13 TYPE crossdock_criteria_tb IS TABLE OF wms_crossdock_criteria%ROWTYPE
14 INDEX BY BINARY_INTEGER;
15 g_crossdock_criteria_tb crossdock_criteria_tb;
16
17 -- This is the global cache table used to store the default routing ID for supplies
18 -- based on the item, org, and vendor. We do not want to include supply lines with a
19 -- routing ID of 3 = Direct. The available routing ID's are as follows:
20 -- 1. Standard 2. Inspect 3. Direct
21 TYPE routing_id_tb IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
22 g_item_routing_id_tb routing_id_tb;
23 g_org_routing_id_tb routing_id_tb;
24 g_vendor_routing_id_tb routing_id_tb;
25
26 -- The following types are used to cache the UOM conversions. The three keys to this
27 -- are the inventory item, from UOM code, and to UOM code. This will yield the conversion
28 -- rate by using a nested PLSQL table structure.
29 TYPE to_uom_code_tb IS TABLE OF NUMBER INDEX BY VARCHAR2(3);
30 TYPE from_uom_code_tb IS TABLE OF to_uom_code_tb INDEX BY VARCHAR2(3);
31 TYPE item_uom_conversion_tb IS TABLE OF from_uom_code_tb INDEX BY BINARY_INTEGER;
32 g_item_uom_conversion_tb item_uom_conversion_tb;
33
34 -- The following are global constants used in this package.
35
36 -- Allocation method for the current pick release batch
37 G_INVENTORY_ONLY CONSTANT VARCHAR2(1) := 'I';
38 G_CROSSDOCK_ONLY CONSTANT VARCHAR2(1) := 'C';
39 G_PRIORITIZE_INVENTORY CONSTANT VARCHAR2(1) := 'N';
40 G_PRIORITIZE_CROSSDOCK CONSTANT VARCHAR2(1) := 'X';
41
42 -- Types of sources
43 G_SRC_TYPE_SUP CONSTANT NUMBER := 1; -- Source type Supply
44 G_SRC_TYPE_DEM CONSTANT NUMBER := 2; -- Source type Demand
45
46 -- Crossdock criterion types
47 G_CRT_TYPE_OPP CONSTANT NUMBER := 1; -- Criterion type Opportunistic
48 G_CRT_TYPE_PLAN CONSTANT NUMBER := 2; -- Criterion type Planned
49
50 -- Crossdock criterion rule types
51 G_CRT_RULE_TYPE_OPP CONSTANT NUMBER := 10; -- Criterion Rule type Opportunistic
52 G_CRT_RULE_TYPE_PLAN CONSTANT NUMBER := 11; -- Criterion Rule type Planned
53
54 -- Scheduling methods
55 G_APPT_START_TIME CONSTANT NUMBER := 1; -- Start of dock appointment
56 G_APPT_MEAN_TIME CONSTANT NUMBER := 2; -- Mean of dock appointment
57 G_APPT_END_TIME CONSTANT NUMBER := 3; -- End of dock appointment
58
59 -- Crossdocking goals
60 G_MINIMIZE_WAIT CONSTANT NUMBER := 1; -- Minimize time between receipt and shipment
61 G_MAXIMIZE_XDOCK CONSTANT NUMBER := 2; -- Maximize time between receipt and shipment
62 G_CUSTOM_GOAL CONSTANT NUMBER := 3; -- Order supply/demand lines using custom logic
63
64 -- Supply sources for Planned Crossdock
65 G_PLAN_SUP_PO_APPR CONSTANT NUMBER := 10; -- Approved PO
66 G_PLAN_SUP_ASN CONSTANT NUMBER := 20; -- ASN
67 G_PLAN_SUP_REQ CONSTANT NUMBER := 30; -- Internal Req
68 G_PLAN_SUP_INTR CONSTANT NUMBER := 40; -- Intransit Shipments
69 G_PLAN_SUP_WIP CONSTANT NUMBER := 50; -- WIP
70 G_PLAN_SUP_RCV CONSTANT NUMBER := 60; -- Material in Receiving
71
72 -- Demand sources for Opportunistic Crossdock
73 G_OPP_DEM_SO_SCHED CONSTANT NUMBER := 10; -- Sales Order (Scheduled)
74 G_OPP_DEM_SO_BKORD CONSTANT NUMBER := 20; -- Sales Order (Backordered)
75 G_OPP_DEM_IO_SCHED CONSTANT NUMBER := 30; -- Internal Order (Scheduled)
76 G_OPP_DEM_IO_BKORD CONSTANT NUMBER := 40; -- Internal Order (Backordered)
77 G_OPP_DEM_WIP_BKORD CONSTANT NUMBER := 50; -- WIP Component Demand (Backordered)
78
79
80 -- Procedure to print debug messages.
81 -- We will rely on the caller to this procedure to determine if debug logging
82 -- should be done or not instead of querying for the profile value every time.
83 PROCEDURE print_debug(p_debug_msg IN VARCHAR2)
84 IS
85 BEGIN
86 inv_mobile_helper_functions.tracelog
87 (p_err_msg => p_debug_msg,
88 p_module => 'WMS_XDock_Pegging_Pub',
89 p_level => 4);
90 END;
91
92
93 -- This function will store the crossdock criteria record inputted into the cache
94 -- {{******************** Crossdock Criteria Caching Functions ********************}}
95 FUNCTION set_crossdock_criteria
96 (p_criterion_id IN NUMBER) RETURN BOOLEAN
97 IS
98 BEGIN
99 IF (p_criterion_id IS NULL) THEN
100 RETURN FALSE;
101 END IF;
102
103 IF (g_crossdock_criteria_tb.EXISTS(p_criterion_id)) THEN
104 -- {{
105 -- Test setting the crossdock criteria record for a crossdock criterion that
106 -- is already cached. }}
107 RETURN TRUE;
108 ELSE
109 -- {{
110 -- Test setting the crossdock criteria record for a crossdock criterion that
111 -- has not yet been cached. }}
112 SELECT *
113 INTO g_crossdock_criteria_tb(p_criterion_id)
114 FROM wms_crossdock_criteria
115 WHERE criterion_id = p_criterion_id;
116 RETURN TRUE;
117 END IF;
118 EXCEPTION
119 WHEN OTHERS THEN
120 RETURN FALSE;
121 END set_crossdock_criteria;
122
123
124 -- This function will retrieve the crossdock criteria record inputted from the cache
125 FUNCTION get_crossdock_criteria
126 (p_criterion_id IN NUMBER) RETURN wms_crossdock_criteria%ROWTYPE
127 IS
128 BEGIN
129 IF (p_criterion_id IS NULL) THEN
130 RETURN NULL;
131 END IF;
132
133 IF (NOT g_crossdock_criteria_tb.EXISTS(p_criterion_id)) THEN
134 -- {{
135 -- Test retrieving a crossdock criteria record for a crossdock criterion that
136 -- has not yet been cached. }}
137 SELECT *
138 INTO g_crossdock_criteria_tb(p_criterion_id)
139 FROM wms_crossdock_criteria
140 WHERE criterion_id = p_criterion_id;
141 END IF;
142 -- {{
143 -- Test retrieving a crossdock criteria record for a crossdock criterion that
144 -- is already cached. }}
145 RETURN g_crossdock_criteria_tb(p_criterion_id);
146 EXCEPTION
147 WHEN OTHERS THEN
148 RETURN NULL;
149 END get_crossdock_criteria;
150
151
152 -- This function will delete the crossdock criteria record inputted from the cache
153 FUNCTION delete_crossdock_criteria
154 (p_criterion_id IN NUMBER) RETURN BOOLEAN
155 IS
156 BEGIN
157 IF (p_criterion_id IS NULL) THEN
158 RETURN FALSE;
159 END IF;
160
161 -- {{
162 -- Test deleting an existing crossdock criteria record from the cache. }}
163 -- {{
164 -- Test deleting a non-existing crossdock criteria record from the cache. }}
165 g_crossdock_criteria_tb.DELETE(p_criterion_id);
166 RETURN TRUE;
167 EXCEPTION
168 WHEN OTHERS THEN
169 RETURN FALSE;
170 END delete_crossdock_criteria;
171
172
173 -- This function will clear all of the crossdock criteria records stored in the cache
174 FUNCTION clear_crossdock_cache RETURN BOOLEAN
175 IS
176 BEGIN
177 -- {{
178 -- Test clearing the entire crossdock criteria cache. }}
179 g_crossdock_criteria_tb.DELETE;
180 RETURN TRUE;
181 EXCEPTION
182 WHEN OTHERS THEN
183 RETURN FALSE;
184 END clear_crossdock_cache;
185 -- {{ }}
186 -- {{******************** End Crossdock Criteria Caching Functions ********************}}
187 -- {{ }}
188
189
190 -- This is a function used to retrieve the default routing ID given an item, org,
191 -- and vendor as inputs. This function will use the same logic as the get_defaul_routing_id
192 -- in the INV_RCV_COMMON_APIS package. However we will cache all of the values retrieved
193 -- for performance. The order to search for a default routing ID is: item, vendor, org.
194 -- The org and item should always be inputted and be non-null.
195 -- {{ }}
196 -- {{******************** Function get_default_routing_id ********************}}
197 FUNCTION get_default_routing_id
198 (p_organization_id IN NUMBER,
199 p_item_id IN NUMBER,
200 p_vendor_id IN NUMBER
201 ) RETURN NUMBER DETERMINISTIC
202 IS
203 BEGIN
204 -- Get the default routing ID based on the item.
205 -- {{
206 -- Get the routing ID from the item when the info has been cached. }}
207 -- {{
208 -- Get the routing ID from the item when the info has not been cached. }}
209 IF (NOT g_item_routing_id_tb.EXISTS(p_item_id)) THEN
210 BEGIN
211 SELECT receiving_routing_id
212 INTO g_item_routing_id_tb(p_item_id)
213 FROM mtl_system_items
214 WHERE inventory_item_id = p_item_id
215 AND organization_id = p_organization_id;
216 EXCEPTION
217 WHEN NO_DATA_FOUND THEN
218 NULL;
219 WHEN OTHERS THEN
220 RAISE fnd_api.g_exc_unexpected_error;
221 END;
222 END IF;
223
224 -- Return the item default routing ID if a cached value exists
225 -- and is not null. A value might not exist in case of a
226 -- NO_DATA_FOUND exception in the query.
227 -- {{
228 -- Test for item routing ID exists but is NULL. Make sure we continue searching
229 -- for a routing ID at the other levels, i.e. vendor and org. }}
230 IF (g_item_routing_id_tb.EXISTS(p_item_id) AND
231 g_item_routing_id_tb(p_item_id) IS NOT NULL) THEN
232 RETURN g_item_routing_id_tb(p_item_id);
233 END IF;
234
235 -- Get the default routing ID based on the vendor
236 -- if a value is passed
237 -- {{
238 -- Get the routing ID from the vendor when the info has been cached. }}
239 -- {{
240 -- Get the routing ID from the vendor when the info has not been cached. }}
241 IF (p_vendor_id IS NOT NULL) THEN
242 IF (NOT g_vendor_routing_id_tb.EXISTS(p_vendor_id)) THEN
243 BEGIN
244 SELECT receiving_routing_id
245 INTO g_vendor_routing_id_tb(p_vendor_id)
246 FROM po_vendors
247 WHERE vendor_id = p_vendor_id;
248 EXCEPTION
249 WHEN NO_DATA_FOUND THEN
250 NULL;
251 WHEN OTHERS THEN
252 RAISE fnd_api.g_exc_unexpected_error;
253 END;
254 END IF;
255
256 -- Return the vendor default routing ID if a cached value exists
257 -- and is not null. A value might not exist in case of a
258 -- NO_DATA_FOUND exception in the query.
259 -- {{
260 -- Test for vendor routing ID exists but is NULL. Make sure we continue searching
261 -- for a routing ID at the other levels, i.e. org. }}
262 IF (g_vendor_routing_id_tb.EXISTS(p_vendor_id) AND
263 g_vendor_routing_id_tb(p_vendor_id) IS NOT NULL) THEN
264 RETURN g_vendor_routing_id_tb(p_vendor_id);
265 END IF;
266 END IF;
267
268 -- Get the default routing ID based on the org
269 -- {{
270 -- Get the routing ID from the org when the info has been cached. }}
271 -- {{
272 -- Get the routing ID from the org when the info has not been cached. }}
273 IF (NOT g_org_routing_id_tb.EXISTS(p_organization_id)) THEN
274 BEGIN
275 SELECT NVL(receiving_routing_id, 1)
276 INTO g_org_routing_id_tb(p_organization_id)
277 FROM rcv_parameters
278 WHERE organization_id = p_organization_id;
279 EXCEPTION
280 WHEN NO_DATA_FOUND THEN
281 NULL;
282 WHEN OTHERS THEN
283 RAISE fnd_api.g_exc_unexpected_error;
284 END;
285 END IF;
286
287 -- Return the org default routing ID if a cached value exists
288 -- and is not null. A value might not exist in case of a
289 -- NO_DATA_FOUND exception in the query.
290 -- {{
291 -- Test for org routing ID exists but is NULL. Make sure we continue searching
292 -- for a routing ID at the other levels. (In this case, there are no places left
293 -- to search for a routing ID). }}
294 IF (g_org_routing_id_tb.EXISTS(p_organization_id) AND
295 g_org_routing_id_tb(p_organization_id) IS NOT NULL) THEN
296 RETURN g_org_routing_id_tb(p_organization_id);
297 END IF;
298
299 -- This case should not happen but return 1 in case nothing
300 -- has been found so far.
301 -- {{
302 -- When no routing ID can be determined, a value of 1 should be returned. }}
303 RETURN 1;
304
305 EXCEPTION
306 WHEN OTHERS THEN
307 -- If an exception occurs, just return a value of 1 to indicate
308 -- Standard routing as the default.
309 RETURN 1;
310 END get_default_routing_id;
311 -- {{ }}
312 -- {{******************** End get_default_routing_id ********************}}
313 -- {{ }}
314
315
316 -- This is a function used to retrieve the UOM conversion rate given an inventory item ID,
317 -- from UOM code and to UOM code. The values retrieved will be cached in a global PLSQL table.
318 -- {{ }}
319 -- {{******************** Function get_conversion_rate ********************}}
320 FUNCTION get_conversion_rate
321 (p_item_id IN NUMBER,
322 p_from_uom_code IN VARCHAR2,
323 p_to_uom_code IN VARCHAR2
324 ) RETURN NUMBER
325 IS
326 l_conversion_rate NUMBER;
327 BEGIN
328 IF (p_from_uom_code = p_to_uom_code) THEN
329 -- No conversion necessary
330 l_conversion_rate := 1;
331 ELSE
332 -- Check if the conversion rate for the item/from UOM/to UOM combination is cached
333 IF (g_item_uom_conversion_tb.EXISTS(p_item_id) AND
334 g_item_uom_conversion_tb(p_item_id).EXISTS(p_from_uom_code) AND
335 g_item_uom_conversion_tb(p_item_id)(p_from_uom_code).EXISTS(p_to_uom_code))
336 THEN
337 -- Conversion rate is cached so just use the value
338 l_conversion_rate :=
339 g_item_uom_conversion_tb(p_item_id)(p_from_uom_code)(p_to_uom_code);
340 ELSE
341 -- Conversion rate is not cached so query and store the value
342 inv_convert.inv_um_conversion(from_unit => p_from_uom_code,
343 to_unit => p_to_uom_code,
344 item_id => p_item_id,
345 uom_rate => l_conversion_rate);
346 IF (l_conversion_rate > 0) THEN
347 -- Store the conversion rate and also the reverse conversion.
348 -- Do this only if the conversion rate returned is valid, i.e. not negative.
349 -- {{
350 -- Test having an exception when retrieving the UOM conversion rate. }}
351 g_item_uom_conversion_tb(p_item_id)(p_from_uom_code)(p_to_uom_code)
352 := l_conversion_rate;
353 g_item_uom_conversion_tb(p_item_id)(p_to_uom_code)(p_from_uom_code)
354 := 1 / l_conversion_rate;
355 END IF;
356 END IF;
357 END IF;
358
359 -- Return the conversion rate retrieved
360 RETURN l_conversion_rate;
361
362 EXCEPTION
363 WHEN OTHERS THEN
364 -- If an exception occurs, return a negative value.
365 -- The calling program should interpret this as an exception in retrieving
366 -- the UOM conversion rate.
367 RETURN -999;
368 END get_conversion_rate;
369 -- {{ }}
370 -- {{******************** End get_conversion_rate ********************}}
371 -- {{ }}
372
373
374 -- Function to see if the inputted WDD demand line is associated with an order line that
375 -- is tied to a WIP supply somehow. i.e. Either already crossdocked or through an existing
376 -- manual reservation with WIP as the supply for that demand. This is needed in case we
377 -- do not want to have order lines partially crossdocked to WIP and other supply types.
378 -- {{ }}
379 -- {{******************** Function is_demand_tied_to_wip ********************}}
380 FUNCTION is_demand_tied_to_wip
381 (p_organization_id IN NUMBER,
382 p_inventory_item_id IN NUMBER,
383 p_demand_type_id IN NUMBER,
384 p_demand_header_id IN NUMBER,
385 p_demand_line_id IN NUMBER
386 ) RETURN VARCHAR2
387 IS
388 l_wip_exists NUMBER;
389
390 BEGIN
391 -- See if there is an existing reservation tying a WIP supply to this demand order line.
392 -- {{
393 -- Test for an OE demand input that is tied to a WIP supply and one that is not. }}
394 BEGIN
395 SELECT 1
396 INTO l_wip_exists
397 FROM dual
398 WHERE EXISTS (SELECT reservation_id
399 FROM mtl_reservations
400 WHERE organization_id = p_organization_id
401 AND inventory_item_id = p_inventory_item_id
402 AND demand_source_type_id = p_demand_type_id
403 AND demand_source_header_id = p_demand_header_id
404 AND demand_source_line_id = p_demand_line_id
405 AND supply_source_type_id = inv_reservation_global.g_source_type_wip);
406 EXCEPTION
407 WHEN OTHERS THEN
408 -- This should be when no reservations are found
409 RETURN 'N';
410 END;
411
412 -- If a reservations exists tying a WIP supply to the demand, return 'Y'.
413 IF (l_wip_exists IS NOT NULL) THEN
414 RETURN 'Y';
415 ELSE
416 RETURN 'N';
417 END IF;
418
419 END is_demand_tied_to_wip;
420 -- {{ }}
421 -- {{******************** End is_demand_tied_to_wip ********************}}
422 -- {{ }}
423
424
425 -- Function to see if the inputted WDD demand line is associated with an order line that
426 -- is tied to a non-WIP and non-Inventory supply somehow. i.e. Either already crossdocked or
427 -- through an existing manual reservation with a non-WIP and non-Inventory supply for that
428 -- demand. This is needed in case we do not want to have order lines partially crossdocked
429 -- to WIP and other supply types.
430 -- {{ }}
431 -- {{******************** Function is_demand_tied_to_non_wip ********************}}
432 FUNCTION is_demand_tied_to_non_wip
433 (p_organization_id IN NUMBER,
434 p_inventory_item_id IN NUMBER,
435 p_demand_type_id IN NUMBER,
436 p_demand_header_id IN NUMBER,
437 p_demand_line_id IN NUMBER
438 ) RETURN VARCHAR2
439 IS
440 l_non_wip_exists NUMBER;
441
442 BEGIN
443 -- See if there is an existing reservation tying a non-WIP and non-Inventory supply
444 -- to this demand order line.
445 -- {{
446 -- Test for an OE demand input that is tied to a non-WIP and non-INV supply
447 -- and one that is not. }}
448 BEGIN
449 SELECT 1
450 INTO l_non_wip_exists
451 FROM dual
452 WHERE EXISTS (SELECT reservation_id
453 FROM mtl_reservations
454 WHERE organization_id = p_organization_id
455 AND inventory_item_id = p_inventory_item_id
456 AND demand_source_type_id = p_demand_type_id
457 AND demand_source_header_id = p_demand_header_id
458 AND demand_source_line_id = p_demand_line_id
459 AND supply_source_type_id <> inv_reservation_global.g_source_type_wip
460 AND supply_source_type_id <> inv_reservation_global.g_source_type_inv);
461 EXCEPTION
462 WHEN OTHERS THEN
463 -- This should be when no reservations are found
464 RETURN 'N';
465 END;
466
467 -- If a reservations exists tying a non-WIP and non-Inventory supply to the demand,
468 -- return 'Y'.
469 IF (l_non_wip_exists IS NOT NULL) THEN
470 RETURN 'Y';
471 ELSE
472 RETURN 'N';
473 END IF;
474
475 END is_demand_tied_to_non_wip;
476 -- {{ }}
477 -- {{******************** End is_demand_tied_to_non_wip ********************}}
478 -- {{ }}
479
480
481 -- This is a private procedure used to crossdock/split a WDD record during pegging.
482 -- A common procedure is created since this exact piece of code is called in two places
483 -- for satisfying existing reservations and newly created crossdock reservations.
484 -- {{ }}
485 -- {{******************** Procedure Crossdock_WDD ********************}}
486 PROCEDURE Crossdock_WDD
487 (p_log_prefix IN VARCHAR2,
488 p_crossdock_type IN NUMBER,
489 p_batch_id IN NUMBER,
490 p_wsh_release_table IN OUT NOCOPY WSH_PR_CRITERIA.relRecTabTyp,
491 p_trolin_delivery_ids IN OUT NOCOPY WSH_UTIL_CORE.Id_Tab_Type,
492 p_del_detail_id IN OUT NOCOPY WSH_PICK_LIST.DelDetTabTyp,
493 l_wdd_index IN OUT NOCOPY NUMBER,
494 l_debug IN OUT NOCOPY NUMBER,
495 l_inventory_item_id IN OUT NOCOPY NUMBER,
496 l_wdd_txn_qty IN OUT NOCOPY NUMBER,
497 l_atd_qty IN OUT NOCOPY NUMBER,
498 l_atd_wdd_qty IN OUT NOCOPY NUMBER,
499 l_atd_wdd_qty2 IN OUT NOCOPY NUMBER,
500 l_supply_uom_code IN OUT NOCOPY VARCHAR2,
501 l_demand_uom_code IN OUT NOCOPY VARCHAR2,
502 l_demand_uom_code2 IN OUT NOCOPY VARCHAR2,
503 l_conversion_rate IN OUT NOCOPY NUMBER,
504 l_conversion_precision IN NUMBER,
505 l_demand_line_detail_id IN OUT NOCOPY NUMBER,
506 l_index IN OUT NOCOPY NUMBER,
507 l_detail_id_tab IN OUT NOCOPY WSH_UTIL_CORE.id_tab_type,
508 l_action_prms IN OUT NOCOPY WSH_GLBL_VAR_STRCT_GRP.dd_action_parameters_rec_type,
509 l_action_out_rec IN OUT NOCOPY WSH_GLBL_VAR_STRCT_GRP.dd_action_out_rec_type,
510 l_split_wdd_id IN OUT NOCOPY NUMBER,
511 l_detail_info_tab IN OUT NOCOPY WSH_INTERFACE_EXT_GRP.Delivery_Details_Attr_Tbl_Type,
512 l_in_rec IN OUT NOCOPY WSH_INTERFACE_EXT_GRP.detailInRecType,
513 l_out_rec IN OUT NOCOPY WSH_INTERFACE_EXT_GRP.detailOutRecType,
514 l_mol_line_id IN OUT NOCOPY NUMBER,
515 l_split_wdd_index IN OUT NOCOPY NUMBER,
516 l_split_delivery_index IN OUT NOCOPY NUMBER,
517 l_split_wdd_rel_rec IN OUT NOCOPY WSH_PR_CRITERIA.relRecTyp,
518 l_allocation_method IN OUT NOCOPY VARCHAR2,
519 l_demand_qty IN OUT NOCOPY NUMBER,
520 l_demand_qty2 IN OUT NOCOPY NUMBER,
521 l_demand_atr_qty IN OUT NOCOPY NUMBER,
522 l_xdocked_wdd_index IN OUT NOCOPY NUMBER,
523 l_supply_type_id IN OUT NOCOPY NUMBER,
524 x_return_status IN OUT NOCOPY VARCHAR2,
525 x_msg_count IN OUT NOCOPY NUMBER,
526 x_msg_data IN OUT NOCOPY VARCHAR2,
527 x_error_code OUT NOCOPY VARCHAR2)
528 IS
529 l_progress VARCHAR2(10);
530
531 BEGIN
532 -- Check if we need to split the WDD record or not based on the ATD qty
533 IF (l_wdd_txn_qty > l_atd_qty) THEN
534 IF (l_debug = 1) THEN
535 print_debug(p_log_prefix || 'WDD txn qty > ATD qty, so need to split the WDD record');
536 END IF;
537 -- Split the WDD record.
538 -- {{
539 -- Test for WDD record being split when crossdocking an existing reservation. }}
540
541 -- First convert l_atd_qty to the UOM on the WDD line
542 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
543 l_supply_uom_code, l_demand_uom_code);
544 IF (l_conversion_rate < 0) THEN
545 IF (l_debug = 1) THEN
546 print_debug(p_log_prefix || 'Error while obtaining UOM conversion rate for WDD');
547 END IF;
548 -- Raise an exception. The caller will do the rollback, cleanups,
549 -- and decide where to goto next.
550 x_error_code := 'UOM';
551 RAISE FND_API.G_EXC_ERROR;
552 END IF;
553 -- Round the converted quantity to the standard precision
554 l_atd_wdd_qty := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
555 IF (l_debug = 1) THEN
556 print_debug(p_log_prefix || 'ATD qty in WDD UOM: => ' || l_atd_wdd_qty || ' ' ||
557 l_demand_uom_code);
558 END IF;
559 l_progress := '10';
560
561 -- Convert l_atd_qty to the secondary UOM on the WDD line if a value exists
562 IF (l_demand_uom_code2 IS NOT NULL) THEN
563 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
564 l_supply_uom_code, l_demand_uom_code2);
565 IF (l_conversion_rate < 0) THEN
566 IF (l_debug = 1) THEN
567 print_debug(p_log_prefix || 'Error while obtaining secondary UOM conversion rate for WDD');
568 END IF;
569 -- Raise an exception. The caller will do the rollback, cleanups,
570 -- and decide where to goto next.
571 x_error_code := 'UOM';
572 RAISE FND_API.G_EXC_ERROR;
573 END IF;
574 -- Round the converted quantity to the standard precision
575 l_atd_wdd_qty2 := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
576 ELSE
577 -- Secondary WDD UOM code is NULL
578 l_atd_wdd_qty2 := NULL;
579 END IF; -- End retrieving conversion rate
580 IF (l_debug = 1) THEN
581 print_debug(p_log_prefix || 'ATD qty in WDD secondary UOM: => ' || l_atd_wdd_qty2 || ' ' ||
582 l_demand_uom_code2);
583 END IF;
584 l_progress := '20';
585
586 -- Split the WDD line with the partial quantity allocated. The original WDD
587 -- line will retain the unallocated quantity.
588 l_detail_id_tab(1) := l_demand_line_detail_id;
589 l_action_prms.caller := 'WMS_XDOCK_PEGGING_PUB';
590 l_action_prms.action_code := 'SPLIT-LINE';
591 l_action_prms.split_quantity := l_atd_wdd_qty;
592 l_action_prms.split_quantity2 := l_atd_wdd_qty2;
593
594 IF (l_debug = 1) THEN
595 print_debug(p_log_prefix || 'Call the Delivery_Detail_Action API to split the WDD');
596 END IF;
597 WSH_INTERFACE_GRP.Delivery_Detail_Action
598 (p_api_version_number => 1.0,
599 p_init_msg_list => fnd_api.g_false,
600 p_commit => fnd_api.g_false,
601 x_return_status => x_return_status,
602 x_msg_count => x_msg_count,
603 x_msg_data => x_msg_data,
604 p_detail_id_tab => l_detail_id_tab,
605 p_action_prms => l_action_prms,
606 x_action_out_rec => l_action_out_rec
607 );
608
609 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
610 IF (l_debug = 1) THEN
611 print_debug(p_log_prefix || 'Error returned from Split Delivery_Detail_Action API: '
612 || x_return_status);
613 END IF;
614 -- Raise an exception. The caller will do the rollback, cleanups,
615 -- and decide where to goto next.
616 x_error_code := 'DB';
617 RAISE FND_API.G_EXC_ERROR;
618 END IF;
619 IF (l_debug = 1) THEN
620 print_debug(p_log_prefix || 'Successfully split the WDD record');
621 END IF;
622 l_progress := '30';
623
624 l_index := l_action_out_rec.result_id_tab.FIRST;
625 l_split_wdd_id := l_action_out_rec.result_id_tab(l_index);
626
627 -- Do the following logic only for Planned Crossdocking
628 IF (p_crossdock_type = G_CRT_TYPE_PLAN) THEN
629 -- Insert the split WDD line into p_wsh_release_table.
630 -- The split WDD release record should be the same as the original one with
631 -- only the following fields modified: delivery_detail_id, released_status,
632 -- move_order_line_id (if supply used is receiving) and requested_quantity fields
633 l_split_wdd_rel_rec := p_wsh_release_table(l_wdd_index);
634 l_split_wdd_rel_rec.delivery_detail_id := l_split_wdd_id;
635 l_split_wdd_rel_rec.released_status := 'S';
636 l_split_wdd_rel_rec.move_order_line_id := l_mol_line_id;
637 l_split_wdd_rel_rec.requested_quantity := l_atd_wdd_qty;
638 l_split_wdd_rel_rec.requested_quantity2 := l_atd_wdd_qty2;
639
640 l_index := p_wsh_release_table.LAST + 1;
641 p_wsh_release_table(l_index) := l_split_wdd_rel_rec;
642 -- Store this newly inserted split WDD index value. In case of rollback,
643 -- we need to remove this record from p_wsh_release_table.
644 l_split_wdd_index := l_index;
645
646 -- Update the original WDD line in p_wsh_release_table with the current
647 -- unallocated quantity while retaining the original released_status
648 -- (should be 'R' or 'B'). Do this in the UOM of the WDD line and also update
649 -- the secondary requested quantity field.
650 p_wsh_release_table(l_wdd_index).requested_quantity := l_demand_qty - l_atd_wdd_qty;
651 p_wsh_release_table(l_wdd_index).requested_quantity2 := l_demand_qty2 - l_atd_wdd_qty2;
652
653 IF (l_debug = 1) THEN
654 print_debug(p_log_prefix || 'Updated the WDD records in p_wsh_release_table');
655 END IF;
656 END IF; -- End of: IF (p_crossdock_type = G_CRT_TYPE_PLAN) THEN
657
658 -- Update the demand qty variable to indicate how much quantity on the original
659 -- WDD demand line is left to be crossdocked if not crossdocked already.
660 -- This is done here outside of the crossdock type loop so opportunistic crossdocking
661 -- can have visibility to how much of the WDD demand line was used for crossdock.
662 l_demand_qty := l_demand_qty - l_atd_wdd_qty;
663 l_demand_qty2 := l_demand_qty2 - l_atd_wdd_qty2;
664 -- Update the demand ATR qty variable if necessary.
665 -- This is needed for Planned Crossdocking when looping through the available supply lines
666 -- in case the WDD demand gets split. The unallocated WDD that loops again needs to have
667 -- the correct ATR qty otherwise the ATD qty calculated will be incorrect.
668 IF (l_demand_atr_qty IS NOT NULL) THEN
669 l_demand_atr_qty := l_demand_atr_qty - l_atd_wdd_qty;
670 ELSE
671 -- NULL value of demand ATR qty implies we are trying to satisfy an existing
672 -- reservation and there was no need to calculate the ATR qty on the demand line.
673 -- All of the qty on it should be reservable. In that case, we do not need to
674 -- update this variable since it isn't used. Doing it here for completeness.
675 l_demand_atr_qty := l_demand_qty;
676 END IF;
677 l_progress := '40';
678 ELSE
679 IF (l_debug = 1) THEN
680 print_debug(p_log_prefix || 'WDD txn qty = ATD qty, so no need to split the WDD record');
681 END IF;
682 -- {{
683 -- Test for WDD qty = available to detail qty. WDD record should be crossdocked
684 -- properly. }}
685
686 -- Do the following logic only for Planned Crossdocking
687 IF (p_crossdock_type = G_CRT_TYPE_PLAN) THEN
688 -- Crossdock/Update the corresponding record in p_wsh_release_table
689 p_wsh_release_table(l_wdd_index).released_status := 'S';
690 p_wsh_release_table(l_wdd_index).move_order_line_id := l_mol_line_id;
691 END IF;
692
693 -- Set the split WDD ID. Even though the WDD record did not get split,
694 -- this variable is used later on to refer to the WDD ID that was crossdocked.
695 l_split_wdd_id := l_demand_line_detail_id;
696
697 -- Update the demand qty variable to indicate how much quantity on the original
698 -- WDD demand line is left to be crossdocked if not crossdocked already.
699 -- This is done here outside of the crossdock type loop so opportunistic crossdocking
700 -- can have visibility to how much of the WDD demand line was used for crossdock.
701 l_demand_qty := 0;
702 l_demand_qty2 := 0;
703 -- Update the demand ATR qty for completeness. This should not be required since
704 -- the WDD did not get split.
705 l_demand_atr_qty := 0;
706 l_progress := '50';
707 END IF; -- End splitting WDD record: Matches IF (l_wdd_txn_qty > l_atd_qty) THEN
708
709 -- Crossdock the WDD record with the allocated quantity.
710 -- Update the released_status to 'S' and update the move_order_line_id
711 -- column if the supply type used is Receiving.
712 IF (l_debug = 1) THEN
713 print_debug(p_log_prefix || 'Update the crossdocked WDD record: ' || l_split_wdd_id);
714 END IF;
715
716 -- Store the crossdocked WDD record to update in l_detail_info_tab.
717 -- The shipping API to update the table of WDD records will be done at the end
718 -- once all lines have been considered for crossdocking.
719 l_xdocked_wdd_index := l_detail_info_tab.COUNT + 1;
720 l_detail_info_tab(l_xdocked_wdd_index).delivery_detail_id := l_split_wdd_id;
721 l_detail_info_tab(l_xdocked_wdd_index).released_status := 'S';
722 -- For WIP supplies being crossdocked to a WDD demand, do not update
723 -- the move_order_line_id column. This is to mimic 11.5.10 and prior behavior.
724 IF (l_supply_type_id <> 5) THEN
725 l_detail_info_tab(l_xdocked_wdd_index).move_order_line_id := l_mol_line_id;
726 END IF;
727 -- For Planned Crossdocking, we also want to update the batch_id column in WDD
728 IF (p_crossdock_type = G_CRT_TYPE_PLAN) THEN
729 l_detail_info_tab(l_xdocked_wdd_index).batch_id := p_batch_id;
730 END IF;
731
732 -- Do the following logic only for Planned Crossdocking
733 IF (p_crossdock_type = G_CRT_TYPE_PLAN) THEN
734 -- Insert a new record into p_trolin_delivery_ids and p_del_detail_id
735 -- for the crossdocked WDD line if allocation method = N (Prioritize Inventory).
736 -- This needs to be done whether the crossdocked WDD is a newly split one, or a pre-existing
737 -- one in the release_table. Shipping does not populate the delivery tables with any info
738 -- so all crossdocked WDD records should have a record inserted there.
739 -- {{
740 -- Crossdocked WDD records should insert new records into the delivery tables for
741 -- allocation method of Prioritize Inventory. }}
742 IF (l_allocation_method = G_PRIORITIZE_INVENTORY) THEN
743 l_index := NVL(p_del_detail_id.LAST, 0) + 1;
744 p_del_detail_id(l_index) := l_split_wdd_id;
745 p_trolin_delivery_ids(l_index) := p_wsh_release_table(l_wdd_index).delivery_id;
746 -- Store this newly inserted delivery related index value. In case of rollback,
747 -- we need to remove these records from p_del_detail_id and p_trolin_delivery_ids.
748 l_split_delivery_index := l_index;
749 IF (l_debug = 1) THEN
750 print_debug(p_log_prefix || 'Inserted record into delivery tables for crossdocked WDD');
751 END IF;
752 END IF;
753 END IF;
754 l_progress := '60';
755
756 EXCEPTION
757 WHEN OTHERS THEN
758 x_return_status := fnd_api.g_ret_sts_error;
759 fnd_msg_pub.count_and_get(p_count => x_msg_count,
760 p_data => x_msg_data);
761 IF (l_debug = 1) THEN
762 print_debug(p_log_prefix || 'Exiting Crossdock_WDD - Execution error: ' ||
763 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
764 END IF;
765
766 END Crossdock_WDD;
767 -- {{ }}
768 -- {{******************** End Crossdock_WDD ********************}}
769 -- {{ }}
770
771
772 -- This is a private procedure used to crossdock/split an RSV record during
773 -- both Planned and Opportunistic crossdock pegging for existing reservations.
774 -- {{ }}
775 -- {{******************** Procedure Crossdock_RSV ********************}}
776 PROCEDURE Crossdock_RSV
777 (p_log_prefix IN VARCHAR2,
778 p_crossdock_type IN NUMBER,
779 l_debug IN OUT NOCOPY NUMBER,
780 l_inventory_item_id IN OUT NOCOPY NUMBER,
781 l_rsv_txn_qty IN OUT NOCOPY NUMBER,
782 l_atd_qty IN OUT NOCOPY NUMBER,
783 l_atd_rsv_qty IN OUT NOCOPY NUMBER,
784 l_atd_rsv_qty2 IN OUT NOCOPY NUMBER,
785 l_atd_prim_qty IN OUT NOCOPY NUMBER,
786 l_supply_uom_code IN OUT NOCOPY VARCHAR2,
787 l_rsv_uom_code IN OUT NOCOPY VARCHAR2,
788 l_rsv_uom_code2 IN OUT NOCOPY VARCHAR2,
789 l_primary_uom_code IN OUT NOCOPY VARCHAR2,
790 l_conversion_rate IN OUT NOCOPY NUMBER,
791 l_conversion_precision IN NUMBER,
792 l_original_rsv_rec IN OUT NOCOPY inv_reservation_global.mtl_reservation_rec_type,
793 l_rsv_id IN OUT NOCOPY NUMBER,
794 l_to_rsv_rec IN OUT NOCOPY inv_reservation_global.mtl_reservation_rec_type,
795 l_split_wdd_id IN OUT NOCOPY NUMBER,
796 l_crossdock_criteria_id IN OUT NOCOPY NUMBER,
797 l_demand_expected_time IN OUT NOCOPY DATE,
798 l_supply_expected_time IN OUT NOCOPY DATE,
799 l_original_serial_number IN OUT NOCOPY inv_reservation_global.serial_number_tbl_type,
800 l_split_rsv_id IN OUT NOCOPY NUMBER,
801 l_rsv_qty IN OUT NOCOPY NUMBER,
802 l_rsv_qty2 IN OUT NOCOPY NUMBER,
803 l_to_serial_number IN OUT NOCOPY inv_reservation_global.serial_number_tbl_type,
804 l_supply_type_id IN OUT NOCOPY NUMBER,
805 x_return_status IN OUT NOCOPY VARCHAR2,
806 x_msg_count IN OUT NOCOPY NUMBER,
807 x_msg_data IN OUT NOCOPY VARCHAR2,
808 x_error_code OUT NOCOPY VARCHAR2)
809 IS
810 l_progress VARCHAR2(10);
811
812 BEGIN
813 -- Check if we need to split the RSV record or not based on the ATD qty
814 IF (l_rsv_txn_qty > l_atd_qty) THEN
815 IF (l_debug = 1) THEN
816 print_debug(p_log_prefix || 'RSV txn qty > ATD qty, so need to split the RSV record');
817 END IF;
818 -- Split the RSV record.
819 -- {{
820 -- Test for RSV record being split when crossdocking an existing reservation. }}
821
822 -- First convert l_atd_qty to the UOM on the RSV line
823 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
824 l_supply_uom_code, l_rsv_uom_code);
825 IF (l_conversion_rate < 0) THEN
826 IF (l_debug = 1) THEN
827 print_debug(p_log_prefix || 'Error while obtaining UOM conversion rate for RSV');
828 END IF;
829 -- Raise an exception. The caller will do the rollback, cleanups,
830 -- and decide where to goto next.
831 x_error_code := 'UOM';
832 RAISE FND_API.G_EXC_ERROR;
833 END IF;
834 -- Round the converted quantity to the standard precision
835 l_atd_rsv_qty := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
836 IF (l_debug = 1) THEN
837 print_debug(p_log_prefix || 'ATD qty in RSV UOM: => ' || l_atd_rsv_qty || ' ' ||
838 l_rsv_uom_code);
839 END IF;
840 l_progress := '10';
841
842 -- Convert l_atd_qty to the secondary UOM on the RSV line if a value exists
843 IF (l_rsv_uom_code2 IS NOT NULL) THEN
844 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
845 l_supply_uom_code, l_rsv_uom_code2);
846 IF (l_conversion_rate < 0) THEN
847 IF (l_debug = 1) THEN
848 print_debug(p_log_prefix || 'Error while obtaining secondary UOM conversion rate for RSV');
849 END IF;
850 -- Raise an exception. The caller will do the rollback, cleanups,
851 -- and decide where to goto next.
852 x_error_code := 'UOM';
853 RAISE FND_API.G_EXC_ERROR;
854 END IF;
855 -- Round the converted quantity to the standard precision
856 l_atd_rsv_qty2 := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
857 ELSE
858 -- Secondary RSV UOM code is NULL
859 l_atd_rsv_qty2 := NULL;
860 END IF; -- End retrieving conversion rate
861 IF (l_debug = 1) THEN
862 print_debug(p_log_prefix || 'ATD qty in secondary RSV UOM: => ' || l_atd_rsv_qty2 || ' ' ||
863 l_rsv_uom_code2);
864 END IF;
865 l_progress := '20';
866
867 -- Do not modify the reservation if the supply is of type WIP.
868 -- We just want to update the l_rsv_qty and l_rsv_qty2 quantities.
869 IF (l_supply_type_id = 5) THEN
870 IF (l_debug = 1) THEN
871 print_debug(p_log_prefix || 'Do not modify the WIP as supply reservation');
872 END IF;
873 ELSE
874 -- Split the reservation with the quantity allocated. The original RSV record
875 -- will be the non-crossdocked one.
876 l_original_rsv_rec.reservation_id := l_rsv_id;
877
878 l_to_rsv_rec.demand_source_line_detail := l_split_wdd_id;
879 l_to_rsv_rec.reservation_quantity := l_atd_rsv_qty;
880 l_to_rsv_rec.reservation_uom_code := l_rsv_uom_code;
881 l_to_rsv_rec.secondary_reservation_quantity := l_atd_rsv_qty2;
882 l_to_rsv_rec.secondary_uom_code := l_rsv_uom_code2;
883 l_to_rsv_rec.primary_reservation_quantity := l_atd_prim_qty;
884 l_to_rsv_rec.primary_uom_code := l_primary_uom_code;
885 l_to_rsv_rec.crossdock_flag := 'Y';
886 l_to_rsv_rec.crossdock_criteria_id := l_crossdock_criteria_id;
887 l_to_rsv_rec.demand_ship_date := l_demand_expected_time;
888 l_to_rsv_rec.supply_receipt_date := l_supply_expected_time;
889
890 IF (l_debug = 1) THEN
891 print_debug(p_log_prefix || 'Call the transfer_reservation API to split the RSV record');
892 END IF;
893 INV_RESERVATION_PVT.transfer_reservation
894 (p_api_version_number => 1.0,
895 p_init_msg_lst => fnd_api.g_false,
896 x_return_status => x_return_status,
897 x_msg_count => x_msg_count,
898 x_msg_data => x_msg_data,
899 p_original_rsv_rec => l_original_rsv_rec,
900 p_to_rsv_rec => l_to_rsv_rec,
901 p_original_serial_number => l_original_serial_number,
902 p_validation_flag => fnd_api.g_true,
903 x_reservation_id => l_split_rsv_id);
904
905 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
906 IF (l_debug = 1) THEN
907 print_debug(p_log_prefix || 'Error returned from transfer_reservation API: '
908 || x_return_status);
909 END IF;
910 -- Raise an exception. The caller will do the rollback, cleanups,
911 -- and decide where to goto next.
912 x_error_code := 'DB';
913 RAISE FND_API.G_EXC_ERROR;
914 END IF;
915 IF (l_debug = 1) THEN
916 print_debug(p_log_prefix || 'Successfully split the RSV record');
917 END IF;
918 END IF;
919
920 -- Decrement the reservation qty variable so we know how much qty is left on the
921 -- original reservation to satisfy
922 l_rsv_qty := l_rsv_qty - l_atd_rsv_qty;
923 l_rsv_qty2 := l_rsv_qty2 - l_atd_rsv_qty2;
924 l_progress := '30';
925 ELSE
926 IF (l_debug = 1) THEN
927 print_debug(p_log_prefix || 'RSV txn qty = ATD qty, so no need to split the RSV record');
928 END IF;
929 -- l_rsv_txn_qty = l_atd_qty so just crossdock the RSV record.
930 -- Update the demand_source_line_detail column to the current WDD, set
931 -- crossdock_flag = 'Y', update the expected ship and receipt dates, and update
932 -- the crossdock criteria column.
933 -- {{
934 -- Test for RSV qty = available to detail qty. Reservation should be crossdocked
935 -- properly. }}
936
937 -- Do not modify the reservation if the supply is of type WIP.
938 -- We just want to update the l_rsv_qty and l_rsv_qty2 quantities.
939 IF (l_supply_type_id = 5) THEN
940 IF (l_debug = 1) THEN
941 print_debug(p_log_prefix || 'Do not modify the WIP as supply reservation');
942 END IF;
943 ELSE
944 l_original_rsv_rec.reservation_id := l_rsv_id;
945
946 l_to_rsv_rec.demand_source_line_detail := l_split_wdd_id;
947 l_to_rsv_rec.crossdock_flag := 'Y';
948 l_to_rsv_rec.crossdock_criteria_id := l_crossdock_criteria_id;
949 l_to_rsv_rec.demand_ship_date := l_demand_expected_time;
950 l_to_rsv_rec.supply_receipt_date := l_supply_expected_time;
951
952 IF (l_debug = 1) THEN
953 print_debug(p_log_prefix || 'Call the update_reservation API to crossdock the RSV record');
954 END IF;
955 INV_RESERVATION_PVT.update_reservation
956 (p_api_version_number => 1.0,
957 p_init_msg_lst => fnd_api.g_false,
958 x_return_status => x_return_status,
959 x_msg_count => x_msg_count,
960 x_msg_data => x_msg_data,
961 p_original_rsv_rec => l_original_rsv_rec,
962 p_to_rsv_rec => l_to_rsv_rec,
963 p_original_serial_number => l_original_serial_number,
964 p_to_serial_number => l_to_serial_number,
965 p_validation_flag => fnd_api.g_true,
966 p_check_availability => fnd_api.g_false);
967
968 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
969 IF (l_debug = 1) THEN
970 print_debug(p_log_prefix || 'Error returned from update_reservation API: '
971 || x_return_status);
972 END IF;
973 -- Raise an exception. The caller will do the rollback, cleanups,
974 -- and decide where to goto next.
975 x_error_code := 'DB';
976 RAISE FND_API.G_EXC_ERROR;
977 END IF;
978 IF (l_debug = 1) THEN
979 print_debug(p_log_prefix || 'Successfully updated and crossdocked the RSV record');
980 END IF;
981 END IF;
982
983 -- Set the reservation qty to 0 indicating the reservation was fully consumed
984 l_rsv_qty := 0;
985 l_rsv_qty2 := 0;
986 l_progress := '40';
987 END IF; -- End crossdocking RSV record: Matches 'IF (l_rsv_txn_qty > l_atd_qty) THEN'
988
989 EXCEPTION
990 WHEN OTHERS THEN
991 x_return_status := fnd_api.g_ret_sts_error;
992 fnd_msg_pub.count_and_get(p_count => x_msg_count,
993 p_data => x_msg_data);
994 IF (l_debug = 1) THEN
995 print_debug(p_log_prefix || 'Exiting Crossdock_RSV - Execution error: ' ||
996 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
997 END IF;
998
999 END Crossdock_RSV;
1000 -- {{ }}
1001 -- {{******************** End Crossdock_RSV ********************}}
1002 -- {{ }}
1003
1004
1005 -- This is a private procedure used to crossdock/split a MOL record during pegging.
1006 -- A common procedure is created since this exact piece of code is called in two places
1007 -- for satisfying existing reservations and newly created crossdock reservations.
1008 -- {{ }}
1009 -- {{******************** Procedure Crossdock_MOL ********************}}
1010 PROCEDURE Crossdock_MOL
1011 (p_log_prefix IN VARCHAR2,
1012 p_crossdock_type IN NUMBER,
1013 l_debug IN OUT NOCOPY NUMBER,
1014 l_inventory_item_id IN OUT NOCOPY NUMBER,
1015 l_mol_qty IN OUT NOCOPY NUMBER,
1016 l_mol_qty2 IN OUT NOCOPY NUMBER,
1017 l_atd_qty IN OUT NOCOPY NUMBER,
1018 l_atd_mol_qty2 IN OUT NOCOPY NUMBER,
1019 l_supply_uom_code IN OUT NOCOPY VARCHAR2,
1020 l_mol_uom_code2 IN OUT NOCOPY VARCHAR2,
1021 l_conversion_rate IN OUT NOCOPY NUMBER,
1022 l_conversion_precision IN NUMBER,
1023 l_mol_prim_qty IN OUT NOCOPY NUMBER,
1024 l_atd_prim_qty IN OUT NOCOPY NUMBER,
1025 l_split_wdd_id IN OUT NOCOPY NUMBER,
1026 l_mol_header_id IN OUT NOCOPY NUMBER,
1027 l_mol_line_id IN OUT NOCOPY NUMBER,
1028 l_supply_atr_qty IN OUT NOCOPY NUMBER,
1029 l_demand_type_id IN OUT NOCOPY NUMBER,
1030 l_wip_entity_id IN OUT NOCOPY NUMBER,
1031 l_operation_seq_num IN OUT NOCOPY NUMBER,
1032 l_repetitive_schedule_id IN OUT NOCOPY NUMBER,
1033 l_wip_supply_type IN OUT NOCOPY NUMBER,
1034 l_xdocked_wdd_index IN OUT NOCOPY NUMBER,
1035 l_detail_info_tab IN OUT NOCOPY WSH_INTERFACE_EXT_GRP.Delivery_Details_Attr_Tbl_Type,
1036 l_wdd_index IN OUT NOCOPY NUMBER,
1037 l_split_wdd_index IN OUT NOCOPY NUMBER,
1038 p_wsh_release_table IN OUT NOCOPY WSH_PR_CRITERIA.relRecTabTyp,
1039 l_supply_type_id IN OUT NOCOPY NUMBER,
1040 x_return_status IN OUT NOCOPY VARCHAR2,
1041 x_msg_count IN OUT NOCOPY NUMBER,
1042 x_msg_data IN OUT NOCOPY VARCHAR2,
1043 x_error_code OUT NOCOPY VARCHAR2,
1044 l_criterion_type IN NUMBER DEFAULT NULL)
1045 IS
1046 l_progress VARCHAR2(10);
1047 l_backorder_detail_id NUMBER;
1048 l_crossdock_type NUMBER;
1049 l_split_mol_line_id NUMBER;
1050
1051 BEGIN
1052 -- Set the value 'mtrl.backorder_delivery_detail_id' should be updated to
1053 -- based on OE or WIP demand.
1054 -- {{
1055 -- Test crossdocking a MOL to a demand of type WIP and OE for
1056 -- opportunistic crossdocking. }}
1057 IF (l_demand_type_id = 5) THEN
1058 -- WIP backordered component demand
1059 l_backorder_detail_id := l_wip_entity_id;
1060 l_crossdock_type := 2;
1061 ELSE
1062 -- OE demand
1063 l_backorder_detail_id := l_split_wdd_id;
1064 l_crossdock_type := 1;
1065 END IF;
1066
1067 -- Check if we need to split the MOL record or not based on the ATD qty
1068 IF (l_mol_qty > l_atd_qty) THEN
1069 IF (l_debug = 1) THEN
1070 print_debug(p_log_prefix || 'MOL qty > ATD qty, so need to split the MOL record');
1071 END IF;
1072 -- Split the MOL record.
1073 -- {{
1074 -- Test for splitting a MOL record for an existing reservation using
1075 -- In Receiving as the supply line source. }}
1076
1077 -- Convert l_atd_qty to the secondary UOM on the MOL line if a value exists
1078 IF (l_mol_uom_code2 IS NOT NULL) THEN
1079 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
1080 l_supply_uom_code, l_mol_uom_code2);
1081 IF (l_conversion_rate < 0) THEN
1082 IF (l_debug = 1) THEN
1083 print_debug(p_log_prefix || 'Error while obtaining UOM2 conversion rate for MOL');
1084 END IF;
1085 -- Raise an exception. The caller will do the rollback, cleanups,
1086 -- and decide where to goto next.
1087 x_error_code := 'UOM';
1088 RAISE FND_API.G_EXC_ERROR;
1089 END IF;
1090 -- Round the converted quantity to the standard precision
1091 l_atd_mol_qty2 := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
1092 ELSE
1093 -- Secondary RSV UOM code is NULL
1094 l_atd_mol_qty2 := NULL;
1095 END IF; -- End retrieving conversion rate
1096 IF (l_debug = 1) THEN
1097 print_debug(p_log_prefix || 'ATD qty in secondary MOL UOM: => ' || l_atd_mol_qty2 || ' ' ||
1098 l_mol_uom_code2);
1099 END IF;
1100 l_progress := '10';
1101
1102 -- Insert the new split MOL record which will be crossdocked with the
1103 -- the available to detail quantity.
1104 -- Note I would use a MERGE statement to do the INSERT and UPDATE in one SQL
1105 -- call. However, this has a limitation where the INSERT clause does not work
1106 -- with a subquery which is how we are inserting the split MOL record.
1107 -- The alternative is to store each of the columns in a variable but that
1108 -- is not ideal.
1109 BEGIN
1110 INSERT INTO mtl_txn_request_lines
1111 (LINE_ID
1112 ,HEADER_ID
1113 ,LINE_NUMBER
1114 ,ORGANIZATION_ID
1115 ,INVENTORY_ITEM_ID
1116 ,REVISION
1117 ,FROM_SUBINVENTORY_CODE
1118 ,FROM_LOCATOR_ID
1119 ,TO_SUBINVENTORY_CODE
1120 ,TO_LOCATOR_ID
1121 ,TO_ACCOUNT_ID
1122 ,LOT_NUMBER
1123 ,SERIAL_NUMBER_START
1124 ,SERIAL_NUMBER_END
1125 ,UOM_CODE
1126 ,QUANTITY
1127 ,QUANTITY_DELIVERED
1128 ,QUANTITY_DETAILED
1129 ,DATE_REQUIRED
1130 ,REASON_ID
1131 ,REFERENCE
1132 ,REFERENCE_TYPE_CODE
1133 ,REFERENCE_ID
1134 ,PROJECT_ID
1135 ,TASK_ID
1136 ,TRANSACTION_HEADER_ID
1137 ,LINE_STATUS
1138 ,STATUS_DATE
1139 ,LAST_UPDATED_BY
1140 ,LAST_UPDATE_LOGIN
1141 ,LAST_UPDATE_DATE
1142 ,CREATED_BY
1143 ,CREATION_DATE
1144 ,REQUEST_ID
1145 ,PROGRAM_APPLICATION_ID
1146 ,PROGRAM_ID
1147 ,PROGRAM_UPDATE_DATE
1148 ,ATTRIBUTE1
1149 ,ATTRIBUTE2
1150 ,ATTRIBUTE3
1151 ,ATTRIBUTE4
1152 ,ATTRIBUTE5
1153 ,ATTRIBUTE6
1154 ,ATTRIBUTE7
1155 ,ATTRIBUTE8
1156 ,ATTRIBUTE9
1157 ,ATTRIBUTE10
1158 ,ATTRIBUTE11
1159 ,ATTRIBUTE12
1160 ,ATTRIBUTE13
1161 ,ATTRIBUTE14
1162 ,ATTRIBUTE15
1163 ,ATTRIBUTE_CATEGORY
1164 ,TXN_SOURCE_ID
1165 ,TXN_SOURCE_LINE_ID
1166 ,TXN_SOURCE_LINE_DETAIL_ID
1167 ,TRANSACTION_TYPE_ID
1168 ,TRANSACTION_SOURCE_TYPE_ID
1169 ,PRIMARY_QUANTITY
1170 ,TO_ORGANIZATION_ID
1171 ,PUT_AWAY_STRATEGY_ID
1172 ,PICK_STRATEGY_ID
1173 ,SHIP_TO_LOCATION_ID
1174 ,UNIT_NUMBER
1175 ,REFERENCE_DETAIL_ID
1176 ,ASSIGNMENT_ID
1177 ,FROM_COST_GROUP_ID
1178 ,TO_COST_GROUP_ID
1179 ,LPN_ID
1180 ,TO_LPN_ID
1181 ,PICK_SLIP_NUMBER
1182 ,PICK_SLIP_DATE
1183 ,INSPECTION_STATUS
1184 ,PICK_METHODOLOGY_ID
1185 ,CONTAINER_ITEM_ID
1186 ,CARTON_GROUPING_ID
1187 ,BACKORDER_DELIVERY_DETAIL_ID
1188 ,WMS_PROCESS_FLAG
1189 ,SHIP_SET_ID
1190 ,SHIP_MODEL_ID
1191 ,MODEL_QUANTITY
1192 ,FROM_SUBINVENTORY_ID
1193 ,TO_SUBINVENTORY_ID
1194 ,CROSSDOCK_TYPE
1195 ,REQUIRED_QUANTITY
1196 ,GRADE_CODE
1197 ,SECONDARY_QUANTITY
1198 ,SECONDARY_QUANTITY_DELIVERED
1199 ,SECONDARY_QUANTITY_DETAILED
1200 ,SECONDARY_REQUIRED_QUANTITY
1201 ,SECONDARY_UOM_CODE
1202 ,WIP_ENTITY_ID
1203 ,REPETITIVE_SCHEDULE_ID
1204 ,OPERATION_SEQ_NUM
1205 ,WIP_SUPPLY_TYPE
1206 )
1207 (SELECT
1208 mtl_txn_request_lines_s.NEXTVAL -- LINE_ID
1209 ,HEADER_ID
1210 ,mtrl_max.line_num --LINE_NUMBER
1211 ,ORGANIZATION_ID
1212 ,INVENTORY_ITEM_ID
1213 ,REVISION
1214 ,FROM_SUBINVENTORY_CODE
1215 ,FROM_LOCATOR_ID
1216 ,TO_SUBINVENTORY_CODE
1217 ,TO_LOCATOR_ID
1218 ,TO_ACCOUNT_ID
1219 ,LOT_NUMBER
1220 ,SERIAL_NUMBER_START
1221 ,SERIAL_NUMBER_END
1222 ,UOM_CODE
1223 ,l_atd_qty --QUANTITY
1224 ,QUANTITY_DELIVERED
1225 ,QUANTITY_DETAILED
1226 ,DATE_REQUIRED
1227 ,REASON_ID
1228 ,REFERENCE
1229 ,REFERENCE_TYPE_CODE
1230 ,REFERENCE_ID
1231 ,PROJECT_ID
1232 ,TASK_ID
1233 ,TRANSACTION_HEADER_ID
1234 ,LINE_STATUS
1235 ,STATUS_DATE
1236 ,LAST_UPDATED_BY
1237 ,LAST_UPDATE_LOGIN
1238 ,SYSDATE --LAST_UPDATE_DATE
1239 ,CREATED_BY
1240 ,SYSDATE --CREATION_DATE
1241 ,REQUEST_ID
1242 ,PROGRAM_APPLICATION_ID
1243 ,PROGRAM_ID
1244 ,PROGRAM_UPDATE_DATE
1245 ,ATTRIBUTE1
1246 ,ATTRIBUTE2
1247 ,ATTRIBUTE3
1248 ,ATTRIBUTE4
1249 ,ATTRIBUTE5
1250 ,ATTRIBUTE6
1251 ,ATTRIBUTE7
1252 ,ATTRIBUTE8
1253 ,ATTRIBUTE9
1254 ,ATTRIBUTE10
1255 ,ATTRIBUTE11
1256 ,ATTRIBUTE12
1257 ,ATTRIBUTE13
1258 ,ATTRIBUTE14
1259 ,ATTRIBUTE15
1260 ,ATTRIBUTE_CATEGORY
1261 ,TXN_SOURCE_ID
1262 ,TXN_SOURCE_LINE_ID
1263 ,TXN_SOURCE_LINE_DETAIL_ID
1264 ,TRANSACTION_TYPE_ID
1265 ,TRANSACTION_SOURCE_TYPE_ID
1266 ,l_atd_prim_qty --PRIMARY_QUANTITY
1267 ,TO_ORGANIZATION_ID
1268 ,PUT_AWAY_STRATEGY_ID
1269 ,PICK_STRATEGY_ID
1270 ,SHIP_TO_LOCATION_ID
1271 ,UNIT_NUMBER
1272 -- Change made for Inbound. For Opportunistic cases inbound
1273 -- can call crossdock API for a particular MOL. Then they need
1274 -- to know the MOLs that have been split and created for this
1275 -- line so that they can requery them somehow for creating suggestions.
1276 ,Decode(l_criterion_type,g_crt_type_opp,l_mol_line_id,reference_detail_id)
1277 ,ASSIGNMENT_ID
1278 ,FROM_COST_GROUP_ID
1279 ,TO_COST_GROUP_ID
1280 ,LPN_ID
1281 ,TO_LPN_ID
1282 ,PICK_SLIP_NUMBER
1283 ,PICK_SLIP_DATE
1284 ,INSPECTION_STATUS
1285 ,PICK_METHODOLOGY_ID
1286 ,CONTAINER_ITEM_ID
1287 ,CARTON_GROUPING_ID
1288 ,l_backorder_detail_id --BACKORDER_DELIVERY_DETAIL_ID
1289 ,WMS_PROCESS_FLAG
1290 ,SHIP_SET_ID
1291 ,SHIP_MODEL_ID
1292 ,MODEL_QUANTITY
1293 ,FROM_SUBINVENTORY_ID
1294 ,TO_SUBINVENTORY_ID
1295 ,l_crossdock_type --CROSSDOCK_TYPE
1296 ,REQUIRED_QUANTITY
1297 ,GRADE_CODE
1298 ,l_atd_mol_qty2 --SECONDARY_QUANTITY
1299 ,SECONDARY_QUANTITY_DELIVERED
1300 ,SECONDARY_QUANTITY_DETAILED
1301 ,SECONDARY_REQUIRED_QUANTITY
1302 ,SECONDARY_UOM_CODE
1303 ,l_wip_entity_id --WIP_ENTITY_ID
1304 ,l_repetitive_schedule_id --REPETITIVE_SCHEDULE_ID
1305 ,l_operation_seq_num --OPERATION_SEQ_NUM
1306 ,l_wip_supply_type --WIP_SUPPLY_TYPE
1307 FROM mtl_txn_request_lines mtrl, (SELECT MAX(line_number) + 1 AS line_num
1308 FROM mtl_txn_request_lines
1309 WHERE header_id = l_mol_header_id) mtrl_max
1310 WHERE mtrl.line_id = l_mol_line_id);
1311 EXCEPTION
1312 WHEN OTHERS THEN
1313 IF (l_debug = 1) THEN
1314 print_debug(p_log_prefix || 'Error inserting split MOL record');
1315 END IF;
1316 -- Raise an exception. The caller will do the rollback, cleanups,
1317 -- and decide where to goto next.
1318 x_error_code := 'DB';
1319 RAISE FND_API.G_EXC_ERROR;
1320 END; -- End inserting split MOL record into MTL_TXN_REQUEST_LINES
1321
1322 -- Retrieve the split MOL line ID we have just inserted above.
1323 -- We cannot use the RETURNING clause since a sub-query was used for the insert.
1324 -- As of 10g, this is not a supported feature.
1325 BEGIN
1326 SELECT line_id
1327 INTO l_split_mol_line_id
1328 FROM mtl_txn_request_lines
1329 WHERE header_id = l_mol_header_id
1330 AND ROWNUM = 1
1331 ORDER BY line_number DESC;
1332 EXCEPTION
1333 WHEN OTHERS THEN
1334 IF (l_debug = 1) THEN
1335 print_debug(p_log_prefix || 'Error retrieving the split MOL line ID');
1336 END IF;
1337 -- Raise an exception. The caller will do the rollback, cleanups,
1338 -- and decide where to goto next.
1339 x_error_code := 'DB';
1340 RAISE FND_API.G_EXC_ERROR;
1341 END;
1342 IF (l_debug = 1) THEN
1343 print_debug(p_log_prefix || 'Successfully inserted/split the MOL record: ' ||
1344 l_split_mol_line_id);
1345 END IF;
1346
1347 -- Update the quantity on the original MOL record.
1348 BEGIN
1349 UPDATE mtl_txn_request_lines SET
1350 quantity = l_mol_qty - l_atd_qty,
1351 primary_quantity = l_mol_prim_qty - l_atd_prim_qty,
1352 secondary_quantity = l_mol_qty2 - l_atd_mol_qty2
1353 WHERE line_id = l_mol_line_id;
1354 EXCEPTION
1355 WHEN OTHERS THEN
1356 IF (l_debug = 1) THEN
1357 print_debug(p_log_prefix || 'Error updating the original MOL record');
1358 END IF;
1359 -- Raise an exception. The caller will do the rollback, cleanups,
1360 -- and decide where to goto next.
1361 x_error_code := 'DB';
1362 RAISE FND_API.G_EXC_ERROR;
1363 END;
1364
1365 -- Update the MOL qty values to indicate how much quantity from the original MOL
1366 -- is still available for crossdocking.
1367 l_mol_qty := l_mol_qty - l_atd_qty;
1368 l_mol_prim_qty := l_mol_prim_qty - l_atd_prim_qty;
1369 l_mol_qty2 := l_mol_qty2 - l_atd_mol_qty2;
1370 -- Do the following logic only for Opportunistic Crossdocking.
1371 -- This is needed so we can tell if the MOL supply line has been fully
1372 -- crossdocked yet.
1373 IF (p_crossdock_type = G_CRT_TYPE_OPP) THEN
1374 l_supply_atr_qty := l_supply_atr_qty - l_atd_qty;
1375 END IF;
1376
1377 IF (l_debug = 1) THEN
1378 print_debug(p_log_prefix || 'Successfully updated and crossdocked the MOL record');
1379 END IF;
1380 l_progress := '20';
1381 ELSE
1382 IF (l_debug = 1) THEN
1383 print_debug(p_log_prefix || 'MOL qty = ATD qty, so no need to split the MOL record');
1384 END IF;
1385 -- l_mol_qty = l_atd_qty so just crossdock the MOL record.
1386 -- Update the backorder_delivery_detail_id column and set the crossdock_type
1387 -- to 1 for crossdocking to Sales or Internal Order.
1388 -- {{
1389 -- Test for MOL qty = available to detail qty. MOL record should be
1390 -- crossdocked properly. }}11
1391 BEGIN
1392 UPDATE mtl_txn_request_lines SET
1393 backorder_delivery_detail_id = l_backorder_detail_id,
1394 crossdock_type = l_crossdock_type,
1395 wip_entity_id = l_wip_entity_id,
1396 repetitive_schedule_id = l_repetitive_schedule_id,
1397 operation_seq_num = l_operation_seq_num,
1398 wip_supply_type = l_wip_supply_type
1399 WHERE line_id = l_mol_line_id;
1400 EXCEPTION
1401 WHEN OTHERS THEN
1402 IF (l_debug = 1) THEN
1403 print_debug(p_log_prefix || 'Error updating the MOL record');
1404 END IF;
1405 -- Raise an exception. The caller will do the rollback, cleanups,
1406 -- and decide where to goto next.
1407 x_error_code := 'DB';
1408 RAISE FND_API.G_EXC_ERROR;
1409 END;
1410
1411 -- Update the MOL qty field to indicate how much quantity from the original MOL
1412 -- is still available for crossdocking.
1413 l_mol_qty := 0;
1414 l_mol_prim_qty := 0;
1415 l_mol_qty2 := 0;
1416 -- Do the following logic only for Opportunistic Crossdocking.
1417 -- This is needed so we can tell if the MOL supply line has been fully
1418 -- crossdocked yet.
1419 IF (p_crossdock_type = G_CRT_TYPE_OPP) THEN
1420 l_supply_atr_qty := 0;
1421 END IF;
1422
1423 IF (l_debug = 1) THEN
1424 print_debug(p_log_prefix || 'Successfully updated and crossdocked the MOL record');
1425 END IF;
1426 l_progress := '30';
1427 END IF; -- End crossdocking MOL record: Matches 'IF (l_mol_qty > l_atd_qty) THEN'
1428
1429 -- If the MOL used to crossdock was split, then it is the split MOL that should be
1430 -- tied to the WDD lines. We need to make sure crossdocked WDD lines are updated
1431 -- properly. Additionally, for Planned Crossdocking, the records in p_wsh_release_table
1432 -- also need to reflect the correct MOL pegged to the WDD. This needs to be done only
1433 -- for OE demand. For WIP backordered component demand, nothing needs to be done since
1434 -- the WIP job is not tied to the move order line (currently).
1435 -- For Opportunistic Crossdocking with WIP as the supply being crossdocked to a WDD demand,
1436 -- we do not need to update the move_order_line_id column. This is to mimic 11.5.10
1437 -- and prior behavior.
1438 IF (l_split_mol_line_id IS NOT NULL AND l_demand_type_id <> 5 AND l_supply_type_id <> 5) THEN
1439 -- Update the crossdocked WDD to point to the split MOL
1440 l_detail_info_tab(l_xdocked_wdd_index).move_order_line_id := l_split_mol_line_id;
1441
1442 -- Update the WDD record in the release table for Planned Crossdocking
1443 IF (p_crossdock_type = G_CRT_TYPE_PLAN) THEN
1444 IF (l_split_wdd_index IS NOT NULL) THEN
1445 -- WDD record was also split so update the appropriate crossdocked WDD
1446 p_wsh_release_table(l_split_wdd_index).move_order_line_id := l_split_mol_line_id;
1447 ELSE
1448 -- WDD record was not split so update the current WDD
1449 p_wsh_release_table(l_wdd_index).move_order_line_id := l_split_mol_line_id;
1450 END IF;
1451 END IF;
1452 IF (l_debug = 1) THEN
1453 print_debug(p_log_prefix || 'Successfully updated the WDD records with the split MOL line');
1454 END IF;
1455 l_progress := '40';
1456 END IF; -- End of logic to update WDD records with split MOL line
1457
1458 EXCEPTION
1459 WHEN OTHERS THEN
1460 x_return_status := fnd_api.g_ret_sts_error;
1461 fnd_msg_pub.count_and_get(p_count => x_msg_count,
1462 p_data => x_msg_data);
1463 IF (l_debug = 1) THEN
1464 print_debug(p_log_prefix || 'Exiting Crossdock_MOL - Execution error: ' ||
1465 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
1466 END IF;
1467
1468 END Crossdock_MOL;
1469 -- {{ }}
1470 -- {{******************** End Crossdock_MOL ********************}}
1471 -- {{ }}
1472
1473
1474 -- This is a private procedure used to create a crossdock reservation during pegging.
1475 -- This will be used for both Planned and Opportunistic crossdocking.
1476 -- {{ }}
1477 -- {{******************** Procedure Create_RSV ********************}}
1478 PROCEDURE Create_RSV
1479 (p_log_prefix IN VARCHAR2,
1480 p_crossdock_type IN NUMBER,
1481 l_debug IN OUT NOCOPY NUMBER,
1482 l_organization_id IN OUT NOCOPY NUMBER,
1483 l_inventory_item_id IN OUT NOCOPY NUMBER,
1484 l_demand_type_id IN OUT NOCOPY NUMBER,
1485 l_demand_so_header_id IN OUT NOCOPY NUMBER,
1486 l_demand_line_id IN OUT NOCOPY NUMBER,
1487 l_split_wdd_id IN OUT NOCOPY NUMBER,
1488 l_primary_uom_code IN OUT NOCOPY VARCHAR2,
1489 l_demand_uom_code2 IN OUT NOCOPY VARCHAR2,
1490 l_supply_uom_code IN OUT NOCOPY VARCHAR2,
1491 l_atd_qty IN OUT NOCOPY NUMBER,
1492 l_atd_prim_qty IN OUT NOCOPY NUMBER,
1493 l_atd_wdd_qty2 IN OUT NOCOPY NUMBER,
1494 l_supply_type_id IN OUT NOCOPY NUMBER,
1495 l_supply_header_id IN OUT NOCOPY NUMBER,
1496 l_supply_line_id IN OUT NOCOPY NUMBER,
1497 l_supply_line_detail_id IN OUT NOCOPY NUMBER,
1498 l_crossdock_criteria_id IN OUT NOCOPY NUMBER,
1499 l_supply_expected_time IN OUT NOCOPY DATE,
1500 l_demand_expected_time IN OUT NOCOPY DATE,
1501 l_demand_project_id IN OUT NOCOPY NUMBER,
1502 l_demand_task_id IN OUT NOCOPY NUMBER,
1503 l_original_rsv_rec IN OUT NOCOPY inv_reservation_global.mtl_reservation_rec_type,
1504 l_original_serial_number IN OUT NOCOPY inv_reservation_global.serial_number_tbl_type,
1505 l_to_serial_number IN OUT NOCOPY inv_reservation_global.serial_number_tbl_type,
1506 l_quantity_reserved IN OUT NOCOPY NUMBER,
1507 l_quantity_reserved2 IN OUT NOCOPY NUMBER,
1508 l_rsv_id IN OUT NOCOPY NUMBER,
1509 x_return_status IN OUT NOCOPY VARCHAR2,
1510 x_msg_count IN OUT NOCOPY NUMBER,
1511 x_msg_data IN OUT NOCOPY VARCHAR2)
1512 IS
1513 l_progress VARCHAR2(10);
1514
1515 BEGIN
1516 -- {{
1517 -- Test that a valid crossdocked reservation is created. The quantities should
1518 -- match the relevant WDD and MOL records. }}
1519 --
1520 -- Set the values for the reservation record to be created
1521 IF (l_debug = 1) THEN
1522 print_debug(p_log_prefix || 'Requirement Date: ' || l_demand_expected_time);
1523 END IF;
1524 l_original_rsv_rec.reservation_id := NULL;
1525 l_original_rsv_rec.requirement_date := l_demand_expected_time;
1526 l_original_rsv_rec.organization_id := l_organization_id;
1527 l_original_rsv_rec.inventory_item_id := l_inventory_item_id;
1528 l_original_rsv_rec.demand_source_name := NULL;
1529 l_original_rsv_rec.demand_source_type_id := l_demand_type_id;
1530 l_original_rsv_rec.demand_source_header_id := l_demand_so_header_id;
1531 l_original_rsv_rec.demand_source_line_id := l_demand_line_id;
1532 l_original_rsv_rec.orig_demand_source_type_id := l_demand_type_id;
1533 l_original_rsv_rec.orig_demand_source_header_id := l_demand_so_header_id;
1534 l_original_rsv_rec.orig_demand_source_line_id := l_demand_line_id;
1535 -- For WIP as supply reservations, just create a regular non-crossdocked reservation.
1536 -- Do not stamp the WDD ID for the demand line detail.
1537 IF (l_supply_type_id = 5) THEN
1538 l_original_rsv_rec.demand_source_line_detail := NULL;
1539 l_original_rsv_rec.orig_demand_source_line_detail := NULL;
1540 ELSE
1541 l_original_rsv_rec.demand_source_line_detail := l_split_wdd_id;
1542 l_original_rsv_rec.orig_demand_source_line_detail := l_split_wdd_id;
1543 END IF;
1544 l_original_rsv_rec.demand_source_delivery := NULL;
1545 l_original_rsv_rec.primary_uom_code := l_primary_uom_code;
1546 l_original_rsv_rec.primary_uom_id := NULL;
1547 l_original_rsv_rec.secondary_uom_code := l_demand_uom_code2;
1548 l_original_rsv_rec.secondary_uom_id := NULL;
1549 l_original_rsv_rec.reservation_uom_code := l_supply_uom_code;
1550 l_original_rsv_rec.reservation_uom_id := NULL;
1551 l_original_rsv_rec.reservation_quantity := l_atd_qty;
1552 l_original_rsv_rec.primary_reservation_quantity := l_atd_prim_qty;
1553 l_original_rsv_rec.secondary_reservation_quantity := l_atd_wdd_qty2;
1554 l_original_rsv_rec.detailed_quantity := NULL;
1555 l_original_rsv_rec.secondary_detailed_quantity := NULL;
1556 l_original_rsv_rec.autodetail_group_id := NULL;
1557 l_original_rsv_rec.external_source_code := 'XDOCK';
1558 l_original_rsv_rec.external_source_line_id := NULL;
1559 l_original_rsv_rec.supply_source_type_id := l_supply_type_id;
1560 l_original_rsv_rec.orig_supply_source_type_id := l_supply_type_id;
1561 l_original_rsv_rec.supply_source_name := NULL;
1562 -- Since reservations with supply type of Receiving are not at the
1563 -- MO header and line level, these fields should be NULL.
1564 IF (l_supply_type_id = 27) THEN
1565 l_original_rsv_rec.supply_source_header_id := NULL;
1566 l_original_rsv_rec.supply_source_line_id := NULL;
1567 l_original_rsv_rec.supply_source_line_detail := NULL;
1568 l_original_rsv_rec.orig_supply_source_header_id := NULL;
1569 l_original_rsv_rec.orig_supply_source_line_id := NULL;
1570 l_original_rsv_rec.orig_supply_source_line_detail := NULL;
1571 ELSIF (l_supply_type_id = 7) THEN
1572 -- Reservations with supply type of Internal Req should have a NULL
1573 -- value for the supply source line detail. Right now this field could
1574 -- potentially store the shipment line ID for an Internal Req that has quantity
1575 -- shipped. Reservations currently are not created at this level of detail.
1576 l_original_rsv_rec.supply_source_header_id := l_supply_header_id;
1577 l_original_rsv_rec.supply_source_line_id := l_supply_line_id;
1578 l_original_rsv_rec.supply_source_line_detail := NULL;
1579 l_original_rsv_rec.orig_supply_source_header_id := l_supply_header_id;
1580 l_original_rsv_rec.orig_supply_source_line_id := l_supply_line_id;
1581 l_original_rsv_rec.orig_supply_source_line_detail := NULL;
1582 ELSIF (l_supply_type_id = 5) THEN
1583 -- Reservations with supply type of WIP should just have the WIP entity ID
1584 -- stored as the supply source header ID. The other WIP fields such as
1585 -- operation seq num and repetitive schedule ID are not currently stored
1586 -- on the reservation.
1587 l_original_rsv_rec.supply_source_header_id := l_supply_header_id;
1588 l_original_rsv_rec.supply_source_line_id := NULL;
1589 l_original_rsv_rec.supply_source_line_detail := NULL;
1590 l_original_rsv_rec.orig_supply_source_header_id := l_supply_header_id;
1591 l_original_rsv_rec.orig_supply_source_line_id := NULL;
1592 l_original_rsv_rec.orig_supply_source_line_detail := NULL;
1593 ELSE
1594 l_original_rsv_rec.supply_source_header_id := l_supply_header_id;
1595 l_original_rsv_rec.supply_source_line_id := l_supply_line_id;
1596 l_original_rsv_rec.supply_source_line_detail := l_supply_line_detail_id;
1597 l_original_rsv_rec.orig_supply_source_header_id := l_supply_header_id;
1598 l_original_rsv_rec.orig_supply_source_line_id := l_supply_line_id;
1599 l_original_rsv_rec.orig_supply_source_line_detail := l_supply_line_detail_id;
1600 END IF;
1601 l_original_rsv_rec.revision := NULL;
1602 l_original_rsv_rec.subinventory_code := NULL;
1603 l_original_rsv_rec.subinventory_id := NULL;
1604 l_original_rsv_rec.locator_id := NULL;
1605 l_original_rsv_rec.lot_number := NULL;
1606 l_original_rsv_rec.lot_number_id := NULL;
1607 l_original_rsv_rec.pick_slip_number := NULL;
1608 l_original_rsv_rec.lpn_id := NULL;
1609 l_original_rsv_rec.attribute_category := NULL;
1610 l_original_rsv_rec.attribute1 := NULL;
1611 l_original_rsv_rec.attribute2 := NULL;
1612 l_original_rsv_rec.attribute3 := NULL;
1613 l_original_rsv_rec.attribute4 := NULL;
1614 l_original_rsv_rec.attribute5 := NULL;
1615 l_original_rsv_rec.attribute6 := NULL;
1616 l_original_rsv_rec.attribute7 := NULL;
1617 l_original_rsv_rec.attribute8 := NULL;
1618 l_original_rsv_rec.attribute9 := NULL;
1619 l_original_rsv_rec.attribute10 := NULL;
1620 l_original_rsv_rec.attribute11 := NULL;
1621 l_original_rsv_rec.attribute12 := NULL;
1622 l_original_rsv_rec.attribute13 := NULL;
1623 l_original_rsv_rec.attribute14 := NULL;
1624 l_original_rsv_rec.attribute15 := NULL;
1625 l_original_rsv_rec.ship_ready_flag := NULL;
1626 l_original_rsv_rec.staged_flag := NULL;
1627 -- For WIP as supply reservations, just create a regular non-crossdocked reservation.
1628 IF (l_supply_type_id = 5) THEN
1629 l_original_rsv_rec.crossdock_flag := NULL;
1630 l_original_rsv_rec.crossdock_criteria_id := NULL;
1631 ELSE
1632 l_original_rsv_rec.crossdock_flag := 'Y';
1633 l_original_rsv_rec.crossdock_criteria_id := l_crossdock_criteria_id;
1634 END IF;
1635 l_original_rsv_rec.serial_reservation_quantity := NULL;
1636 l_original_rsv_rec.supply_receipt_date := l_supply_expected_time;
1637 l_original_rsv_rec.demand_ship_date := l_demand_expected_time;
1638 l_original_rsv_rec.project_id := l_demand_project_id;
1639 l_original_rsv_rec.task_id := l_demand_task_id;
1640 l_original_rsv_rec.serial_number := NULL;
1641 l_progress := '10';
1642
1643 IF (l_debug = 1) THEN
1644 print_debug(p_log_prefix || 'Call the create_reservation API to create the crossdock peg');
1645 END IF;
1646 INV_RESERVATION_PVT.create_reservation
1647 (p_api_version_number => 1.0,
1648 p_init_msg_lst => fnd_api.g_false,
1649 x_return_status => x_return_status,
1650 x_msg_count => x_msg_count,
1651 x_msg_data => x_msg_data,
1652 p_rsv_rec => l_original_rsv_rec,
1653 p_serial_number => l_original_serial_number,
1654 x_serial_number => l_to_serial_number,
1655 p_partial_reservation_flag => fnd_api.g_false,
1656 p_force_reservation_flag => fnd_api.g_false,
1657 p_validation_flag => fnd_api.g_true,
1658 x_quantity_reserved => l_quantity_reserved,
1659 x_secondary_quantity_reserved => l_quantity_reserved2,
1660 x_reservation_id => l_rsv_id
1661 );
1662
1663 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
1664 IF (l_debug = 1) THEN
1665 print_debug(p_log_prefix || 'Error returned from create_reservation API: '
1666 || x_return_status);
1667 END IF;
1668 -- Raise an exception. The caller will do the rollback, cleanups,
1669 -- and decide where to goto next.
1670 RAISE FND_API.G_EXC_ERROR;
1671 END IF;
1672 l_progress := '20';
1673
1674 EXCEPTION
1675 WHEN OTHERS THEN
1676 x_return_status := fnd_api.g_ret_sts_error;
1677 fnd_msg_pub.count_and_get(p_count => x_msg_count,
1678 p_data => x_msg_data);
1679 IF (l_debug = 1) THEN
1680 print_debug(p_log_prefix || 'Exiting Create_RSV - Execution error: ' ||
1681 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
1682 END IF;
1683
1684 END Create_RSV;
1685 -- {{ }}
1686 -- {{******************** End Create_RSV ********************}}
1687 -- {{ }}
1688
1689
1690 -- {{ }}
1691 -- {{******************** Procedure Planned_Cross_Dock ********************}}
1692 PROCEDURE Planned_Cross_Dock
1693 (p_api_version IN NUMBER,
1694 p_init_msg_list IN VARCHAR2,
1695 p_commit IN VARCHAR2,
1696 x_return_status OUT NOCOPY VARCHAR2,
1697 x_msg_count OUT NOCOPY NUMBER,
1698 x_msg_data OUT NOCOPY VARCHAR2,
1699 p_batch_id IN NUMBER,
1700 p_wsh_release_table IN OUT NOCOPY WSH_PR_CRITERIA.relRecTabTyp,
1701 p_trolin_delivery_ids IN OUT NOCOPY WSH_UTIL_CORE.Id_Tab_Type,
1702 p_del_detail_id IN OUT NOCOPY WSH_PICK_LIST.DelDetTabTyp)
1703 IS
1704 l_api_name CONSTANT VARCHAR2(30) := 'Planned_Cross_Dock';
1705 l_api_version CONSTANT NUMBER := 1.0;
1706 l_progress VARCHAR2(10);
1707 l_debug NUMBER := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
1708
1709 -- This variable is used to indicate if the custom APIs were used.
1710 l_api_is_implemented BOOLEAN;
1711
1712 -- These variable will store the org, allocation method, crossdock criteria ID
1713 -- and the existing reservations only flag for the inputted picking batch.
1714 l_organization_id NUMBER;
1715 l_allocation_method VARCHAR2(1);
1716 l_wpb_xdock_criteria_id NUMBER;
1717 l_existing_rsvs_only VARCHAR2(1);
1718
1719 -- This variable stores the PJM org parameter to allow cross project allocation
1720 -- when matching supply to demand lines for crossdocking. Possible values are 'Y' or 'N'.
1721 l_allow_cross_proj_issues VARCHAR2(1);
1722
1723 -- This variable indicates if the org is PJM enabled or not. 1 = Yes, 2 = No
1724 l_project_ref_enabled NUMBER;
1725
1726 -- This boolean variable indicates if the org is a WMS org or not.
1727 l_wms_org_flag BOOLEAN;
1728
1729 -- This variable stores the current item being crossdocking from the release table
1730 l_inventory_item_id NUMBER;
1731 l_primary_uom_code VARCHAR2(3);
1732
1733 -- Cursor to retrieve valid approved PO supply lines
1734 CURSOR po_approved_lines IS
1735 SELECT
1736 poll.po_header_id AS header_id,
1737 poll.line_location_id AS line_id,
1738 NULL AS line_detail_id,
1739 NULL AS quantity,
1740 muom.uom_code AS uom_code,
1741 NULL AS primary_quantity,
1742 NULL AS secondary_quantity,
1743 NULL AS secondary_uom_code,
1744 MIN(pod.project_id) AS project_id,
1745 MIN(pod.task_id) AS task_id,
1746 NULL AS lpn_id
1747 FROM po_headers_all poh, po_lines_all pol, po_line_locations_all poll,
1748 po_distributions_all pod, po_line_types plt, mtl_units_of_measure muom
1749 WHERE poh.type_lookup_code IN ('STANDARD','PLANNED','BLANKET','CONTRACT')
1750 AND NVL(poh.cancel_flag, 'N') IN ('N', 'I')
1751 AND NVL(poh.closed_code, 'OPEN') NOT IN ('FINALLY CLOSED','CLOSED FOR RECEIVING','CLOSED')
1752 AND pol.po_header_id = poh.po_header_id
1753 AND poh.po_header_id = poll.po_header_id
1754 AND pol.po_line_id = poll.po_line_id
1755 AND pod.po_header_id = poh.po_header_id
1756 AND pod.po_line_id = pol.po_line_id
1757 AND pod.line_location_id = poll.line_location_id
1758 AND pol.item_id = l_inventory_item_id
1759 AND pol.line_type_id = plt.line_type_id
1760 AND NVL(plt.outside_operation_flag, 'N') = 'N'
1761 AND poll.unit_meas_lookup_code = muom.unit_of_measure
1762 AND NVL(poll.approved_flag, 'N') = 'Y'
1763 AND NVL(poll.cancel_flag, 'N') = 'N'
1764 AND NVL(poll.closed_code, 'OPEN') NOT IN ('FINALLY CLOSED','CLOSED FOR RECEIVING','CLOSED')
1765 AND poll.shipment_type IN ('STANDARD', 'BLANKET', 'SCHEDULED')
1766 AND poll.ship_to_organization_id = l_organization_id
1767 AND poll.quantity > NVL(poll.quantity_received, 0)
1768 AND NVL(poll.receiving_routing_id,
1769 WMS_Xdock_Pegging_Pub.get_default_routing_id(l_organization_id,
1770 l_inventory_item_id,
1771 poh.vendor_id)) <> 3
1772 AND NOT EXISTS (SELECT 'Invalid Destination'
1773 FROM po_distributions_all pod2
1774 WHERE pod2.po_header_id = poll.po_header_id
1775 AND pod2.po_line_id = poll.po_line_id
1776 AND pod2.line_location_id = poll.line_location_id
1777 AND NVL(pod2.destination_type_code, pod2.destination_context) IN
1778 ('EXPENSE','SHOP FLOOR'))
1779 AND NOT EXISTS (SELECT 'Drop Ship'
1780 FROM oe_drop_ship_sources odss
1781 WHERE odss.po_header_id = poll.po_header_id
1782 AND odss.po_line_id = poll.po_line_id
1783 AND odss.line_location_id = poll.line_location_id)
1784 GROUP BY poll.po_header_id, poll.po_line_id, poll.line_location_id, muom.uom_code
1785 HAVING COUNT(DISTINCT NVL(pod.project_id, -999)) = 1
1786 AND COUNT(DISTINCT NVL(pod.task_id, -999)) = 1;
1787
1788
1789 -- Cursor to retrieve valid ASN supply lines
1790 CURSOR po_asn_lines IS
1791 SELECT
1792 rsl.po_header_id AS header_id,
1793 rsl.po_line_location_id AS line_id,
1794 rsl.shipment_line_id AS line_detail_id,
1795 NULL AS quantity,
1796 muom.uom_code AS uom_code,
1797 NULL AS primary_quantity,
1798 NULL AS secondary_quantity,
1799 NULL AS secondary_uom_code,
1800 MIN(pod.project_id) AS project_id,
1801 MIN(pod.task_id) AS task_id,
1802 NULL AS lpn_id
1803 FROM rcv_shipment_headers rsh, rcv_shipment_lines rsl, po_lines_all pol, po_line_types plt,
1804 po_line_locations_all poll, po_distributions_all pod, mtl_units_of_measure muom
1805 WHERE rsh.shipment_num IS NOT NULL
1806 AND rsh.receipt_source_code = 'VENDOR'
1807 AND rsh.asn_type in ('ASN','ASBN')
1808 AND rsh.shipment_header_id = rsl.shipment_header_id
1809 AND rsl.to_organization_id = l_organization_id
1810 AND rsl.shipment_line_status_code in ('EXPECTED','PARTIALLY RECEIVED')
1811 AND rsl.item_id = l_inventory_item_id
1812 AND rsl.quantity_shipped > NVL(rsl.quantity_received, 0)
1813 AND rsl.po_line_id = pol.po_line_id
1814 AND pol.line_type_id = plt.line_type_id
1815 AND NVL(plt.outside_operation_flag, 'N') = 'N'
1816 AND pol.po_line_id = poll.po_line_id
1817 AND rsl.po_line_location_id = poll.line_location_id
1818 AND pod.po_line_id = pol.po_line_id
1819 AND pod.line_location_id = poll.line_location_id
1820 AND rsl.unit_of_measure = muom.unit_of_measure
1821 AND NVL(poll.receiving_routing_id,
1822 WMS_Xdock_Pegging_Pub.get_default_routing_id(l_organization_id,
1823 l_inventory_item_id,
1824 rsh.vendor_id)) <> 3
1825 AND NOT EXISTS (SELECT 'Invalid Destination'
1826 FROM po_distributions_all pod2
1827 WHERE pod2.po_header_id = poll.po_header_id
1828 AND pod2.po_line_id = poll.po_line_id
1829 AND pod2.line_location_id = poll.line_location_id
1830 AND NVL(pod2.destination_type_code, pod2.destination_context) IN
1831 ('EXPENSE','SHOP FLOOR'))
1832 AND NOT EXISTS (SELECT 'Drop Ship'
1833 FROM oe_drop_ship_sources odss
1834 WHERE odss.po_header_id = poll.po_header_id
1835 AND odss.po_line_id = poll.po_line_id
1836 AND odss.line_location_id = poll.line_location_id)
1837 GROUP BY rsl.po_header_id, rsl.po_line_location_id, rsl.shipment_line_id,
1838 muom.uom_code
1839 HAVING COUNT(DISTINCT NVL(pod.project_id, -999)) = 1
1840 AND COUNT(DISTINCT NVL(pod.task_id, -999)) = 1;
1841
1842
1843 -- Cursor to retrieve valid Internal Requisition supply lines
1844 CURSOR internal_req_lines IS
1845 -- Shipped In Transit Internal Reqs
1846 SELECT
1847 prl.requisition_header_id AS header_id,
1848 prl.requisition_line_id AS line_id,
1849 rsl.shipment_line_id AS line_detail_id,
1850 NULL AS quantity,
1851 muom.uom_code AS uom_code,
1852 NULL AS primary_quantity,
1853 NULL AS secondary_quantity,
1854 NULL AS secondary_uom_code,
1855 MIN(prd.project_id) AS project_id,
1856 MIN(prd.task_id) AS task_id,
1857 NULL AS lpn_id
1858 FROM po_requisition_headers_all prh, po_requisition_lines_all prl,
1859 rcv_shipment_lines rsl, rcv_shipment_headers rsh, po_req_distributions_all prd,
1860 mtl_units_of_measure muom
1861 WHERE prh.requisition_header_id = prl.requisition_header_id
1862 AND prd.requisition_line_id = prl.requisition_line_id
1863 AND prh.authorization_status = 'APPROVED'
1864 AND NVL(prl.cancel_flag,'N') = 'N'
1865 AND prl.source_type_code = 'INVENTORY'
1866 AND prl.destination_organization_id = l_organization_id
1867 AND prl.item_id = l_inventory_item_id
1868 AND rsl.requisition_line_id = prl.requisition_line_id
1869 AND rsl.routing_header_id > 0
1870 AND rsl.shipment_line_status_code IN ('EXPECTED','PARTIALLY RECEIVED')
1871 AND rsl.to_organization_id = l_organization_id
1872 AND rsl.item_id = l_inventory_item_id
1873 AND rsl.quantity_shipped > NVL(rsl.quantity_received, 0)
1874 AND rsh.shipment_header_id = rsl.shipment_header_id
1875 AND rsl.unit_of_measure = muom.unit_of_measure
1876 AND NVL(rsl.routing_header_id,
1877 WMS_Xdock_Pegging_Pub.get_default_routing_id(l_organization_id,
1878 l_inventory_item_id,
1879 rsh.vendor_id)) <> 3
1880 AND NVL(NVL(prl.destination_type_code, prl.destination_context), 'INVENTORY') NOT IN
1881 ('EXPENSE', 'SHOP FLOOR')
1882 GROUP BY prl.requisition_header_id, prl.requisition_line_id, rsl.shipment_line_id,
1883 muom.uom_code
1884 HAVING COUNT(DISTINCT NVL(prd.project_id, -999)) = 1
1885 AND COUNT(DISTINCT NVL(prd.task_id, -999)) = 1
1886
1887 UNION
1888 -- Approved but not shipped Internal Reqs
1889 SELECT
1890 prl.requisition_header_id AS header_id,
1891 prl.requisition_line_id AS line_id,
1892 NULL AS line_detail_id,
1893 NULL AS quantity,
1894 muom.uom_code AS uom_code,
1895 NULL AS primary_quantity,
1896 NULL AS secondary_quantity,
1897 NULL AS secondary_uom_code,
1898 MIN(prd.project_id) AS project_id,
1899 MIN(prd.task_id) AS task_id,
1900 NULL AS lpn_id
1901 FROM po_requisition_headers_all prh, po_requisition_lines_all prl,
1902 po_req_distributions_all prd, mtl_interorg_parameters mip, mtl_units_of_measure muom
1903 WHERE prh.requisition_header_id = prl.requisition_header_id
1904 AND prd.requisition_line_id = prl.requisition_line_id
1905 AND prh.authorization_status = 'APPROVED'
1906 AND NVL(prl.cancel_flag,'N') = 'N'
1907 AND prl.source_type_code = 'INVENTORY'
1908 AND prl.destination_organization_id = l_organization_id
1909 AND prl.item_id = l_inventory_item_id
1910 AND NOT EXISTS (SELECT 'Ship Confirmed'
1911 FROM rcv_shipment_lines rsl
1912 WHERE rsl.requisition_line_id = prl.requisition_line_id
1913 AND rsl.routing_header_id > 0
1914 AND rsl.shipment_line_status_code <> 'CANCELLED'
1915 AND rsl.to_organization_id = l_organization_id
1916 AND rsl.item_id = l_inventory_item_id)
1917 AND mip.from_organization_id = prl.source_organization_id
1918 AND mip.to_organization_id = prl.destination_organization_id
1919 AND prl.unit_meas_lookup_code = muom.unit_of_measure
1920 AND NVL(mip.routing_header_id,
1921 WMS_Xdock_Pegging_Pub.get_default_routing_id(l_organization_id,
1922 l_inventory_item_id,
1923 prl.vendor_id)) <> 3
1924 AND NVL(NVL(prl.destination_type_code, prl.destination_context), 'INVENTORY') NOT IN
1925 ('EXPENSE', 'SHOP FLOOR')
1926 GROUP BY prl.requisition_header_id, prl.requisition_line_id, muom.uom_code
1927 HAVING COUNT(DISTINCT NVL(prd.project_id, -999)) = 1
1928 AND COUNT(DISTINCT NVL(prd.task_id, -999)) = 1;
1929
1930
1931 -- Cursor to retrieve valid In Transit Shipment supply lines
1932 CURSOR intship_lines IS
1933 SELECT
1934 rsl.shipment_header_id AS header_id,
1935 rsl.shipment_line_id AS line_id,
1936 NULL AS line_detail_id,
1937 NULL AS quantity,
1938 muom.uom_code AS uom_code,
1939 NULL AS primary_quantity,
1940 NULL AS secondary_quantity,
1941 NULL AS secondary_uom_code,
1942 NULL AS project_id,
1943 NULL AS task_id,
1944 NULL AS lpn_id
1945 FROM rcv_shipment_headers rsh, rcv_shipment_lines rsl, mtl_units_of_measure muom
1946 WHERE rsh.shipment_num IS NOT NULL
1947 AND rsh.shipment_header_id = rsl.shipment_header_id
1948 AND rsh.receipt_source_code = 'INVENTORY'
1949 AND EXISTS (SELECT 'Available Supply'
1950 FROM mtl_supply ms
1951 WHERE ms.to_organization_id = l_organization_id
1952 AND ms.shipment_header_id = rsh.shipment_header_id)
1953 AND rsl.shipment_line_status_code IN ('EXPECTED','PARTIALLY RECEIVED')
1954 AND rsl.to_organization_id = l_organization_id
1955 AND rsl.item_id = l_inventory_item_id
1956 AND rsl.quantity_shipped > NVL(rsl.quantity_received, 0)
1957 AND rsl.unit_of_measure = muom.unit_of_measure
1958 AND NVL(rsl.routing_header_id,
1959 WMS_Xdock_Pegging_Pub.get_default_routing_id(l_organization_id,
1960 l_inventory_item_id,
1961 rsh.vendor_id)) <> 3
1962 AND NVL(NVL(rsl.destination_type_code, rsl.destination_context), 'INVENTORY') NOT IN
1963 ('EXPENSE','SHOP FLOOR');
1964 --AND (l_project_ref_enabled = 2 OR l_allow_cross_proj_issues = 'Y');
1965 -- In Transit Shipments going to a destination org that is PJM enabled will
1966 -- always have a NULL project/task, i.e. part of common stock. The assumption is
1967 -- that if such a supply exists, the user cannot receive it into a specific project/task.
1968
1969
1970 -- Cursor to retrieve valid In Receiving supply lines.
1971 CURSOR in_receiving_lines IS
1972 SELECT
1973 mtrl.header_id AS header_id,
1974 mtrl.line_id AS line_id,
1975 NULL AS line_detail_id,
1976 mtrl.quantity AS quantity,
1977 mtrl.uom_code AS uom_code,
1978 mtrl.primary_quantity AS primary_quantity,
1979 mtrl.secondary_quantity AS secondary_quantity,
1980 mtrl.secondary_uom_code AS secondary_uom_code,
1981 mtrl.project_id AS project_id,
1982 mtrl.task_id AS task_id,
1983 mtrl.lpn_id AS lpn_id
1984 FROM mtl_txn_request_lines mtrl, mtl_txn_request_headers mtrh,
1985 wms_license_plate_numbers wlpn
1986 WHERE mtrl.header_id = mtrh.header_id
1987 AND mtrh.move_order_type = inv_globals.g_move_order_put_away
1988 AND mtrl.organization_id = l_organization_id
1989 AND mtrl.inventory_item_id = l_inventory_item_id
1990 -- Modified the line below to use an IN instead of <> so the
1991 -- index MTL_TXN_REQUEST_LINES_N10 on MTRL is more likely to be used.
1992 -- AND mtrl.line_status <> inv_globals.g_to_status_closed
1993 AND mtrl.line_status IN (inv_globals.g_to_status_preapproved,
1994 inv_globals.g_to_status_approved)
1995 AND mtrl.backorder_delivery_detail_id IS NULL
1996 AND mtrl.lpn_id IS NOT NULL
1997 AND mtrl.quantity > 0
1998 AND NVL(mtrl.quantity_delivered, 0) = 0
1999 AND NVL(mtrl.quantity_detailed, 0) = 0
2000 AND NVL(mtrl.inspection_status, 2) = 2
2001 AND NVL(mtrl.wms_process_flag, 1) = 1
2002 AND NVL(mtrl.reference, 'non-RMA') <> 'ORDER_LINE_ID'
2003 AND mtrl.lpn_id = wlpn.lpn_id
2004 AND wlpn.lpn_context = 3
2005 -- Added the following line so the index: WMS_LICENSE_PLATE_NUMBERS_N6
2006 -- can be used in case the SQL optimizer uses WLPN as the driving table.
2007 AND wlpn.organization_id = l_organization_id;
2008
2009
2010 -- Variables to retrieve the values from the supply lines cursors.
2011 -- We will bulk collect the records from the cursors into these PLSQL tables and
2012 -- use them to do a bulk insert into the xdock pegging global temp table.
2013 TYPE num_tab IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
2014 TYPE uom_tab IS TABLE OF VARCHAR2(3) INDEX BY BINARY_INTEGER;
2015 l_header_id_tb num_tab;
2016 l_line_id_tb num_tab;
2017 l_line_detail_id_tb num_tab;
2018 l_uom_code_tb uom_tab;
2019 l_project_id_tb num_tab;
2020 l_task_id_tb num_tab;
2021
2022 -- Additional PLSQL tables used only by In Receiving supply source type.
2023 -- Since In Receiving supply lines consist of MOLs which can be split during
2024 -- crossdocking, we need this information in order to properly split the MOL records.
2025 -- Non-receiving supply types will just select NULL values for them currently.
2026 l_quantity_tb num_tab;
2027 l_primary_quantity_tb num_tab;
2028 l_secondary_quantity_tb num_tab;
2029 l_secondary_uom_code_tb uom_tab;
2030 l_lpn_id_tb num_tab;
2031
2032 -- Variables to store the expected time values for the supply line records retrieved.
2033 -- We will use the date tables to do a bulk insert into the xdock pegging global temp table.
2034 TYPE date_tab IS TABLE OF DATE INDEX BY BINARY_INTEGER;
2035 l_dock_start_time_tb date_tab;
2036 l_dock_mean_time_tb date_tab;
2037 l_dock_end_time_tb date_tab;
2038 l_expected_time_tb date_tab;
2039
2040 -- Type used to keep track of which supply source types for a given item
2041 -- have already been queried for so we do not do this again.
2042 -- This table will be indexed by the supply source code as used by the crossdock criteria
2043 -- tables. If an entry exists for that index it will have a value of TRUE. If the value
2044 -- does not exist, then the supply source type has not been queried for yet.
2045 TYPE bool_tab IS TABLE OF BOOLEAN INDEX BY BINARY_INTEGER;
2046
2047 -- Table indexed by inventory_item_id to keep track of which
2048 -- supply source types have already been retrieved and inserted into
2049 -- the wms_xdock_pegging_gtmp table.
2050 TYPE src_types_retrieved_tb IS TABLE OF bool_tab INDEX BY BINARY_INTEGER;
2051 l_src_types_retrieved_tb src_types_retrieved_tb;
2052
2053 -- Index used to loop through the release table
2054 l_wdd_index NUMBER;
2055
2056 -- Cursor to lock the WDD demand record
2057 CURSOR lock_wdd_record(p_delivery_detail_id NUMBER) IS
2058 SELECT delivery_detail_id
2059 FROM wsh_delivery_details
2060 WHERE delivery_detail_id = p_delivery_detail_id
2061 FOR UPDATE NOWAIT;
2062
2063 -- Variables used for the current WDD demand record
2064 l_demand_type_id NUMBER;
2065 l_demand_header_id NUMBER; -- OE order header ID
2066 l_demand_so_header_id NUMBER; -- Sales order header ID
2067 l_demand_line_id NUMBER;
2068 l_demand_line_detail_id NUMBER;
2069 l_crossdock_criteria_id NUMBER;
2070 l_dock_start_time DATE;
2071 l_dock_mean_time DATE;
2072 l_dock_end_time DATE;
2073 l_demand_expected_time DATE;
2074 l_demand_dock_exists BOOLEAN;
2075 l_demand_qty NUMBER;
2076 l_demand_uom_code VARCHAR2(3);
2077 l_demand_qty2 NUMBER;
2078 l_demand_uom_code2 VARCHAR2(3);
2079 l_demand_project_id NUMBER;
2080 l_demand_task_id NUMBER;
2081
2082 -- Type used to cache the item parameters needed
2083 TYPE item_params_rec IS RECORD
2084 (primary_uom_code VARCHAR2(3),
2085 reservable_type NUMBER,
2086 lot_control_code NUMBER,
2087 lot_divisible_flag VARCHAR2(1),
2088 item_type VARCHAR2(30)
2089 );
2090 -- Table indexed by inventory_item_id to store item parameters
2091 TYPE item_params_tb IS TABLE OF item_params_rec
2092 INDEX BY BINARY_INTEGER;
2093 l_item_params_tb item_params_tb;
2094
2095 -- Variables used to call the rules engine to retrieve the crossdock criteria
2096 l_return_type VARCHAR2(1);
2097 l_sequence_number NUMBER;
2098
2099 -- Type used to cache the UOM class info for a given UOM code
2100 TYPE uom_class_tb IS TABLE OF VARCHAR2(10) INDEX BY VARCHAR2(3);
2101 l_uom_class_tb uom_class_tb;
2102
2103 -- Cursor to retrieve the existing high level non-crossdocked non-inventory reservations
2104 -- for the current WDD record. For these types of reservations, the detailed_quantity
2105 -- column should be NULL or 0.
2106 -- We will also lock the reservations records here. Using the SKIP LOCKED keyword,
2107 -- we can select only row records which are lockable without erroring out the entire query.
2108 CURSOR existing_rsvs_cursor IS
2109 SELECT reservation_id, supply_source_type_id, supply_source_header_id,
2110 supply_source_line_id, supply_source_line_detail,
2111 reservation_quantity, reservation_uom_code,
2112 secondary_reservation_quantity, secondary_uom_code,
2113 primary_reservation_quantity, primary_uom_code
2114 FROM mtl_reservations
2115 WHERE organization_id = l_organization_id
2116 AND inventory_item_id = l_inventory_item_id
2117 AND demand_source_type_id = l_demand_type_id
2118 AND demand_source_line_id = l_demand_line_id
2119 AND supply_source_type_id <> inv_reservation_global.g_source_type_inv
2120 AND NVL(crossdock_flag, 'N') = 'N'
2121 AND primary_reservation_quantity - NVL(detailed_quantity, 0) > 0
2122 FOR UPDATE SKIP LOCKED; --Bug 6813492
2123
2124 -- Table to store the results from the existing reservations cursor
2125 TYPE existing_rsvs_tb IS TABLE OF existing_rsvs_cursor%ROWTYPE INDEX BY BINARY_INTEGER;
2126 l_existing_rsvs_tb existing_rsvs_tb;
2127
2128 -- Index used to loop through the existing high level non-inventory reservations
2129 l_rsv_index NUMBER;
2130
2131 -- Variables for existing reservations and the related supply line on it
2132 l_rsv_id NUMBER;
2133 l_rsv_qty NUMBER;
2134 l_rsv_uom_code VARCHAR2(3);
2135 l_rsv_qty2 NUMBER;
2136 l_rsv_uom_code2 VARCHAR2(3);
2137 l_rsv_prim_qty NUMBER;
2138 l_rsv_prim_uom_code VARCHAR2(3);
2139 l_supply_uom_code VARCHAR2(3);
2140 l_supply_type_id NUMBER;
2141 l_supply_header_id NUMBER;
2142 l_supply_line_id NUMBER;
2143 l_supply_line_detail_id NUMBER;
2144 l_supply_project_id NUMBER;
2145 l_supply_task_id NUMBER;
2146
2147 -- Variable used to store the current supply source code (as used by crossdock criteria)
2148 -- The supply source codes are different for Reservations and Crossdock Criteria.
2149 l_supply_src_code NUMBER;
2150
2151 -- Variable for retrieving the expected receipt time for supply line
2152 -- from existing reservations.
2153 l_supply_expected_time DATE;
2154 l_supply_dock_exists BOOLEAN;
2155
2156 -- Crossdock Criteria time interval values.
2157 -- The max precision for the DAY is 2 digits (i.e. 99 DAYs is the largest possible value)
2158 -- and will be enforced in the crossdock criteria definition form.
2159 l_xdock_window_interval INTERVAL DAY(2) TO SECOND;
2160 l_buffer_interval INTERVAL DAY(2) TO SECOND;
2161 l_processing_interval INTERVAL DAY(2) TO SECOND;
2162 l_past_due_interval INTERVAL DAY(2) TO SECOND;
2163 -- Store the past due time value too so we can tell in Get_Supply_Lines if this
2164 -- value is null or not.
2165 l_past_due_time NUMBER;
2166
2167 -- Crossdock time window start and end times. Any valid supplies within this
2168 -- time interval are valid for crossdocking.
2169 l_xdock_start_time DATE;
2170 l_xdock_end_time DATE;
2171
2172 -- The following are cursors used to satisfy existing reservations. The supply line(s)
2173 -- on the reservation needs to be locked before we can crossdock it.
2174 -- A UOM code to match can be inputted if we are trying to crossdock an existing
2175 -- reservation for this supply type. If the UOM Integrity flag is 'Y',
2176 -- we only want to pick up supply line(s) that have the same UOM as the reservation.
2177 -- We just need to lock the appropriate records (do not need to lock MUOM records).
2178 -- The project and task of the demand line is also passed in to match to the supply.
2179 -- If the org is PJM enabled and cross project allocation is not allowed, then the project
2180 -- and task values have to match. The project and task values for the PO, ASN, and Int Req
2181 -- cursors are retrieved from a subquery. This is because the FOR UPDATE OF clause does not
2182 -- work if there is a GROUP BY in the main clause.
2183
2184 -- Cursor to lock the PO supply line record.
2185 CURSOR lock_po_record(p_uom_code VARCHAR2, p_project_id NUMBER, p_task_id NUMBER) IS
2186 SELECT muom.uom_code, pod.project_id, pod.task_id
2187 FROM po_line_locations_all poll, mtl_units_of_measure muom,
2188 (SELECT po_header_id, po_line_id, line_location_id,
2189 MIN(project_id) AS project_id, MIN(task_id) AS task_id
2190 FROM po_distributions_all
2191 WHERE po_header_id = l_supply_header_id
2192 AND line_location_id = l_supply_line_id
2193 GROUP BY po_header_id, po_line_id, line_location_id
2194 HAVING COUNT(DISTINCT NVL(project_id, -999)) = 1
2195 AND COUNT(DISTINCT NVL(task_id, -999)) = 1
2196 AND (l_project_ref_enabled = 2 OR
2197 l_allow_cross_proj_issues = 'Y' OR
2198 (NVL(MIN(project_id), -999) = NVL(p_project_id, -999) AND
2199 NVL(MIN(task_id), -999) = NVL(p_task_id, -999)))) pod
2200 WHERE poll.po_header_id = l_supply_header_id
2201 AND poll.line_location_id = l_supply_line_id
2202 AND poll.unit_meas_lookup_code = muom.unit_of_measure
2203 AND (p_uom_code IS NULL OR muom.uom_code = p_uom_code)
2204 AND pod.po_header_id = poll.po_header_id
2205 AND pod.po_line_id = poll.po_line_id
2206 AND pod.line_location_id = poll.line_location_id
2207 FOR UPDATE OF poll.line_location_id NOWAIT;
2208
2209 -- Cursor to lock the ASN supply line record.
2210 CURSOR lock_asn_record(p_uom_code VARCHAR2, p_project_id NUMBER, p_task_id NUMBER) IS
2211 SELECT muom.uom_code, pod.project_id, pod.task_id
2212 FROM rcv_shipment_lines rsl, po_line_locations_all poll, mtl_units_of_measure muom,
2213 (SELECT po_header_id, po_line_id, line_location_id,
2214 MIN(project_id) AS project_id, MIN(task_id) AS task_id
2215 FROM po_distributions_all
2216 WHERE po_header_id = l_supply_header_id
2217 AND line_location_id = l_supply_line_id
2218 GROUP BY po_header_id, po_line_id, line_location_id
2219 HAVING COUNT(DISTINCT NVL(project_id, -999)) = 1
2220 AND COUNT(DISTINCT NVL(task_id, -999)) = 1
2221 AND (l_project_ref_enabled = 2 OR
2222 l_allow_cross_proj_issues = 'Y' OR
2223 (NVL(MIN(project_id), -999) = NVL(p_project_id, -999) AND
2224 NVL(MIN(task_id), -999) = NVL(p_task_id, -999)))) pod
2225 WHERE rsl.po_header_id = l_supply_header_id
2226 AND rsl.po_line_location_id = l_supply_line_id
2227 AND rsl.shipment_line_id = l_supply_line_detail_id
2228 AND rsl.po_line_location_id = poll.line_location_id
2229 AND rsl.unit_of_measure = muom.unit_of_measure
2230 AND (p_uom_code IS NULL OR muom.uom_code = p_uom_code)
2231 AND pod.po_header_id = poll.po_header_id
2232 AND pod.po_line_id = poll.po_line_id
2233 AND pod.line_location_id = poll.line_location_id
2234 FOR UPDATE OF rsl.shipment_line_id, poll.line_location_id NOWAIT;
2235
2236 -- Cursor to lock the Internal Req supply line record.
2237 -- This can pull up multiple records if the given requisition line has several
2238 -- shipment lines tied to it. Each shipment line can be in a different UOM.
2239 -- For UOM integrity, if we want to match the UOM from the supply to the reservation,
2240 -- just use the UOM at the requisition line level.
2241 CURSOR lock_intreq_record(p_uom_code VARCHAR2, p_project_id NUMBER, p_task_id NUMBER) IS
2242 SELECT muom_prl.uom_code, prd.project_id, prd.task_id
2243 FROM po_requisition_lines_all prl, rcv_shipment_lines rsl, mtl_units_of_measure muom_prl,
2244 (SELECT requisition_line_id, MIN(project_id) AS project_id, MIN(task_id) AS task_id
2245 FROM po_req_distributions_all
2246 WHERE requisition_line_id = l_supply_line_id
2247 GROUP BY requisition_line_id
2248 HAVING COUNT(DISTINCT NVL(project_id, -999)) = 1
2249 AND COUNT(DISTINCT NVL(task_id, -999)) = 1
2250 AND (l_project_ref_enabled = 2 OR
2251 l_allow_cross_proj_issues = 'Y' OR
2252 (NVL(MIN(project_id), -999) = NVL(p_project_id, -999) AND
2253 NVL(MIN(task_id), -999) = NVL(p_task_id, -999)))) prd
2254 WHERE prl.requisition_header_id = l_supply_header_id
2255 AND prl.requisition_line_id = l_supply_line_id
2256 AND prl.unit_meas_lookup_code = muom_prl.unit_of_measure
2257 AND prl.requisition_line_id = rsl.requisition_line_id (+)
2258 AND (p_uom_code IS NULL OR muom_prl.uom_code = p_uom_code)
2259 AND prd.requisition_line_id = prl.requisition_line_id
2260 FOR UPDATE OF prl.requisition_line_id, rsl.shipment_line_id NOWAIT;
2261
2262 -- Cursor to lock the In Transit Shipment supply line record.
2263 CURSOR lock_intship_record(p_uom_code VARCHAR2, p_project_id NUMBER, p_task_id NUMBER) IS
2264 SELECT muom.uom_code, NULL AS project_id, NULL AS task_id
2265 FROM rcv_shipment_lines rsl, mtl_units_of_measure muom
2266 WHERE rsl.shipment_header_id = l_supply_header_id
2267 AND rsl.shipment_line_id = l_supply_line_id
2268 AND rsl.unit_of_measure = muom.unit_of_measure
2269 AND (p_uom_code IS NULL OR muom.uom_code = p_uom_code)
2270 AND (l_project_ref_enabled = 2 OR
2271 l_allow_cross_proj_issues = 'Y' OR
2272 (p_project_id IS NULL AND p_task_id IS NULL))
2273 FOR UPDATE OF rsl.shipment_line_id NOWAIT;
2274
2275 -- Cursor to lock and retrieve valid In Receiving supply move order lines.
2276 -- The MOLs will be ordered by ABS(mtrl.primary_quantity - p_rsv_prim_qty) ASC in order
2277 -- to minimize the amount of splitting that might need to be done for reservations and WDD
2278 -- demand lines. This ordering will find MOLs that are closest to the reservation quantity.
2279 -- MOLs which have the same primary quantity.
2280 -- We also want to match the project/task on the demand line to the MOL supply lines if
2281 -- cross project allocation is not allowed.
2282 CURSOR lock_receiving_lines(p_uom_code VARCHAR2,
2283 p_rsv_prim_qty NUMBER,
2284 p_project_id NUMBER,
2285 p_task_id NUMBER) IS
2286 SELECT
2287 mtrl.header_id AS header_id,
2288 mtrl.line_id AS line_id,
2289 NULL AS line_detail_id,
2290 mtrl.quantity AS quantity,
2291 mtrl.uom_code AS uom_code,
2292 mtrl.primary_quantity AS primary_quantity,
2293 mtrl.secondary_quantity AS secondary_quantity,
2294 mtrl.secondary_uom_code AS secondary_uom_code,
2295 mtrl.project_id AS project_id,
2296 mtrl.task_id AS task_id,
2297 mtrl.lpn_id AS lpn_id
2298 FROM mtl_txn_request_lines mtrl, mtl_txn_request_headers mtrh,
2299 wms_license_plate_numbers wlpn
2300 WHERE mtrl.header_id = mtrh.header_id
2301 AND mtrh.move_order_type = inv_globals.g_move_order_put_away
2302 AND mtrl.organization_id = l_organization_id
2303 AND mtrl.inventory_item_id = l_inventory_item_id
2304 -- Modified the line below to use an IN instead of <> so the
2305 -- index MTL_TXN_REQUEST_LINES_N10 on MTRL is more likely to be used.
2306 -- AND mtrl.line_status <> inv_globals.g_to_status_closed
2307 AND mtrl.line_status IN (inv_globals.g_to_status_preapproved,
2308 inv_globals.g_to_status_approved)
2309 AND mtrl.backorder_delivery_detail_id IS NULL
2310 AND mtrl.lpn_id IS NOT NULL
2311 AND mtrl.quantity > 0
2312 AND NVL(mtrl.quantity_delivered, 0) = 0
2313 AND NVL(mtrl.quantity_detailed, 0) = 0
2314 AND NVL(mtrl.inspection_status, 2) = 2
2315 AND NVL(mtrl.wms_process_flag, 1) = 1
2316 AND NVL(mtrl.reference, 'non-RMA') <> 'ORDER_LINE_ID'
2317 AND (p_uom_code IS NULL OR mtrl.uom_code = p_uom_code)
2318 AND (l_project_ref_enabled = 2 OR
2319 l_allow_cross_proj_issues = 'Y' OR
2320 (NVL(mtrl.project_id, -999) = NVL(p_project_id, -999) AND
2321 NVL(mtrl.task_id, -999) = NVL(p_task_id, -999)))
2322 AND mtrl.lpn_id = wlpn.lpn_id
2323 AND wlpn.lpn_context = 3
2324 -- Added the following line so the index: WMS_LICENSE_PLATE_NUMBERS_N6
2325 -- can be used in case the SQL optimizer uses WLPN as the driving table.
2326 AND wlpn.organization_id = l_organization_id
2327 ORDER BY ABS(mtrl.primary_quantity - p_rsv_prim_qty) ASC
2328 FOR UPDATE OF mtrl.line_id NOWAIT;
2329
2330 -- Table to store the results from the lock_receiving_lines cursor
2331 TYPE rcv_lines_tb IS TABLE OF lock_receiving_lines%ROWTYPE INDEX BY BINARY_INTEGER;
2332 l_rcv_lines_tb rcv_lines_tb;
2333
2334 -- Variables to store the converted quantity values and the available to detail
2335 -- values. They will all be converted to the UOM on the supply line, l_supply_uom_code.
2336 -- We also need the ATD qty in the primary UOM of the item.
2337 -- l_wdd_atr_txn_qty is used when the full quantity on the WDD line may not be available
2338 -- for crossdocking. This is not the case for existing reservations but is possible for
2339 -- normal crossdocking, i.e. other existing reservations tying up quantity on the WDD line.
2340 l_wdd_txn_qty NUMBER;
2341 l_wdd_atr_txn_qty NUMBER;
2342 l_rsv_txn_qty NUMBER;
2343 l_atd_qty NUMBER;
2344 l_atd_prim_qty NUMBER;
2345
2346 -- These values will store the available to detail quantity converted to the UOM of
2347 -- the WDD and RSV record respectively. They are used whenever those records need
2348 -- to be split. The secondary quantities are needed too when splitting a WDD or RSV record.
2349 -- For MOL records, the ATD quantity is always in that UOM. However, we still need to
2350 -- convert the ATD quantity to the secondary UOM on the MOL record if it exists.
2351 l_atd_wdd_qty NUMBER;
2352 l_atd_wdd_qty2 NUMBER;
2353 l_atd_rsv_qty NUMBER;
2354 l_atd_rsv_qty2 NUMBER;
2355 l_atd_mol_qty2 NUMBER;
2356
2357 -- Variables to store supply line info for supply source type of Receiving
2358 l_mol_qty NUMBER;
2359 l_mol_header_id NUMBER;
2360 l_mol_line_id NUMBER;
2361 l_mol_prim_qty NUMBER;
2362 l_mol_qty2 NUMBER;
2363 l_mol_uom_code2 VARCHAR2(3);
2364 l_mol_lpn_id NUMBER;
2365
2366 -- Conversion rate when converting quantity values to different UOMs
2367 l_conversion_rate NUMBER;
2368 -- The standard Inventory precision is to 5 decimal places. Define this in a local constant
2369 -- in case this needs to be changed later on. Variable is used to round off converted values
2370 -- to this precision level.
2371 l_conversion_precision CONSTANT NUMBER := 5;
2372
2373 -- Index used to loop through the supply lines for satisfying an existing reservation.
2374 -- For supplies of type non-Receiving, there is only one supply line used. However, for
2375 -- Receiving supply type, there are multiple MOL's that are possible to loop through.
2376 l_supply_index NUMBER;
2377
2378 -- Variables used to call the Shipping API to split a WDD line if a partial quantity
2379 -- is crossdocked on the WDD line.
2380 l_detail_id_tab WSH_UTIL_CORE.id_tab_type;
2381 l_action_prms WSH_GLBL_VAR_STRCT_GRP.dd_action_parameters_rec_type;
2382 l_action_out_rec WSH_GLBL_VAR_STRCT_GRP.dd_action_out_rec_type;
2383 l_split_wdd_rel_rec WSH_PR_CRITERIA.relRecTyp;
2384 l_split_wdd_id NUMBER;
2385 l_index NUMBER;
2386 l_next_index NUMBER;
2387
2388 -- Variables used to call the Shipping API to update a WDD line when it is
2389 -- being crossdocked.
2390 l_detail_info_tab WSH_INTERFACE_EXT_GRP.Delivery_Details_Attr_Tbl_Type;
2391 l_in_rec WSH_INTERFACE_EXT_GRP.detailInRecType;
2392 l_out_rec WSH_INTERFACE_EXT_GRP.detailOutRecType;
2393
2394 -- Variables to split and update reservations records
2395 l_original_rsv_rec inv_reservation_global.mtl_reservation_rec_type;
2396 l_to_rsv_rec inv_reservation_global.mtl_reservation_rec_type;
2397 l_original_serial_number inv_reservation_global.serial_number_tbl_type;
2398 l_to_serial_number inv_reservation_global.serial_number_tbl_type;
2399 l_split_rsv_id NUMBER;
2400
2401 -- Variables to call the pregenerate API when MOL records are crossdocked
2402 -- to existing reservations.
2403 l_partial_success VARCHAR2(1);
2404 l_lpn_line_error_tbl wms_putaway_suggestions.lpn_line_error_tbl;
2405 l_lpn_index NUMBER;
2406
2407 -- Variables to store the available to reserve quantity for a demand or supply line
2408 -- both in the primary and demand/supply line UOM.
2409 l_demand_atr_prim_qty NUMBER;
2410 l_demand_atr_qty NUMBER;
2411 l_demand_available_qty NUMBER;
2412 l_supply_atr_prim_qty NUMBER;
2413 l_supply_atr_qty NUMBER;
2414 l_supply_available_qty NUMBER;
2415
2416 -- Cursor to retrieve eligible supply source types for a given crossdock criteria
2417 CURSOR supply_src_types_cursor IS
2418 SELECT source_code
2419 FROM wms_xdock_source_assignments
2420 WHERE criterion_id = l_crossdock_criteria_id
2421 AND source_type = G_SRC_TYPE_SUP
2422 ORDER BY priority;
2423
2424 -- Table to store the eligible supply source types indexed by crossdock criteria ID
2425 TYPE supply_src_types_tb IS TABLE OF num_tab INDEX BY BINARY_INTEGER;
2426 l_supply_src_types_tb supply_src_types_tb;
2427
2428 -- Table to store the valid supply lines for crossdocking for the current WDD demand.
2429 -- The type is defined in the specs instead so the custom logic package can reference it.
2430 l_shopping_basket_tb shopping_basket_tb;
2431
2432 -- Cursor to retrieve valid supply lines that fall within the crossdock window
2433 -- of the current demand.
2434 CURSOR get_supply_lines(p_xdock_start_time DATE,
2435 p_xdock_end_time DATE,
2436 p_sup_resched_flag NUMBER,
2437 p_sup_sched_method NUMBER,
2438 p_crossdock_goal NUMBER,
2439 p_past_due_interval INTERVAL DAY TO second,
2440 p_past_due_time NUMBER,
2441 p_po_sup NUMBER, p_po_priority NUMBER,
2442 p_asn_sup NUMBER, p_asn_priority NUMBER,
2443 p_intreq_sup NUMBER, p_intreq_priority NUMBER,
2444 p_intship_sup NUMBER, p_intship_priority NUMBER,
2445 p_rcv_sup NUMBER, p_rcv_priority NUMBER,
2446 p_demand_prim_qty NUMBER,
2447 p_project_id NUMBER,
2448 p_task_id NUMBER) IS
2449 SELECT ROWID,
2450 inventory_item_id,
2451 xdock_source_code,
2452 source_type_id,
2453 source_header_id,
2454 source_line_id,
2455 source_line_detail_id,
2456 dock_start_time,
2457 dock_mean_time,
2458 dock_end_time,
2459 expected_time,
2460 quantity,
2461 reservable_quantity,
2462 uom_code,
2463 primary_quantity,
2464 secondary_quantity,
2465 secondary_uom_code,
2466 project_id,
2467 task_id,
2468 lpn_id,
2469 wip_supply_type
2470 FROM wms_xdock_pegging_gtmp
2471 WHERE inventory_item_id = l_inventory_item_id
2472 AND xdock_source_code IN (p_po_sup, p_asn_sup, p_intreq_sup, p_intship_sup, p_rcv_sup)
2473 AND ((expected_time IS NOT NULL AND (p_past_due_time IS NULL OR
2474 expected_time > SYSDATE - p_past_due_interval)) OR
2475 (dock_start_time IS NOT NULL AND (p_past_due_time IS NULL OR
2476 dock_start_time > SYSDATE - p_past_due_interval)))
2477 -- Only pick up supply lines that match the project/task if necessary
2478 AND (l_project_ref_enabled = 2 OR
2479 l_allow_cross_proj_issues = 'Y' OR
2480 (NVL(project_id, -999) = NVL(p_project_id, -999) AND
2481 NVL(task_id, -999) = NVL(p_task_id, -999)))
2482 AND (-- Dock Appointment Exists
2483 (dock_start_time IS NOT NULL AND
2484 ((p_sup_sched_method = G_APPT_START_TIME AND
2485 dock_start_time BETWEEN p_xdock_start_time AND p_xdock_end_time) OR
2486 (p_sup_sched_method = G_APPT_MEAN_TIME AND
2487 dock_mean_time BETWEEN p_xdock_start_time AND p_xdock_end_time) OR
2488 (p_sup_sched_method = G_APPT_END_TIME AND
2489 dock_end_time BETWEEN p_xdock_start_time AND p_xdock_end_time))
2490 )
2491 -- No Dock Appointment but supply can be rescheduled
2492 OR (dock_start_time IS NULL AND p_sup_resched_flag = 1 AND
2493 expected_time BETWEEN TRUNC(p_xdock_start_time) AND
2494 TO_DATE(TO_CHAR(TRUNC(p_xdock_end_time), 'DD-MON-YYYY') ||
2495 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS')
2496 )
2497 -- No Dock Appointment and supply cannot be rescheduled
2498 OR (dock_start_time IS NULL AND p_sup_resched_flag = 2 AND
2499 expected_time BETWEEN p_xdock_start_time AND p_xdock_end_time
2500 )
2501 )
2502 ORDER BY DECODE (xdock_source_code,
2503 G_PLAN_SUP_PO_APPR, p_po_priority,
2504 G_PLAN_SUP_ASN, p_asn_priority,
2505 G_PLAN_SUP_REQ, p_intreq_priority,
2506 G_PLAN_SUP_INTR, p_intship_priority,
2507 G_PLAN_SUP_RCV, p_rcv_priority,
2508 99),
2509 -- For In Receiving supply lines, order by the quantity closest to the
2510 -- ATR demand qty we are crossdocking for. The expected times should all
2511 -- be the same since the material has already been received.
2512 -- Putting this order by first before the crossdocking goal since only
2513 -- In Receiving supply lines will have a non-null value for primary_quantity.
2514 -- For other supply types, this order by will do nothing. Doing this since the
2515 -- expected time for In Receiving lines just use SYSDATE. We do not want the
2516 -- order the MOL's are encountered and inserted into wms_xdock_pegging_gtmp to
2517 -- affect the order we consume them for crossdocking.
2518 ABS(NVL(primary_quantity, 0) - p_demand_prim_qty) ASC,
2519 DECODE (p_crossdock_goal,
2520 G_MINIMIZE_WAIT, SYSDATE - NVL(expected_time, dock_start_time),
2521 G_MAXIMIZE_XDOCK, NVL(expected_time, dock_start_time) - SYSDATE,
2522 G_CUSTOM_GOAL, NULL,
2523 NULL);
2524
2525 -- Variables for the get_supply_lines cursor to indicate which supply source
2526 -- types/codes to retrieve valid supply lines for. If the supply type is not used,
2527 -- a value of -1 will be defaulted. If it is used, the corresponding supply source code
2528 -- that crossdock criteria uses will be passed.
2529 l_po_sup NUMBER;
2530 l_asn_sup NUMBER;
2531 l_intreq_sup NUMBER;
2532 l_intship_sup NUMBER;
2533 l_rcv_sup NUMBER;
2534
2535 -- Variables for the get_supply_lines cursor to indicate the relative priority of the supply
2536 -- source types to retrieve valid supply lines for. If we don't need to prioritize documents,
2537 -- a default value of 99 will be used. The cursor get_supply_lines will order by the priority
2538 -- value in ascending order so lower values have higher priority.
2539 l_po_priority NUMBER;
2540 l_asn_priority NUMBER;
2541 l_intreq_priority NUMBER;
2542 l_intship_priority NUMBER;
2543 l_rcv_priority NUMBER;
2544
2545 -- Variables to deal with rolling back the changes to the PLSQL data structures:
2546 -- p_wsh_release_table, p_trolin_delivery_ids and p_del_detail_id in case a rollback
2547 -- occurs. The rollback will deal with the database changes to WDD, RSV, and MOL records.
2548 -- However, we are locally storing the changes to WDD records in the data structures
2549 -- mentioned above. We should clean that up and rollback the similar changes made there.
2550 -- Also need to keep track of the WDD values inserted into WSH_PICK_LIST.G_XDOCK_DETAIL_TAB
2551 -- and WSH_PICK_LIST.G_XDOCK_MOL_TAB used for updating the crossdocked WDD records.
2552 l_split_wdd_index NUMBER;
2553 l_split_delivery_index NUMBER;
2554 l_xdocked_wdd_index NUMBER;
2555
2556 -- Type used to store the original WDD values that were modified when crossdocked
2557 TYPE orig_wdd_values_rec IS RECORD
2558 (requested_quantity NUMBER,
2559 requested_quantity2 NUMBER,
2560 released_status VARCHAR2(1),
2561 move_order_line_id NUMBER);
2562 l_orig_wdd_values_rec orig_wdd_values_rec;
2563
2564 -- The following are types used to keep track of which set of MOLs have already been
2565 -- locked as valid supply lines for crossdocking. The three keys to this are the
2566 -- inventory item, project ID, and task ID. This will keep track of what project and task
2567 -- MOLs have already been locked for crossdocking using a nested PLSQL table structure.
2568 -- The project and task part are only stored if the org is PJM enabled AND cross project
2569 -- allocation is not allowed. In that case, the set of MOLs locked will be for a specific
2570 -- project and task matched to ones on the current demand line. Null values of project
2571 -- and task will use -999 as the ID. If the org is not PJM enabled OR cross project allocation
2572 -- is allowed, we just need to insert a dummy project/task part for the given item.
2573 -- e.g. l_locked_mols_tb(l_inventory_item_id)(-999)(-999) := TRUE; In that case, we just need
2574 -- to check that a value exists for the item, i.e. l_locked_mols_tb.EXISTS(l_inventory_item_id).
2575 -- There is no need to go to the project/task levels.
2576 TYPE task_id_tb IS TABLE OF BOOLEAN INDEX BY BINARY_INTEGER;
2577 TYPE project_id_tb IS TABLE OF task_id_tb INDEX BY BINARY_INTEGER;
2578 TYPE locked_mols_tb IS TABLE OF project_id_tb INDEX BY BINARY_INTEGER;
2579 l_locked_mols_tb locked_mols_tb;
2580 l_dummy_project_id NUMBER := -999;
2581 l_dummy_task_id NUMBER := -999;
2582
2583 -- The following are variables used to call the create_reservation API
2584 l_quantity_reserved NUMBER;
2585 l_quantity_reserved2 NUMBER;
2586
2587 -- The following is a table indexed by LPN ID to indicate which LPNs contained MOLs that
2588 -- were crossdocked. This set of MOLs need to call the pre-generate API so the crossdock
2589 -- tasks can be generated.
2590 TYPE crossdocked_lpns_tb IS TABLE OF BOOLEAN INDEX BY BINARY_INTEGER;
2591 l_crossdocked_lpns_tb crossdocked_lpns_tb;
2592
2593 -- Table storing the delivery detail ID's for backordered lines. These records
2594 -- should be removed from the input tables, p_trolin_delivery_ids and p_del_detail_id
2595 -- for allocation mode of N (Prioritize Inventory).
2596 -- This is so deliveries are not autocreated for them later on by Shipping.
2597 l_backordered_wdd_tbl bool_tab;
2598 l_backordered_wdd_lines PLS_INTEGER;
2599
2600 -- Variable used to call the Shipping API to backorder WDD lines.
2601 -- This is used for allocation mode of N (Prioritize Inventory).
2602 l_shipping_attr WSH_INTERFACE.ChangedAttributeTabType;
2603
2604 -- Variables used to bulk update the reservable_quantity column in the global temp table,
2605 -- wms_xdock_pegging_gtmp. We want to do a bulk update for this in case multiple
2606 -- supply lines are consumed when crossdocking a WDD record.
2607 l_supply_atr_index NUMBER;
2608 TYPE rowid_tab IS TABLE OF urowid INDEX BY BINARY_INTEGER;
2609 l_supply_rowid_tb rowid_tab;
2610 l_supply_atr_qty_tb num_tab;
2611
2612 -- Variables used when calling custom logic to sort the supply lines in the
2613 -- shopping basket table.
2614 l_sorted_order_tb sorted_order_tb;
2615 l_shopping_basket_temp_tb shopping_basket_tb;
2616 l_indices_used_tb bool_tab;
2617
2618 -- Error code variable used when calling the private Crossdock_WDD and Crossdock_MOL
2619 -- procedures. This will indicate if an exception occurred during UOM conversion or
2620 -- during a database operation.
2621 -- Possible values are: UOM - UOM Conversion error
2622 -- DB - Database Update error
2623 l_error_code VARCHAR2(3);
2624
2625 -- Dummy variables used for calling Crossdock_MOL. These values are used for
2626 -- WIP demand lines for Opportunistic Crossdock.
2627 l_wip_entity_id NUMBER;
2628 l_repetitive_schedule_id NUMBER;
2629 l_operation_seq_num NUMBER;
2630 l_wip_supply_type NUMBER;
2631
2632 -- Variable for Allocation method of 'Crossdock Only' to indicate if any of the
2633 -- input demand release lines were unable to be crossdocked. This is used so
2634 -- Shipping can display a status of 'Warning' to the user to indicate that some
2635 -- of the lines were unable to be allocated for whatever reason.
2636 l_unable_to_crossdock BOOLEAN := FALSE;
2637
2638 BEGIN
2639 -- Start the profiler for Unit Testing to ensure complete code coverage
2640 --dbms_profiler.start_profiler('Planned_Cross_Dock: ' || p_batch_id);
2641
2642 IF (l_debug = 1) THEN
2643 print_debug('***Calling Planned_Cross_Dock with the following parameters***');
2644 print_debug('Package Version: => ' || g_pkg_version);
2645 print_debug('p_api_version: ===> ' || p_api_version);
2646 print_debug('p_init_msg_list: => ' || p_init_msg_list);
2647 print_debug('p_commit: ========> ' || p_commit);
2648 print_debug('p_batch_id: ======> ' || p_batch_id);
2649 END IF;
2650
2651 -- Set the savepoint
2652 SAVEPOINT Planned_Cross_Dock_sp;
2653 l_progress := '10';
2654
2655 -- Standard Call to check for call compatibility
2656 IF NOT fnd_api.Compatible_API_Call(l_api_version, p_api_version, l_api_name, g_pkg_name) THEN
2657 IF (l_debug = 1) THEN
2658 print_debug('FND_API version not compatible!');
2659 END IF;
2660 RAISE fnd_api.g_exc_unexpected_error;
2661 END IF;
2662
2663 -- Initialize message list to clear any existing messages
2664 IF fnd_api.To_Boolean(p_init_msg_list) THEN
2665 fnd_msg_pub.initialize;
2666 END IF;
2667 l_progress := '20';
2668
2669 -- Initialize API return status to success
2670 x_return_status := fnd_api.g_ret_sts_success;
2671 l_progress := '30';
2672
2673 -- Return if there are no records to crossdock in p_wsh_release_table.
2674 -- {{
2675 -- If no records exist in the release table, API should still process without error. }}
2676 IF (p_wsh_release_table.COUNT = 0) THEN
2677 IF (l_debug = 1) THEN
2678 print_debug('No records in p_wsh_release_table, exiting.');
2679 END IF;
2680 RETURN;
2681 END IF;
2682
2683 -- Initialize the PLSQL tables used to retrieve the supply line cursor records
2684 l_header_id_tb.DELETE;
2685 l_line_id_tb.DELETE;
2686 l_line_detail_id_tb.DELETE;
2687 l_dock_start_time_tb.DELETE;
2688 l_dock_mean_time_tb.DELETE;
2689 l_dock_end_time_tb.DELETE;
2690 l_expected_time_tb.DELETE;
2691 l_quantity_tb.DELETE;
2692 l_uom_code_tb.DELETE;
2693 l_primary_quantity_tb.DELETE;
2694 l_secondary_quantity_tb.DELETE;
2695 l_secondary_uom_code_tb.DELETE;
2696 l_project_id_tb.DELETE;
2697 l_task_id_tb.DELETE;
2698 l_lpn_id_tb.DELETE;
2699
2700 -- Initialize the source types retrieved table
2701 l_src_types_retrieved_tb.DELETE;
2702
2703 -- Initialize the item parameters table
2704 l_item_params_tb.DELETE;
2705
2706 -- Initialize the UOM class table
2707 l_uom_class_tb.DELETE;
2708
2709 -- Initialize the global Item UOM conversion table
2710 g_item_uom_conversion_tb.DELETE;
2711
2712 -- Initialize the eligible supply source types table
2713 l_supply_src_types_tb.DELETE;
2714
2715 -- Initialize the locked MOL's table
2716 l_locked_mols_tb.DELETE;
2717
2718 -- Initialize the crossdocked LPN's table
2719 l_crossdocked_lpns_tb.DELETE;
2720
2721 -- Initialize the detail info table used for updating
2722 -- crossdocked WDD records
2723 l_detail_info_tab.DELETE;
2724
2725 -- Initialize the crossdock criteria cache table
2726 g_crossdock_criteria_tb.DELETE;
2727 l_progress := '40';
2728
2729 -- Query for and cache the picking batch record for the inputted batch ID
2730 -- {{
2731 -- Test for invalid batch ID entered. API should error out. }}
2732 IF (NOT INV_CACHE.set_wpb_rec
2733 (p_batch_id => p_batch_id,
2734 p_request_number => NULL)) THEN
2735 IF (l_debug = 1) THEN
2736 print_debug('Error caching the WSH picking batch record');
2737 END IF;
2738 RAISE fnd_api.g_exc_unexpected_error;
2739 END IF;
2740 l_progress := '50';
2741
2742 -- Retrieve the necessary parameters from the picking batch
2743 -- {{
2744 -- Test for multiple orgs tied to the picking batch. }}
2745 -- If multiple orgs are tied to the picking batch, there should still be only one
2746 -- org for the sub-batch passed to the crossdock API. Just retrieve the org from
2747 -- p_wsh_release_table instead.
2748 --l_organization_id := inv_cache.wpb_rec.organization_id;
2749 l_organization_id := p_wsh_release_table(p_wsh_release_table.FIRST).organization_id;
2750 l_allocation_method := NVL(inv_cache.wpb_rec.allocation_method, G_INVENTORY_ONLY);
2751 l_wpb_xdock_criteria_id := inv_cache.wpb_rec.crossdock_criteria_id;
2752 l_existing_rsvs_only := NVL(inv_cache.wpb_rec.existing_rsvs_only_flag, 'N');
2753 l_progress := '60';
2754
2755 -- Query for and cache the org record.
2756 IF (NOT INV_CACHE.set_org_rec(l_organization_id)) THEN
2757 IF (l_debug = 1) THEN
2758 print_debug('Error caching the org record');
2759 END IF;
2760 RAISE fnd_api.g_exc_unexpected_error;
2761 END IF;
2762 -- Set the PJM enabled flag.
2763 l_project_ref_enabled := INV_CACHE.org_rec.project_reference_enabled;
2764 l_progress := '70';
2765
2766 -- Check if the organization is a WMS organization
2767 l_wms_org_flag := wms_install.check_install
2768 (x_return_status => x_return_status,
2769 x_msg_count => x_msg_count,
2770 x_msg_data => x_msg_data,
2771 p_organization_id => l_organization_id);
2772 IF (x_return_status <> fnd_api.g_ret_sts_success) THEN
2773 IF (l_debug = 1) THEN
2774 print_debug('Call to wms_install.check_install failed: ' || x_msg_data);
2775 END IF;
2776 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
2777 END IF;
2778 l_progress := '80';
2779
2780 -- Retrieve the org parameter for allowing cross project allocation for crossdocking.
2781 -- For now, just hardcode this to 'N'. The reason is even if we create a peg with
2782 -- differing project/task combinations, execution needs to be able to handle this.
2783 -- A project/task transfer needs to be done so until that code is present, we should not
2784 -- create cross project pegs. The following is the SQL for retrieving this value.
2785 /*IF (l_project_ref_enabled = 1) THEN
2786 -- PJM org so see if cross project allocation is allowed
2787 BEGIN
2788 SELECT NVL(allow_cross_proj_issues, 'N')
2789 INTO l_allow_cross_proj_issues
2790 FROM pjm_org_parameters
2791 WHERE organization_id = l_organization_id;
2792 EXCEPTION
2793 WHEN OTHERS THEN
2794 l_allow_cross_proj_issues := 'N';
2795 END;
2796 ELSE
2797 -- Non-PJM org so cross project allocation is allowed since there are no projects or tasks
2798 l_allow_cross_proj_issues := 'Y';
2799 END IF;*/
2800 l_allow_cross_proj_issues := 'N';
2801 l_progress := '90';
2802
2803 -- Validate that the allocation method is not Inventory Only
2804 -- {{
2805 -- Make sure API errors out if the allocation method is Inventory Only. }}
2806 IF (l_allocation_method = G_INVENTORY_ONLY) THEN
2807 IF (l_debug = 1) THEN
2808 print_debug('Allocation method of Inventory Only is invalid');
2809 END IF;
2810 RAISE fnd_api.g_exc_unexpected_error;
2811 END IF;
2812 l_progress := '100';
2813
2814 -- Query for and cache the crossdock criteria record for the picking batch
2815 -- if a value exists. This crossdock criterion will be used for all of the
2816 -- WDD records to be crossdocked.
2817 -- {{
2818 -- API should error out if invalid crossdock criteria is passed from the picking batch. }}
2819 IF (l_wpb_xdock_criteria_id IS NOT NULL) THEN
2820 IF (NOT set_crossdock_criteria(l_wpb_xdock_criteria_id)) THEN
2821 IF (l_debug = 1) THEN
2822 print_debug('Error caching the crossdock criteria record: ' ||
2823 l_wpb_xdock_criteria_id);
2824 END IF;
2825 RAISE fnd_api.g_exc_unexpected_error;
2826 END IF;
2827 END IF;
2828 l_progress := '110';
2829 -- End of validations and initializations
2830
2831
2832 -- Loop through the release table and try to crossdock records with
2833 -- a released status of 'R' or 'B'.
2834 l_wdd_index := p_wsh_release_table.FIRST;
2835 LOOP
2836 -- Crossdock the current WDD record only if it has a released status of R or B.
2837 -- Do not crossdock any of the WDD records if the org is not a WMS org. We still need
2838 -- to do some post-crossdocking logic for certain cases if this API is called for a
2839 -- non WMS org, e.g. backordering the unallocated WDD lines for Prioritize Inventory.
2840 -- {{
2841 -- WDD records with a released status other than R or B should not be crossdocked. }}
2842 -- {{
2843 -- Test for crossdock API called for a non WMS org. Post crossdock logic should still
2844 -- be done, such as backordering the unallocated WDD lines for Prioritize Inventory. }}
2845 IF (p_wsh_release_table(l_wdd_index).released_status NOT IN ('R','B') OR
2846 NOT l_wms_org_flag) THEN
2847 GOTO next_record;
2848 END IF;
2849
2850 -- Section 1: Demand line validations and initializations
2851 -- For the current demand line, perform the following validations and
2852 -- initializations on it.
2853 -- 1.1 - Validate that the demand line is eligible for crossdocking.
2854 -- 1.2 - Lock the demand line record.
2855 -- 1.3 - Retrieve and store the crossdock criterion for the demand line.
2856 -- 1.4 - Determine the expected ship date for the demand line.
2857 -- Calculate the crossdock window given the expected ship date and crossdock
2858 -- criteria time parameters.
2859
2860 -- Retrieve necessary parameters for the current demand line from p_wsh_release_table
2861 --l_organization_id := p_wsh_release_table(l_wdd_index).organization_id;
2862 l_inventory_item_id := p_wsh_release_table(l_wdd_index).inventory_item_id;
2863 l_demand_header_id := p_wsh_release_table(l_wdd_index).source_header_id;
2864 l_demand_so_header_id := inv_salesorder.get_salesorder_for_oeheader(l_demand_header_id);
2865 l_demand_line_id := p_wsh_release_table(l_wdd_index).source_line_id;
2866 l_demand_line_detail_id := p_wsh_release_table(l_wdd_index).delivery_detail_id;
2867 l_demand_qty := p_wsh_release_table(l_wdd_index).requested_quantity;
2868 l_demand_uom_code := p_wsh_release_table(l_wdd_index).requested_quantity_uom;
2869 l_demand_qty2 := p_wsh_release_table(l_wdd_index).requested_quantity2;
2870 l_demand_uom_code2 := p_wsh_release_table(l_wdd_index).requested_quantity_uom2;
2871 l_demand_project_id := p_wsh_release_table(l_wdd_index).project_id;
2872 l_demand_task_id := p_wsh_release_table(l_wdd_index).task_id;
2873 IF (NVL(p_wsh_release_table(l_wdd_index).source_doc_type, -999) <> 10) THEN
2874 -- Sales Order
2875 l_demand_type_id := 2;
2876 ELSE
2877 -- Internal Order
2878 l_demand_type_id := 8;
2879 END IF;
2880 IF (l_debug = 1) THEN
2881 print_debug('1.0 - Current WDD to crossdock: ==> ' || l_demand_line_detail_id);
2882 print_debug('1.0 - Current Item to crossdock: => ' || l_inventory_item_id);
2883 END IF;
2884
2885 -- 1.1 - Validate that the demand line is eligible for crossdocking.
2886 IF (l_debug = 1) THEN
2887 print_debug('1.1 - Validate that the demand line is eligible for crossdocking');
2888 END IF;
2889
2890 -- Make sure current WDD is not associated with a ship set or ship model.
2891 -- {{
2892 -- WDD demand lines tied to ship sets or ship models should not be crossdocked. }}
2893 IF (l_debug = 1) THEN
2894 print_debug('1.1 - Ship Set ID: ========> ' ||
2895 p_wsh_release_table(l_wdd_index).ship_set_id);
2896 print_debug('1.1 - Top Model Line ID: ==> ' ||
2897 p_wsh_release_table(l_wdd_index).top_model_line_id);
2898 END IF;
2899 IF (p_wsh_release_table(l_wdd_index).ship_set_id IS NOT NULL OR
2900 p_wsh_release_table(l_wdd_index).top_model_line_id IS NOT NULL) THEN
2901 IF (l_debug = 1) THEN
2902 print_debug('1.1 - Do not crossdock ship set or ship model WDD lines');
2903 END IF;
2904 GOTO next_record;
2905 END IF;
2906
2907 -- Query for and cache the item parameters needed.
2908 -- {{
2909 -- If item parameter information cannot be retrieved, make sure we just go on to the
2910 -- next WDD record to crossdock. }}
2911 IF (NOT l_item_params_tb.EXISTS(l_inventory_item_id)) THEN
2912 BEGIN
2913 SELECT primary_uom_code, NVL(reservable_type, 1),
2914 NVL(lot_control_code, 1), NVL(lot_divisible_flag, 'Y'), item_type
2915 INTO l_item_params_tb(l_inventory_item_id)
2916 FROM mtl_system_items
2917 WHERE inventory_item_id = l_inventory_item_id
2918 AND organization_id = l_organization_id;
2919 EXCEPTION
2920 WHEN OTHERS THEN
2921 IF (l_debug = 1) THEN
2922 print_debug('1.1 - Error caching the item parameters: ' ||
2923 l_inventory_item_id);
2924 END IF;
2925 GOTO next_record;
2926 --RAISE fnd_api.g_exc_unexpected_error;
2927 END;
2928 END IF;
2929 -- Store the item's primary UOM code in a local variable
2930 l_primary_uom_code := l_item_params_tb(l_inventory_item_id).primary_uom_code;
2931
2932 -- Make sure the item is reservable.
2933 -- {{
2934 -- Non-reservable items should not be crossdocked. }}
2935 IF (l_debug = 1) THEN
2936 print_debug('1.1 - Reservable Type: ====> ' ||
2937 l_item_params_tb(l_inventory_item_id).reservable_type);
2938 END IF;
2939 IF (l_item_params_tb(l_inventory_item_id).reservable_type = 2) THEN
2940 IF (l_debug = 1) THEN
2941 print_debug('1.1 - Do not crossdock non-reservable items');
2942 END IF;
2943 GOTO next_record;
2944 END IF;
2945
2946 -- Make sure the item is lot divisible if it is lot controlled.
2947 -- {{
2948 -- Lot Indivisible items should not be crossdocked. }}
2949 IF (l_debug = 1) THEN
2950 print_debug('1.1 - Lot Control Code: ===> ' ||
2951 l_item_params_tb(l_inventory_item_id).lot_control_code);
2952 print_debug('1.1 - Lot Divisible Flag: => ' ||
2953 l_item_params_tb(l_inventory_item_id).lot_divisible_flag);
2954 END IF;
2955 IF (l_item_params_tb(l_inventory_item_id).lot_control_code = 2 AND
2956 l_item_params_tb(l_inventory_item_id).lot_divisible_flag = 'N') THEN
2957 IF (l_debug = 1) THEN
2958 print_debug('1.1 - Do not crossdock lot indivisible items');
2959 END IF;
2960 GOTO next_record;
2961 END IF;
2962 l_progress := '120';
2963
2964 -- If we do not allow partial WIP crossdocking, that is a mix of demand being tied to
2965 -- both WIP and other non-Inventory supply sources, validate that the current demand
2966 -- it not already tied to WIP supply.
2967 IF (WMS_XDOCK_CUSTOM_APIS_PUB.g_allow_partial_wip_xdock = 'N') THEN
2968 IF (WMS_XDOCK_PEGGING_PUB.is_demand_tied_to_wip
2969 (p_organization_id => l_organization_id,
2970 p_inventory_item_id => l_inventory_item_id,
2971 p_demand_type_id => l_demand_type_id,
2972 p_demand_header_id => l_demand_so_header_id,
2973 p_demand_line_id => l_demand_line_id) = 'Y') THEN
2974 IF (l_debug = 1) THEN
2975 print_debug('1.1 - Do not crossdock demand already tied to WIP supply');
2976 END IF;
2977 GOTO next_record;
2978 END IF;
2979 END IF;
2980 l_progress := '125';
2981
2982 -- 1.2 - Lock the demand line record.
2983 -- {{
2984 -- If the WDD demand line cannot be locked, move on to the next record. }}
2985 IF (l_debug = 1) THEN
2986 print_debug('1.2 - Lock the demand line record: ' || l_demand_line_detail_id);
2987 END IF;
2988 BEGIN
2989 OPEN lock_wdd_record(l_demand_line_detail_id);
2990 CLOSE lock_wdd_record;
2991 EXCEPTION
2992 WHEN OTHERS THEN
2993 IF (l_debug = 1) THEN
2994 print_debug('1.2 - Could not lock the current WDD record: ' ||
2995 l_demand_line_detail_id);
2996 END IF;
2997 -- If unable to lock the current WDD record for some reason, do not error out.
2998 -- Just skip it and try to crossdock the next WDD record.
2999 GOTO next_record;
3000 END;
3001 l_progress := '130';
3002
3003 -- 1.3 - Retrieve and store the crossdock criterion for the demand line.
3004 IF (l_debug = 1) THEN
3005 print_debug('1.3 - Retrieve and store the crossdock criterion for the demand line');
3006 END IF;
3007 IF (l_wpb_xdock_criteria_id IS NOT NULL) THEN
3008 -- Use the crossdock criteria inputted for the picking batch.
3009 -- This record should already be queried for and cached.
3010 l_crossdock_criteria_id := l_wpb_xdock_criteria_id;
3011 ELSE
3012 -- Query for and cache the UOM class for the current UOM code.
3013 -- {{
3014 -- If the UOM class cannot be retrieved, just move on to the next WDD record. }}
3015 IF (NOT l_uom_class_tb.EXISTS(l_demand_uom_code)) THEN
3016 BEGIN
3017 SELECT uom_class
3018 INTO l_uom_class_tb(l_demand_uom_code)
3019 FROM mtl_units_of_measure
3020 WHERE uom_code = l_demand_uom_code;
3021 EXCEPTION
3022 WHEN OTHERS THEN
3023 IF (l_debug = 1) THEN
3024 print_debug('1.3 - Error caching the UOM class: ' || l_demand_uom_code);
3025 END IF;
3026 --GOTO next_record;
3027 --RAISE fnd_api.g_exc_unexpected_error;
3028 -- Instead of skipping to the next record, just store a NULL value
3029 -- for the UOM class. The crossdock criteria retrieved will thus not
3030 -- make use of the UOM class as a filter.
3031 l_uom_class_tb(l_demand_uom_code) := NULL;
3032 END;
3033 END IF;
3034
3035 -- Call the custom API to determine a valid crossdock criteria first.
3036 -- If this API is not implemented, it will just be a stub and return a value of
3037 -- FALSE for x_api_is_implemented.
3038 -- {{
3039 -- Test for an implemented custom API to get the crossdock criteria. We should not
3040 -- call the rules engine in this case. }}
3041 WMS_XDOCK_CUSTOM_APIS_PUB.Get_Crossdock_Criteria
3042 (p_wdd_release_record => p_wsh_release_table(l_wdd_index),
3043 x_return_status => x_return_status,
3044 x_msg_count => x_msg_count,
3045 x_msg_data => x_msg_data,
3046 x_api_is_implemented => l_api_is_implemented,
3047 x_crossdock_criteria_id => l_crossdock_criteria_id);
3048
3049 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
3050 IF (l_debug = 1) THEN
3051 print_debug('1.3 - Success returned from Get_Crossdock_Criteria API');
3052 END IF;
3053 ELSE
3054 IF (l_debug = 1) THEN
3055 print_debug('1.3 - Failure returned from Get_Crossdock_Criteria API');
3056 END IF;
3057 GOTO next_record;
3058 --RAISE fnd_api.g_exc_error;
3059 END IF;
3060
3061 -- If the custom API is not implemented, call the rules engine to determine the
3062 -- crossdock criteria for the current WDD record.
3063 IF (NOT l_api_is_implemented) THEN
3064 -- Call the rules engine to retrieve the crossdock criteria
3065 -- for the current WDD record
3066 -- {{
3067 -- If the rules errors out while determining a crossdock criteria, just go to the
3068 -- next WDD record. }}
3069 IF (l_debug = 1) THEN
3070 print_debug('1.3 - Call the cross_dock_search Rules Workbench API');
3071 END IF;
3072 wms_rules_workbench_pvt.cross_dock_search
3073 ( p_rule_type_code => G_CRT_RULE_TYPE_PLAN,
3074 p_organization_id => l_organization_id,
3075 p_customer_id => p_wsh_release_table(l_wdd_index).customer_id,
3076 p_inventory_item_id => l_inventory_item_id,
3077 p_item_type => l_item_params_tb(l_inventory_item_id).item_type,
3078 p_vendor_id => NULL,
3079 p_location_id => p_wsh_release_table(l_wdd_index).ship_from_location_id,
3080 p_project_id => p_wsh_release_table(l_wdd_index).project_id,
3081 p_task_id => p_wsh_release_table(l_wdd_index).task_id,
3082 p_user_id => FND_GLOBAL.user_id,
3083 p_uom_code => l_demand_uom_code,
3084 p_uom_class => l_uom_class_tb(l_demand_uom_code),
3085 x_return_type => l_return_type,
3086 x_return_type_id => l_crossdock_criteria_id,
3087 x_sequence_number => l_sequence_number,
3088 x_return_status => x_return_status);
3089
3090 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
3091 IF (l_debug = 1) THEN
3092 print_debug('1.3 - Success returned from cross_dock_search API');
3093 END IF;
3094 ELSE
3095 IF (l_debug = 1) THEN
3096 print_debug('1.3 - Failure returned from cross_dock_search API');
3097 END IF;
3098 GOTO next_record;
3099 --RAISE fnd_api.g_exc_error;
3100 END IF;
3101 END IF;
3102
3103 -- Query for and cache the crossdock criteria retrieved from the rules engine
3104 IF (l_crossdock_criteria_id IS NOT NULL) THEN
3105 IF (NOT set_crossdock_criteria(l_crossdock_criteria_id)) THEN
3106 IF (l_debug = 1) THEN
3107 print_debug('1.3 - Error caching the crossdock criteria record: ' ||
3108 l_crossdock_criteria_id);
3109 END IF;
3110 GOTO next_record;
3111 --RAISE fnd_api.g_exc_unexpected_error;
3112 END IF;
3113 END IF;
3114
3115 END IF; -- END IF matching 'IF (l_wpb_xdock_criteria_id IS NOT NULL) THEN'
3116 IF (l_debug = 1) THEN
3117 print_debug('1.3 - Crossdock Criteria ID to use: ' || l_crossdock_criteria_id);
3118 END IF;
3119 -- Do not crossdock WDD record if a crossdock criteria is not retrieved.
3120 -- {{
3121 -- If a crossdock criteria is not returned by the rules engine, stop processing
3122 -- and move on to the next WDD record to crossdock. }}
3123 IF (l_crossdock_criteria_id IS NULL) THEN
3124 GOTO next_record;
3125 END IF;
3126 l_progress := '140';
3127
3128 -- 1.4 - Determine the expected ship date for the demand line.
3129 -- Calculate the crossdock window given the expected ship date and crossdock
3130 -- criteria time parameters.
3131 IF (l_debug = 1) THEN
3132 print_debug('1.4 - Determine the expected ship date for the demand line');
3133 END IF;
3134 Get_Expected_Time
3135 (p_source_type_id => l_demand_type_id,
3136 p_source_header_id => l_demand_so_header_id,
3137 p_source_line_id => l_demand_line_id,
3138 p_source_line_detail_id => l_demand_line_detail_id,
3139 p_supply_or_demand => G_SRC_TYPE_DEM,
3140 p_crossdock_criterion_id => l_crossdock_criteria_id,
3141 x_return_status => x_return_status,
3142 x_msg_count => x_msg_count,
3143 x_msg_data => x_msg_data,
3144 x_dock_start_time => l_dock_start_time,
3145 x_dock_mean_time => l_dock_mean_time,
3146 x_dock_end_time => l_dock_end_time,
3147 x_expected_time => l_demand_expected_time);
3148
3149 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
3150 IF (l_debug = 1) THEN
3151 print_debug('1.4 - Success returned from Get_Expected_Time API');
3152 END IF;
3153 ELSE
3154 IF (l_debug = 1) THEN
3155 print_debug('1.4 - Failure returned from Get_Expected_Time API');
3156 END IF;
3157 GOTO next_record;
3158 --RAISE fnd_api.g_exc_error;
3159 END IF;
3160 -- Use this value to determine if a dock appointment for the demand line exists.
3161 -- There is a parameter on the crossdock criteria to decide if we should schedule
3162 -- demand anytime on the shipment date if no dock appointment exists.
3163 IF (l_dock_start_time IS NOT NULL) THEN
3164 l_demand_dock_exists := TRUE;
3165 ELSE
3166 l_demand_dock_exists := FALSE;
3167 END IF;
3168 -- Do not crossdock WDD record if an expected time cannot be determined.
3169 -- {{
3170 -- If the expected time for the WDD demand cannot be determined, stop processing
3171 -- and move on to the next record. }}
3172 IF (l_demand_expected_time IS NULL) THEN
3173 IF (l_debug = 1) THEN
3174 print_debug('1.4 - Unable to crossdock WDD record since demand expected time is NULL');
3175 END IF;
3176 GOTO next_record;
3177 END IF;
3178 IF (l_debug = 1) THEN
3179 print_debug('1.4 - Demand expected time: => ' ||
3180 TO_CHAR(l_demand_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
3181 END IF;
3182 l_progress := '150';
3183
3184 -- Get the time interval values for the crossdock criteria.
3185 -- Time intervals will be defined using the function NUMTODSINTERVAL
3186 -- Crossdock Window Time Interval
3187 l_xdock_window_interval := NUMTODSINTERVAL
3188 (g_crossdock_criteria_tb(l_crossdock_criteria_id).window_interval,
3189 g_crossdock_criteria_tb(l_crossdock_criteria_id).window_uom);
3190 IF (l_debug = 1) THEN
3191 print_debug('1.4 - Crossdock Window: ' ||
3192 g_crossdock_criteria_tb(l_crossdock_criteria_id).window_interval || ' ' ||
3193 g_crossdock_criteria_tb(l_crossdock_criteria_id).window_uom);
3194 END IF;
3195 -- Buffer Time Interval
3196 -- The buffer time interval and UOM should either both be NULL or not NULL.
3197 l_buffer_interval := NUMTODSINTERVAL
3198 (NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_interval, 0),
3199 NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_uom, 'HOUR'));
3200 IF (l_debug = 1) THEN
3201 print_debug('1.4 - Buffer Time: ' ||
3202 g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_interval || ' ' ||
3203 g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_uom);
3204 END IF;
3205 -- Order Processing Time Interval
3206 -- The order processing time interval and UOM should either both be NULL or not NULL.
3207 l_processing_interval := NUMTODSINTERVAL
3208 (NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_interval, 0),
3209 NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_uom, 'HOUR'));
3210 IF (l_debug = 1) THEN
3211 print_debug('1.4 - Order Processing Time: ' ||
3212 g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_interval || ' ' ||
3213 g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_uom);
3214 END IF;
3215 -- Past Due Time Interval
3216 -- The past due time interval and UOM should either both be NULL or not NULL.
3217 l_past_due_interval := NUMTODSINTERVAL
3218 (NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).past_due_interval, 0),
3219 NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).past_due_uom, 'HOUR'));
3220 IF (l_debug = 1) THEN
3221 print_debug('1.4 - Past Due Time: ' ||
3222 g_crossdock_criteria_tb(l_crossdock_criteria_id).past_due_interval || ' ' ||
3223 g_crossdock_criteria_tb(l_crossdock_criteria_id).past_due_uom);
3224 END IF;
3225 -- Set the variable to the past due time value.
3226 -- If this value is NULL, then that means we do not restrict past due supplies no matter
3227 -- how far in the past their expected time is.
3228 l_past_due_time := g_crossdock_criteria_tb(l_crossdock_criteria_id).past_due_interval;
3229
3230 -- If a dock appointment for the demand does not exist and the crossdock criteria
3231 -- allows rescheduling of the demand for anytime on the expected ship date, set the
3232 -- appropriate crossdock time window interval.
3233 -- {{
3234 -- Test for a WDD demand where a dock appointment does not exist and demand rescheduling
3235 -- is allowed. }}
3236 IF (NOT l_demand_dock_exists AND
3237 g_crossdock_criteria_tb(l_crossdock_criteria_id).allow_demand_reschedule_flag = 1 AND
3238 l_demand_expected_time >= SYSDATE) THEN
3239 -- Demand can be scheduled anytime on the expected ship date so use 12:00AM to calculate
3240 -- the crossdock window start time and 11:59PM to calculate the crossdock window
3241 -- end time. Note this will yield a time interval of 24 hours plus the crossdock window
3242 -- time interval.
3243 l_xdock_start_time := TRUNC(l_demand_expected_time) -
3244 (l_processing_interval + l_buffer_interval + l_xdock_window_interval);
3245 l_xdock_end_time := TO_DATE(TO_CHAR(TRUNC(l_demand_expected_time), 'DD-MON-YYYY') ||
3246 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS') -
3247 (l_processing_interval + l_buffer_interval);
3248 ELSIF (l_demand_expected_time < SYSDATE) THEN
3249 -- For demand that is expected to ship out in the past, consider it as ready to ship
3250 -- out anytime on the current date. Ideally someone should go back to modify the
3251 -- scheduled ship date for these demand lines.
3252 l_xdock_start_time := TRUNC(SYSDATE) -
3253 (l_processing_interval + l_buffer_interval + l_xdock_window_interval);
3254 l_xdock_end_time := TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'DD-MON-YYYY') ||
3255 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS') -
3256 (l_processing_interval + l_buffer_interval);
3257 ELSE
3258 -- Demand cannot be rescheduled so just use the expected ship date to calculate
3259 -- the crossdock window start and end times for valid supplies to crossdock
3260 l_xdock_start_time := l_demand_expected_time -
3261 (l_processing_interval + l_buffer_interval + l_xdock_window_interval);
3262 l_xdock_end_time := l_demand_expected_time -
3263 (l_processing_interval + l_buffer_interval);
3264 END IF;
3265 IF (l_debug = 1) THEN
3266 print_debug('1.4 - Crossdock start time: => ' ||
3267 TO_CHAR(l_xdock_start_time, 'DD-MON-YYYY HH24:MI:SS'));
3268 print_debug('1.4 - Crossdock end time: ===> ' ||
3269 TO_CHAR(l_xdock_end_time, 'DD-MON-YYYY HH24:MI:SS'));
3270 END IF;
3271 l_progress := '160';
3272
3273 -- Section 2: Crossdocking existing high level reservations
3274 -- For the current demand line, query to see if any existing high level reservations
3275 -- exist. If they do, we should try to detail those first.
3276 -- 2.1 - Query for and lock existing high level reservations for the demand line.
3277 -- - If a reservation cannot be locked, do not pick up the record for crossdocking.
3278 -- 2.2 - Check if the supply line on reservation is valid for crossdocking.
3279 -- - Supply source type must be allowed on the crossdock criteria.
3280 -- - Supply expected receipt time must lie within the crossdock time window.
3281 -- 2.3 - Lock the supply line record(s). Check that the UOM on the supply and
3282 -- reservation match if UOM integrity is Yes. If cross project allocation is not
3283 -- allowed and the org is PJM enabled, make sure the project and task values
3284 -- on the supply line matches the demand.
3285 -- 2.4 - Crossdock detail the reservation and update the demand and supply line records.
3286 -- 2.5 - After processing through all existing reservations, check the prior reservations
3287 -- only flag on the picking batch. If 'Y', we are done with the current demand line.
3288 -- 2.6 - If quantity still remains on the WDD to be crossdocked, see how much reservable
3289 -- quantity on the demand is actually available for crossdocking.
3290
3291 -- 2.1 - Query for and lock existing high level reservations for the demand line.
3292 -- - If a reservation cannot be locked, do not pick up the record for crossdocking.
3293 -- {{
3294 -- Test for WDD demand lines with existing high level non-inventory reservations.
3295 -- The possible supply source types for these reservations are:
3296 -- Purchase Order
3297 -- Internal Requisition
3298 -- ASN
3299 -- In Transit Shipment
3300 -- In Receiving }}
3301 -- {{
3302 -- Test where an existing reservation is already locked. This record should not be
3303 -- picked up for crossdocking. }}
3304 IF (l_debug = 1) THEN
3305 print_debug('2.1 - Query for existing high level reservations for the demand line');
3306 END IF;
3307 -- Initialize the table we are fetching records into.
3308 l_existing_rsvs_tb.DELETE;
3309 BEGIN
3310 OPEN existing_rsvs_cursor;
3311 FETCH existing_rsvs_cursor BULK COLLECT INTO l_existing_rsvs_tb;
3312 CLOSE existing_rsvs_cursor;
3313 EXCEPTION
3314 WHEN OTHERS THEN
3315 IF (l_debug = 1) THEN
3316 print_debug('2.1 - Exception retrieving the existing reservations');
3317 END IF;
3318 GOTO after_existing_rsvs;
3319 --RAISE fnd_api.g_exc_unexpected_error;
3320 END;
3321 l_progress := '170';
3322
3323 -- Loop through the existing reservations and try to crossdock them
3324 l_rsv_index := l_existing_rsvs_tb.FIRST;
3325 LOOP
3326 -- If no existing reservations were found, exit out of loop.
3327 IF (l_existing_rsvs_tb.COUNT = 0) THEN
3328 IF (l_debug = 1) THEN
3329 print_debug('2.1 - No existing reservations to crossdock');
3330 END IF;
3331 EXIT;
3332 END IF;
3333
3334 -- Retrieve necessary parameters for the supply line from the current reservation
3335 l_rsv_id := l_existing_rsvs_tb(l_rsv_index).reservation_id;
3336 l_rsv_qty := l_existing_rsvs_tb(l_rsv_index).reservation_quantity;
3337 l_rsv_uom_code := l_existing_rsvs_tb(l_rsv_index).reservation_uom_code;
3338 l_rsv_qty2 := l_existing_rsvs_tb(l_rsv_index).secondary_reservation_quantity;
3339 l_rsv_uom_code2 := l_existing_rsvs_tb(l_rsv_index).secondary_uom_code;
3340 l_rsv_prim_qty := l_existing_rsvs_tb(l_rsv_index).primary_reservation_quantity;
3341 l_rsv_prim_uom_code := l_existing_rsvs_tb(l_rsv_index).primary_uom_code;
3342 l_supply_type_id := l_existing_rsvs_tb(l_rsv_index).supply_source_type_id;
3343 l_supply_header_id := l_existing_rsvs_tb(l_rsv_index).supply_source_header_id;
3344 l_supply_line_id := l_existing_rsvs_tb(l_rsv_index).supply_source_line_id;
3345 l_supply_line_detail_id := l_existing_rsvs_tb(l_rsv_index).supply_source_line_detail;
3346 IF (l_debug = 1) THEN
3347 print_debug('2.1 - Reservation ID: ========> ' || l_rsv_id);
3348 print_debug('2.1 - Reservation Quantity: ==> ' || l_rsv_qty || ' ' ||
3349 l_rsv_uom_code);
3350 print_debug('2.1 - Reservation Quantity2: => ' || l_rsv_qty2 || ' ' ||
3351 l_rsv_uom_code2);
3352 print_debug('2.1 - Reservation Prim Qty: ==> ' || l_rsv_prim_qty || ' ' ||
3353 l_rsv_prim_uom_code);
3354 print_debug('2.1 - Supply source type ID: => ' || l_supply_type_id);
3355 print_debug('2.1 - Supply header ID: ======> ' || l_supply_header_id);
3356 print_debug('2.1 - Supply line ID: ========> ' || l_supply_line_id);
3357 print_debug('2.1 - Supply line detail ID: => ' || l_supply_line_detail_id);
3358 END IF;
3359 l_progress := '180';
3360
3361 -- Make sure the primary UOM code on the reservation matches the one for the item.
3362 -- This error condition should not come about but if it does, just skip this
3363 -- reservation and go to the next one.
3364 IF (l_primary_uom_code <> l_rsv_prim_uom_code) THEN
3365 IF (l_debug = 1) THEN
3366 print_debug('2.1 - Item and reservation primary UOM codes do not match!');
3367 END IF;
3368 GOTO next_reservation;
3369 END IF;
3370 l_progress := '190';
3371
3372 -- 2.2 - Check if the supply line on reservation is valid for crossdocking.
3373 -- - Supply source type must be allowed on the crossdock criteria.
3374 -- - Supply expected receipt time must lie within the crossdock time window.
3375 -- Valid supplies:
3376 -- 1 - Purchase Order
3377 -- 7 - Internal Requisition
3378 -- 25 - ASN
3379 -- 26 - In Transit Shipment
3380 -- 27 - In Receiving
3381 IF (l_debug = 1) THEN
3382 print_debug('2.2 - Check if the supply line on reservation is valid for crossdocking');
3383 END IF;
3384
3385 -- Set the appropriate Crossdock Planned Supply source code. This uses a different
3386 -- set of lookup values compared to the reservations supply source codes.
3387 IF (l_supply_type_id = 1) THEN
3388 -- PO
3389 l_supply_src_code := G_PLAN_SUP_PO_APPR;
3390 ELSIF (l_supply_type_id = 7) THEN
3391 -- Internal Requisition
3392 l_supply_src_code := G_PLAN_SUP_REQ;
3393 ELSIF (l_supply_type_id = 25) THEN
3394 -- ASN
3395 l_supply_src_code := G_PLAN_SUP_ASN;
3396 ELSIF (l_supply_type_id = 26) THEN
3397 -- In Transit Shipment
3398 l_supply_src_code := G_PLAN_SUP_INTR;
3399 ELSIF (l_supply_type_id = 27) THEN
3400 -- In Receiving
3401 l_supply_src_code := G_PLAN_SUP_RCV;
3402 ELSE
3403 -- Invalid supply for crossdocking.
3404 -- {{
3405 -- For prior existing reservations that are not supported for crossdocking (WIP),
3406 -- make sure we do not try to crossdock them. }}
3407 GOTO next_reservation;
3408 END IF;
3409 IF (l_debug = 1) THEN
3410 print_debug('2.2 - Crossdock Supply Source Code: => ' || l_supply_src_code);
3411 END IF;
3412 l_progress := '200';
3413
3414 -- Supply source type must be allowed on the crossdock criteria.
3415 -- Check if the supply line tied to the reservation is valid for crossdocking
3416 -- based on the valid supply types allowed for the crossdock criteria.
3417 -- {{
3418 -- Test for existing reservations for valid supply types to crossdock which are
3419 -- not allowed on the crossdock criteria. Processing should stop and the next
3420 -- existing reservation should be considered for crossdocking. }}
3421 IF (NOT WMS_XDOCK_UTILS_PVT.Is_Eligible_Supply_Source
3422 (p_criterion_id => l_crossdock_criteria_id,
3423 p_source_code => l_supply_src_code)) THEN
3424 -- Supply line on reservation is not valid source for crossdocking
3425 IF (l_debug = 1) THEN
3426 print_debug('2.2 - Supply line on reservation is not valid source for crossdocking');
3427 END IF;
3428 GOTO next_reservation;
3429 END IF;
3430 l_progress := '210';
3431
3432 -- Supply expected receipt time must lie within the crossdock time window.
3433 -- Check if the supply line tied to the reservation is valid for crossdocking
3434 -- based on the crossdock window for the crossdock criteria.
3435 IF (l_debug = 1) THEN
3436 print_debug('2.2 - Determine the expected receipt time for the supply line');
3437 END IF;
3438 IF (l_supply_type_id <> 27) THEN
3439 -- For supply types that are not In Receiving, call the Get_Expected_Time
3440 -- API to determine the expected receipt time
3441 Get_Expected_Time
3442 (p_source_type_id => l_supply_type_id,
3443 p_source_header_id => l_supply_header_id,
3444 p_source_line_id => l_supply_line_id,
3445 p_source_line_detail_id => l_supply_line_detail_id,
3446 p_supply_or_demand => G_SRC_TYPE_SUP,
3447 p_crossdock_criterion_id => l_crossdock_criteria_id,
3448 x_return_status => x_return_status,
3449 x_msg_count => x_msg_count,
3450 x_msg_data => x_msg_data,
3451 x_dock_start_time => l_dock_start_time,
3452 x_dock_mean_time => l_dock_mean_time,
3453 x_dock_end_time => l_dock_end_time,
3454 x_expected_time => l_supply_expected_time);
3455
3456 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
3457 IF (l_debug = 1) THEN
3458 print_debug('2.2 - Success returned from Get_Expected_Time API');
3459 END IF;
3460 ELSE
3461 IF (l_debug = 1) THEN
3462 print_debug('2.2 - Failure returned from Get_Expected_Time API');
3463 END IF;
3464 GOTO next_reservation;
3465 --RAISE fnd_api.g_exc_error;
3466 END IF;
3467 -- Use this value to determine if a dock appointment for the supply line exists.
3468 -- There is a parameter on the crossdock criteria to decide if we should schedule
3469 -- supply anytime on the expected receipt date if no dock appointment exists.
3470 IF (l_dock_start_time IS NOT NULL) THEN
3471 l_supply_dock_exists := TRUE;
3472 ELSE
3473 l_supply_dock_exists := FALSE;
3474 END IF;
3475 ELSE
3476 -- In Receiving supply will just use SYSDATE as the expected receipt time
3477 l_supply_expected_time := SYSDATE;
3478 -- For In Receiving, dock appointments do not apply since the material is already
3479 -- received. However, set this variable to be TRUE so that the expected receipt time
3480 -- for the supply is not rescheduled for anytime on the expected receipt date.
3481 l_supply_dock_exists := TRUE;
3482 END IF;
3483 -- Do not crossdock the supply line on the reservation if an expected receipt
3484 -- time cannot be determined.
3485 -- {{
3486 -- If an expected receipt time for the supply line on an existing reservation
3487 -- cannot be determined, skip processing and move on to the next existing reservation. }}
3488 IF (l_supply_expected_time IS NULL) THEN
3489 IF (l_debug = 1) THEN
3490 print_debug('2.2 - Unable to crossdock reservation since supply expected time is NULL');
3491 END IF;
3492 GOTO next_reservation;
3493 END IF;
3494 IF (l_debug = 1) THEN
3495 print_debug('2.2 - Supply expected time: => ' ||
3496 TO_CHAR(l_supply_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
3497 END IF;
3498 l_progress := '220';
3499
3500 -- See if the supply lies within the crossdock time window.
3501 -- If a dock appointment for the supply does not exist and the crossdock criteria
3502 -- allows rescheduling of the supply for anytime on the expected receipt date, set the
3503 -- appropriate logic to determine if the supply is valid.
3504 -- {{
3505 -- Test for a supply line on an existing reservation that does not have a dock appointment
3506 -- and supply reschedule is allowed. }}
3507 -- {{
3508 -- Test for a supply line on an existing reservation lying within the crossdock window. }}
3509 -- {{
3510 -- Test for a supply line on an existing reservation not lying within the crossdock
3511 -- window. In this case, we cannot crossdock the existing reservation so just move
3512 -- on to the next one. }}
3513 IF ((NOT l_supply_dock_exists AND
3514 g_crossdock_criteria_tb(l_crossdock_criteria_id).allow_supply_reschedule_flag = 1 AND
3515 l_supply_expected_time BETWEEN TRUNC(l_xdock_start_time) AND
3516 TO_DATE(TO_CHAR(TRUNC(l_xdock_end_time), 'DD-MON-YYYY') ||
3517 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
3518 OR (l_supply_expected_time BETWEEN l_xdock_start_time AND l_xdock_end_time)) THEN
3519 -- Supply is valid for crossdocking based on crossdock time window
3520 IF (l_debug = 1) THEN
3521 print_debug('2.2 - Supply line is within the crossdock window');
3522 END IF;
3523 ELSE
3524 -- Supply is not valid for crossdocking so skip to the next existing
3525 -- reservation to crossdock
3526 IF (l_debug = 1) THEN
3527 print_debug('2.2 - Supply line is not within the crossdock window');
3528 END IF;
3529 GOTO next_reservation;
3530 END IF;
3531 l_progress := '230';
3532
3533 -- 2.3 - Lock the supply line record(s). Check that the UOM on the supply and
3534 -- reservation match if UOM integrity is Yes. If cross project allocation is not
3535 -- allowed and the org is PJM enabled, make sure the project and task values
3536 -- on the supply line matches the demand.
3537
3538 -- Based on the UOM integrity flag, decide if we should pick up the supply line record(s)
3539 -- only if the UOM matches the one on the reservation.
3540 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).uom_integrity_flag = 1) THEN
3541 l_supply_uom_code := l_existing_rsvs_tb(l_rsv_index).reservation_uom_code;
3542 ELSE
3543 l_supply_uom_code := NULL;
3544 END IF;
3545 IF (l_debug = 1) THEN
3546 print_debug('2.3 - UOM code the supply line should match to: ' || l_supply_uom_code);
3547 END IF;
3548
3549 -- The cursors to lock the supply lines take a UOM code as input to deal with UOM integrity.
3550 -- {{
3551 -- Test a crossdock criteria where UOM integrity is 'Y'. The UOM on the reservation
3552 -- and supply line must match. Test both cases where it does and does not match. If it
3553 -- doesn't match, then we should stop processing and move on to the next reservation. }}
3554 -- {{
3555 -- Test for a PJM org where cross project allocation is not allowed. For an existing
3556 -- reservation, if the demand and supply lines have different project and task values, the
3557 -- reservation should not be crossdocked. Test this for all types of supply lines.}}
3558 -- {{
3559 -- Test for a PJM org where cross project allocation is not allowed. For an existing
3560 -- reservation, if the supply line has multiple project/task values on the distribution
3561 -- level (PO, ASN, Int Req), the reservation should not be crossdocked.}}
3562 -- {{
3563 -- Test for a PJM org where cross project allocation is not allowed. For an existing
3564 -- reservation with a supply of type Intransit Shipment, the reservation should be skipped
3565 -- and not crossdocked.}}
3566 IF (l_debug = 1) THEN
3567 print_debug('2.3 - Lock and validate the supply line record(s): ' || l_supply_type_id);
3568 END IF;
3569 IF (l_supply_type_id = 1) THEN
3570 -- PO
3571 BEGIN
3572 OPEN lock_po_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
3573 FETCH lock_po_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
3574 IF (lock_po_record%NOTFOUND) THEN
3575 -- If a record is not found, do not error out. This could mean that the
3576 -- UOM on the supply did not match the reservation and UOM integrity is 'Y'.
3577 -- This could also mean that the project and task on the supply line did not
3578 -- match the demand and the org is PJM enabled and cross project allocation is
3579 -- not allowed. Skip this reservation and try to crossdock the next one.
3580 IF (l_debug = 1) THEN
3581 print_debug('2.3 - Supply record not found. UOM/project/task values do not match');
3582 END IF;
3583 CLOSE lock_po_record;
3584 GOTO next_reservation;
3585 END IF;
3586 CLOSE lock_po_record;
3587 EXCEPTION
3588 WHEN OTHERS THEN
3589 IF (l_debug = 1) THEN
3590 print_debug('2.3 - Could not lock the PO supply line record');
3591 END IF;
3592 -- If we cannot lock the supply line, do not error out. Just go to the
3593 -- next existing reservation and try to crossdock that.
3594 GOTO next_reservation;
3595 END;
3596 ELSIF (l_supply_type_id = 7) THEN
3597 -- Internal Requisition
3598 BEGIN
3599 OPEN lock_intreq_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
3600 -- Multiple records could be returned from this cursor. We only care about existence.
3601 FETCH lock_intreq_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
3602 IF (lock_intreq_record%NOTFOUND) THEN
3603 -- If a record is not found, do not error out. This could mean that the
3604 -- UOM on the supply did not match the reservation and UOM integrity is 'Y'.
3605 -- This could also mean that the project and task on the supply line did not
3606 -- match the demand and the org is PJM enabled and cross project allocation is
3607 -- not allowed. Skip this reservation and try to crossdock the next one.
3608 IF (l_debug = 1) THEN
3609 print_debug('2.3 - Supply record not found. UOM/project/task values do not match');
3610 END IF;
3611 CLOSE lock_intreq_record;
3612 GOTO next_reservation;
3613 END IF;
3614 CLOSE lock_intreq_record;
3615 EXCEPTION
3616 WHEN OTHERS THEN
3617 IF (l_debug = 1) THEN
3618 print_debug('2.3 - Could not lock the Internal Req supply line record');
3619 END IF;
3620 -- If we cannot lock the supply line, do not error out. Just go to the
3621 -- next existing reservation and try to crossdock that.
3622 GOTO next_reservation;
3623 END;
3624 ELSIF (l_supply_type_id = 25) THEN
3625 -- ASN
3626 BEGIN
3627 OPEN lock_asn_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
3628 FETCH lock_asn_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
3629 IF (lock_asn_record%NOTFOUND) THEN
3630 -- If a record is not found, do not error out. This could mean that the
3631 -- UOM on the supply did not match the reservation and UOM integrity is 'Y'.
3632 -- This could also mean that the project and task on the supply line did not
3633 -- match the demand and the org is PJM enabled and cross project allocation is
3634 -- not allowed. Skip this reservation and try to crossdock the next one.
3635 IF (l_debug = 1) THEN
3636 print_debug('2.3 - Supply record not found. UOM/project/task values do not match');
3637 END IF;
3638 CLOSE lock_asn_record;
3639 GOTO next_reservation;
3640 END IF;
3641 CLOSE lock_asn_record;
3642 EXCEPTION
3643 WHEN OTHERS THEN
3644 IF (l_debug = 1) THEN
3645 print_debug('2.3 - Could not lock the ASN supply line record');
3646 END IF;
3647 -- If we cannot lock the supply line, do not error out. Just go to the
3648 -- next existing reservation and try to crossdock that.
3649 GOTO next_reservation;
3650 END;
3651 ELSIF (l_supply_type_id = 26) THEN
3652 -- In Transit Shipment
3653 BEGIN
3654 OPEN lock_intship_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
3655 FETCH lock_intship_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
3656 IF (lock_intship_record%NOTFOUND) THEN
3657 -- If a record is not found, do not error out. This could mean that the
3658 -- UOM on the supply did not match the reservation and UOM integrity is 'Y'.
3659 -- This could also mean that the org is PJM enabled, cross project allocation
3660 -- is not allowed, and the demand project/task is not null. In Transit Shipments
3661 -- going to a PJM org will only be allowed for common stock (NULL) project/task.
3662 -- Skip this reservation and try to crossdock the next one.
3663 IF (l_debug = 1) THEN
3664 print_debug('2.3 - Supply record not found. UOM/project/task values do not match');
3665 END IF;
3666 CLOSE lock_intship_record;
3667 GOTO next_reservation;
3668 END IF;
3669 CLOSE lock_intship_record;
3670 EXCEPTION
3671 WHEN OTHERS THEN
3672 IF (l_debug = 1) THEN
3673 print_debug('2.3 - Could not lock the In Transit Shipment supply line record');
3674 END IF;
3675 -- If we cannot lock the supply line, do not error out. Just go to the
3676 -- next existing reservation and try to crossdock that.
3677 GOTO next_reservation;
3678 END;
3679 ELSIF (l_supply_type_id = 27) THEN
3680 -- In Receiving
3681 -- Initialize the table we are fetching records into.
3682 l_rcv_lines_tb.DELETE;
3683 BEGIN
3684 OPEN lock_receiving_lines(l_supply_uom_code, l_rsv_prim_qty,
3685 l_demand_project_id, l_demand_task_id);
3686 FETCH lock_receiving_lines BULK COLLECT INTO l_rcv_lines_tb;
3687 -- If no valid receiving lines are found, do not error out. Skip this
3688 -- reservation and try to crossdock the next one. This means that there were no
3689 -- valid MOLs found that matched either the UOM (if UOM integrity is 'Y') or the
3690 -- project/task (if cross project allocation is not allowed for a PJM org).
3691 IF (l_rcv_lines_tb.COUNT = 0) THEN
3692 IF (l_debug = 1) THEN
3693 print_debug('2.3 - No valid receiving supply lines found');
3694 END IF;
3695 CLOSE lock_receiving_lines;
3696 GOTO next_reservation;
3697 END IF;
3698 CLOSE lock_receiving_lines;
3699 EXCEPTION
3700 WHEN OTHERS THEN
3701 IF (l_debug = 1) THEN
3702 print_debug('2.3 - Could not lock the Receiving supply line records');
3703 END IF;
3704 -- If we cannot lock the supply lines, do not error out. Just go to the
3705 -- next existing reservation and try to crossdock that.
3706 GOTO next_reservation;
3707 END;
3708 ELSE
3709 -- Invalid supply for crossdocking.
3710 GOTO next_reservation;
3711 END IF; -- End locking supply line(s) from different source types
3712 IF (l_debug = 1) THEN
3713 print_debug('2.3 - Successfully locked and validated the supply line record(s)');
3714 print_debug('2.3 - Supply UOM Code: ===> ' || l_supply_uom_code);
3715 print_debug('2.3 - Supply Project ID: => ' || l_supply_project_id);
3716 print_debug('2.3 - Supply Task ID: ====> ' || l_supply_task_id);
3717 END IF;
3718 l_progress := '240';
3719
3720 -- 2.4 - Crossdock detail the reservation and update the demand and supply line records.
3721 IF (l_debug = 1) THEN
3722 print_debug('2.4 - Crossdock detail the relevant records: RSV, WDD, supply');
3723 END IF;
3724 l_supply_index := NVL(l_rcv_lines_tb.FIRST, 1);
3725
3726 -- Loop through the valid supply lines to fulfill the existing reservation.
3727 -- For non-receiving supply types, there will only be one such supply line to use.
3728 -- For Receiving supply type, there is at least one valid MOL to fulfill the reservation.
3729 -- {{
3730 -- For supply line(s) of In Receiving type, test that the MOL's are looped through
3731 -- properly until they are all exhausted, reservation is fulfilled, or WDD quantity is
3732 -- is completely fulfilled. }}
3733 LOOP
3734 -- Define a savepoint so if an exception occurs while updating database records such as
3735 -- WDD, RSV, or MOL, we need to rollback the changes and goto the next WDD record
3736 -- to crossdock. Put this inside the supply lines loop so if one supply line
3737 -- is crossdocked successfully but another one errors out, we can still crossdock
3738 -- the first one. Multiple supply lines are only possible for Receiving supply type.
3739 SAVEPOINT Existing_Reservation_sp;
3740
3741 -- Initialize the variables to store the original WDD values in case
3742 -- we need to rollback the changes to local PLSQL data structures
3743 l_split_wdd_index := NULL;
3744 l_split_delivery_index := NULL;
3745 l_orig_wdd_values_rec := NULL;
3746 l_xdocked_wdd_index := NULL;
3747
3748 -- Set the supply UOM code to the UOM of the current MOL for receiving supply type.
3749 -- For non-receiving supply types, there is only one line and the supply UOM code
3750 -- has already been retrieved when locking the supply line record.
3751 IF (l_supply_type_id = 27) THEN
3752 l_mol_header_id := l_rcv_lines_tb(l_supply_index).header_id;
3753 l_mol_line_id := l_rcv_lines_tb(l_supply_index).line_id;
3754 l_mol_qty := l_rcv_lines_tb(l_supply_index).quantity;
3755 l_supply_uom_code := l_rcv_lines_tb(l_supply_index).uom_code;
3756 l_mol_prim_qty := l_rcv_lines_tb(l_supply_index).primary_quantity;
3757 l_mol_qty2 := l_rcv_lines_tb(l_supply_index).secondary_quantity;
3758 l_mol_uom_code2 := l_rcv_lines_tb(l_supply_index).secondary_uom_code;
3759 l_supply_project_id := l_rcv_lines_tb(l_supply_index).project_id;
3760 l_supply_task_id := l_rcv_lines_tb(l_supply_index).task_id;
3761 l_mol_lpn_id := l_rcv_lines_tb(l_supply_index).lpn_id;
3762 ELSE
3763 l_mol_line_id := NULL;
3764 END IF;
3765 l_progress := '250';
3766
3767 -- Convert the WDD qty to the UOM on the supply line.
3768 IF (l_debug = 1) THEN
3769 print_debug('2.4 - Current supply UOM code to convert to: ' || l_supply_uom_code);
3770 END IF;
3771 -- Retrieve the conversion rate for the item/from UOM/to UOM combination.
3772 -- {{
3773 -- Test that the WDD quantity is converted properly to the UOM on the supply line. }}
3774 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
3775 l_demand_uom_code, l_supply_uom_code);
3776 IF (l_conversion_rate < 0) THEN
3777 IF (l_debug = 1) THEN
3778 print_debug('2.4 - Error while obtaining UOM conversion rate for WDD qty');
3779 END IF;
3780 -- Rollback any db changes that might have occurred (currently none).
3781 ROLLBACK TO Existing_Reservation_sp;
3782 -- Process the next existing reservation record.
3783 GOTO next_reservation;
3784 END IF;
3785 -- Round the converted quantity to the standard precision
3786 l_wdd_txn_qty := ROUND(l_conversion_rate * l_demand_qty, l_conversion_precision);
3787 IF (l_debug = 1) THEN
3788 print_debug('2.4 - WDD qty: =====> ' || l_demand_qty || ' ' || l_demand_uom_code);
3789 print_debug('2.4 - WDD txn qty: => ' || l_wdd_txn_qty || ' ' || l_supply_uom_code);
3790 END IF;
3791 l_progress := '260';
3792
3793 -- Convert the RSV qty to the UOM on the supply line.
3794 -- Retrieve the conversion rate for the item/from UOM/to UOM combination.
3795 -- {{
3796 -- Test that the RSV quantity is converted properly to the UOM on the supply line. }}
3797 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
3798 l_rsv_uom_code, l_supply_uom_code);
3799 IF (l_conversion_rate < 0) THEN
3800 IF (l_debug = 1) THEN
3801 print_debug('2.4 - Error while obtaining UOM conversion rate for RSV qty');
3802 END IF;
3803 -- Rollback any db changes that might have occurred (currently none).
3804 ROLLBACK TO Existing_Reservation_sp;
3805 -- Process the next existing reservation record.
3806 GOTO next_reservation;
3807 END IF;
3808 -- Round the converted quantity to the standard precision
3809 l_rsv_txn_qty := ROUND(l_conversion_rate * l_rsv_qty, l_conversion_precision);
3810 IF (l_debug = 1) THEN
3811 print_debug('2.4 - RSV qty: =====> ' || l_rsv_qty || ' ' || l_rsv_uom_code);
3812 print_debug('2.4 - RSV txn qty: => ' || l_rsv_txn_qty || ' ' || l_supply_uom_code);
3813 END IF;
3814 l_progress := '270';
3815
3816 -- For receiving supply types, multiple MOL's comprise the supply line source.
3817 IF (l_supply_type_id = 27) THEN
3818 IF (l_debug = 1) THEN
3819 print_debug('2.4 - MOL qty: =====> ' || l_mol_qty || ' ' || l_supply_uom_code);
3820 END IF;
3821 ELSE
3822 -- For non-receiving supply types, just set this to be equal to the RSV txn qty.
3823 -- We assume that there is more than enough quantity on the supply to fulfill
3824 -- the reservation otherwise it should not have been created. This variable is
3825 -- set here for calculating the ATD qty.
3826 l_mol_qty := l_rsv_txn_qty;
3827 END IF;
3828
3829 -- Calculate the Available to Detail quantity.
3830 -- {{
3831 -- Test that the available to detail quantity is calculated properly,
3832 -- i.e. is lower than WDD, RSV, and MOL qty, and is an integer value if
3833 -- UOM integrity = 'Y'. }}
3834 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).uom_integrity_flag = 1) THEN
3835 -- UOM Integrity is 'Yes'
3836 l_atd_qty := LEAST(FLOOR(l_wdd_txn_qty), FLOOR(l_rsv_txn_qty), FLOOR(l_mol_qty));
3837 ELSE
3838 -- UOM Integrity is 'No'
3839 l_atd_qty := LEAST(l_wdd_txn_qty, l_rsv_txn_qty, l_mol_qty);
3840 END IF;
3841 IF (l_debug = 1) THEN
3842 print_debug('2.4 - Available to detail qty: ' || l_atd_qty || ' ' ||
3843 l_supply_uom_code);
3844 END IF;
3845 -- If the ATD qty is 0, then goto the next reservation to crossdock.
3846 -- This is possible if the UOM integrity flag is 'Y' and the resultant quantities
3847 -- were floored to 0.
3848 -- {{
3849 -- Test for ATD qty = 0. This can come about if UOM integrity is Yes and the
3850 -- demand, reservation or supply line gets floored to 0. }}
3851 IF (l_atd_qty = 0) THEN
3852 IF (l_debug = 1) THEN
3853 print_debug('2.4 - No available qty to detail for this reservation');
3854 END IF;
3855 -- Rollback any db changes that might have occurred (currently none).
3856 ROLLBACK TO Existing_Reservation_sp;
3857 -- Process the next existing reservation record.
3858 GOTO next_reservation;
3859 END IF;
3860 l_progress := '280';
3861
3862 -- Convert l_atd_qty to the primary UOM
3863 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
3864 l_supply_uom_code, l_primary_uom_code);
3865 IF (l_conversion_rate < 0) THEN
3866 IF (l_debug = 1) THEN
3867 print_debug('2.4 - Error while obtaining primary UOM conversion rate for ATD qty');
3868 END IF;
3869 -- Rollback any db changes that might have occurred (currently none).
3870 ROLLBACK TO Existing_Reservation_sp;
3871 -- Process the next existing reservation record.
3872 GOTO next_reservation;
3873 END IF;
3874 -- Round the converted quantity to the standard precision
3875 l_atd_prim_qty := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
3876 IF (l_debug = 1) THEN
3877 print_debug('2.4 - ATD qty in primary UOM: => ' || l_atd_prim_qty || ' ' ||
3878 l_primary_uom_code);
3879 END IF;
3880 l_progress := '290';
3881
3882 -- Store the original WDD values in case of rollback where we need
3883 -- to clean up the local PLSQL data structures
3884 l_orig_wdd_values_rec.requested_quantity :=
3885 p_wsh_release_table(l_wdd_index).requested_quantity;
3886 l_orig_wdd_values_rec.requested_quantity2 :=
3887 p_wsh_release_table(l_wdd_index).requested_quantity2;
3888 l_orig_wdd_values_rec.released_status :=
3889 p_wsh_release_table(l_wdd_index).released_status;
3890 l_orig_wdd_values_rec.move_order_line_id :=
3891 p_wsh_release_table(l_wdd_index).move_order_line_id;
3892
3893 -- Crossdock the WDD record, splitting it if necessary.
3894 IF (l_debug = 1) THEN
3895 print_debug('2.4 - Call the Crossdock_WDD API to crossdock/split the WDD');
3896 END IF;
3897 Crossdock_WDD
3898 (p_log_prefix => '2.4 - ',
3899 p_crossdock_type => G_CRT_TYPE_PLAN,
3900 p_batch_id => p_batch_id,
3901 p_wsh_release_table => p_wsh_release_table,
3902 p_trolin_delivery_ids => p_trolin_delivery_ids,
3903 p_del_detail_id => p_del_detail_id,
3904 l_wdd_index => l_wdd_index,
3905 l_debug => l_debug,
3906 l_inventory_item_id => l_inventory_item_id,
3907 l_wdd_txn_qty => l_wdd_txn_qty,
3908 l_atd_qty => l_atd_qty,
3909 l_atd_wdd_qty => l_atd_wdd_qty,
3910 l_atd_wdd_qty2 => l_atd_wdd_qty2,
3911 l_supply_uom_code => l_supply_uom_code,
3912 l_demand_uom_code => l_demand_uom_code,
3913 l_demand_uom_code2 => l_demand_uom_code2,
3914 l_conversion_rate => l_conversion_rate,
3915 l_conversion_precision => l_conversion_precision,
3916 l_demand_line_detail_id => l_demand_line_detail_id,
3917 l_index => l_index,
3918 l_detail_id_tab => l_detail_id_tab,
3919 l_action_prms => l_action_prms,
3920 l_action_out_rec => l_action_out_rec,
3921 l_split_wdd_id => l_split_wdd_id,
3922 l_detail_info_tab => l_detail_info_tab,
3923 l_in_rec => l_in_rec,
3924 l_out_rec => l_out_rec,
3925 l_mol_line_id => l_mol_line_id,
3926 l_split_wdd_index => l_split_wdd_index,
3927 l_split_delivery_index => l_split_delivery_index,
3928 l_split_wdd_rel_rec => l_split_wdd_rel_rec,
3929 l_allocation_method => l_allocation_method,
3930 l_demand_qty => l_demand_qty,
3931 l_demand_qty2 => l_demand_qty2,
3932 l_demand_atr_qty => l_demand_atr_qty,
3933 l_xdocked_wdd_index => l_xdocked_wdd_index,
3934 l_supply_type_id => l_supply_type_id,
3935 x_return_status => x_return_status,
3936 x_msg_count => x_msg_count,
3937 x_msg_data => x_msg_data,
3938 x_error_code => l_error_code
3939 );
3940
3941 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
3942 IF (l_debug = 1) THEN
3943 print_debug('2.4 - Error returned from Crossdock_WDD API: '
3944 || x_return_status);
3945 END IF;
3946 --RAISE fnd_api.g_exc_error;
3947 -- If an exception occurs while modifying a database record, rollback the changes
3948 -- and just go to the next WDD record or reservation to crossdock.
3949 ROLLBACK TO Existing_Reservation_sp;
3950 -- We need to also rollback changes done to local PLSQL data structures
3951 IF (l_split_wdd_index IS NOT NULL) THEN
3952 p_wsh_release_table.DELETE(l_split_wdd_index);
3953 END IF;
3954 IF (l_split_delivery_index IS NOT NULL) THEN
3955 p_del_detail_id.DELETE(l_split_delivery_index);
3956 p_trolin_delivery_ids.DELETE(l_split_delivery_index);
3957 END IF;
3958 IF (l_xdocked_wdd_index IS NOT NULL) THEN
3959 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
3960 END IF;
3961 p_wsh_release_table(l_wdd_index).requested_quantity :=
3962 l_orig_wdd_values_rec.requested_quantity;
3963 p_wsh_release_table(l_wdd_index).requested_quantity2 :=
3964 l_orig_wdd_values_rec.requested_quantity2;
3965 p_wsh_release_table(l_wdd_index).released_status :=
3966 l_orig_wdd_values_rec.released_status;
3967 p_wsh_release_table(l_wdd_index).move_order_line_id :=
3968 l_orig_wdd_values_rec.move_order_line_id;
3969
3970 -- Skip to the next WDD record or reservation to crossdock
3971 IF (l_error_code = 'UOM') THEN
3972 GOTO next_reservation;
3973 ELSE -- l_error_code = 'DB'
3974 GOTO next_record;
3975 END IF;
3976 ELSE
3977 IF (l_debug = 1) THEN
3978 print_debug('2.4 - Successfully crossdocked/split the WDD record');
3979 END IF;
3980 END IF;
3981 l_progress := '300';
3982
3983
3984 -- Crossdock the RSV record, splitting it if necessary
3985 IF (l_debug = 1) THEN
3986 print_debug('2.4 - Call the Crossdock_RSV API to crossdock/split the RSV');
3987 END IF;
3988 Crossdock_RSV
3989 (p_log_prefix => '2.4 - ',
3990 p_crossdock_type => G_CRT_TYPE_PLAN,
3991 l_debug => l_debug,
3992 l_inventory_item_id => l_inventory_item_id,
3993 l_rsv_txn_qty => l_rsv_txn_qty,
3994 l_atd_qty => l_atd_qty,
3995 l_atd_rsv_qty => l_atd_rsv_qty,
3996 l_atd_rsv_qty2 => l_atd_rsv_qty2,
3997 l_atd_prim_qty => l_atd_prim_qty,
3998 l_supply_uom_code => l_supply_uom_code,
3999 l_rsv_uom_code => l_rsv_uom_code,
4000 l_rsv_uom_code2 => l_rsv_uom_code2,
4001 l_primary_uom_code => l_primary_uom_code,
4002 l_conversion_rate => l_conversion_rate,
4003 l_conversion_precision => l_conversion_precision,
4004 l_original_rsv_rec => l_original_rsv_rec,
4005 l_rsv_id => l_rsv_id,
4006 l_to_rsv_rec => l_to_rsv_rec,
4007 l_split_wdd_id => l_split_wdd_id,
4008 l_crossdock_criteria_id => l_crossdock_criteria_id,
4009 l_demand_expected_time => l_demand_expected_time,
4010 l_supply_expected_time => l_supply_expected_time,
4011 l_original_serial_number => l_original_serial_number,
4012 l_split_rsv_id => l_split_rsv_id,
4013 l_rsv_qty => l_rsv_qty,
4014 l_rsv_qty2 => l_rsv_qty2,
4015 l_to_serial_number => l_to_serial_number,
4016 l_supply_type_id => l_supply_type_id,
4017 x_return_status => x_return_status,
4018 x_msg_count => x_msg_count,
4019 x_msg_data => x_msg_data,
4020 x_error_code => l_error_code
4021 );
4022
4023 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
4024 IF (l_debug = 1) THEN
4025 print_debug('2.4 - Error returned from Crossdock_RSV API: '
4026 || x_return_status);
4027 END IF;
4028 --RAISE fnd_api.g_exc_error;
4029 -- If an exception occurs while modifying a database record, rollback the changes
4030 -- and just go to the next WDD record or reservation to crossdock.
4031 ROLLBACK TO Existing_Reservation_sp;
4032 -- We need to also rollback changes done to local PLSQL data structures
4033 IF (l_split_wdd_index IS NOT NULL) THEN
4034 p_wsh_release_table.DELETE(l_split_wdd_index);
4035 END IF;
4036 IF (l_split_delivery_index IS NOT NULL) THEN
4037 p_del_detail_id.DELETE(l_split_delivery_index);
4038 p_trolin_delivery_ids.DELETE(l_split_delivery_index);
4039 END IF;
4040 IF (l_xdocked_wdd_index IS NOT NULL) THEN
4041 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
4042 END IF;
4043 p_wsh_release_table(l_wdd_index).requested_quantity :=
4044 l_orig_wdd_values_rec.requested_quantity;
4045 p_wsh_release_table(l_wdd_index).requested_quantity2 :=
4046 l_orig_wdd_values_rec.requested_quantity2;
4047 p_wsh_release_table(l_wdd_index).released_status :=
4048 l_orig_wdd_values_rec.released_status;
4049 p_wsh_release_table(l_wdd_index).move_order_line_id :=
4050 l_orig_wdd_values_rec.move_order_line_id;
4051
4052 -- Skip to the next WDD record or reservation to crossdock
4053 IF (l_error_code = 'UOM') THEN
4054 GOTO next_reservation;
4055 ELSE -- l_error_code = 'DB'
4056 GOTO next_record;
4057 END IF;
4058 ELSE
4059 IF (l_debug = 1) THEN
4060 print_debug('2.4 - Successfully crossdocked/split the RSV record');
4061 END IF;
4062 END IF;
4063 l_progress := '310';
4064
4065
4066 -- Crossdock and split the MOL supply line if necessary
4067 IF (l_mol_line_id IS NOT NULL) THEN
4068 IF (l_debug = 1) THEN
4069 print_debug('2.4 - Call the Crossdock_MOL API to crossdock/split the MOL: '
4070 || l_mol_line_id);
4071 END IF;
4072 Crossdock_MOL
4073 (p_log_prefix => '2.4 - ',
4074 p_crossdock_type => G_CRT_TYPE_PLAN,
4075 l_debug => l_debug,
4076 l_inventory_item_id => l_inventory_item_id,
4077 l_mol_qty => l_mol_qty,
4078 l_mol_qty2 => l_mol_qty2,
4079 l_atd_qty => l_atd_qty,
4080 l_atd_mol_qty2 => l_atd_mol_qty2,
4081 l_supply_uom_code => l_supply_uom_code,
4082 l_mol_uom_code2 => l_mol_uom_code2,
4083 l_conversion_rate => l_conversion_rate,
4084 l_conversion_precision => l_conversion_precision,
4085 l_mol_prim_qty => l_mol_prim_qty,
4086 l_atd_prim_qty => l_atd_prim_qty,
4087 l_split_wdd_id => l_split_wdd_id,
4088 l_mol_header_id => l_mol_header_id,
4089 l_mol_line_id => l_mol_line_id,
4090 l_supply_atr_qty => l_supply_atr_qty,
4091 l_demand_type_id => l_demand_type_id,
4092 l_wip_entity_id => l_wip_entity_id,
4093 l_operation_seq_num => l_operation_seq_num,
4094 l_repetitive_schedule_id => l_repetitive_schedule_id,
4095 l_wip_supply_type => l_wip_supply_type,
4096 l_xdocked_wdd_index => l_xdocked_wdd_index,
4097 l_detail_info_tab => l_detail_info_tab,
4098 l_wdd_index => l_wdd_index,
4099 l_split_wdd_index => l_split_wdd_index,
4100 p_wsh_release_table => p_wsh_release_table,
4101 l_supply_type_id => l_supply_type_id,
4102 x_return_status => x_return_status,
4103 x_msg_count => x_msg_count,
4104 x_msg_data => x_msg_data,
4105 x_error_code => l_error_code
4106 );
4107
4108 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
4109 IF (l_debug = 1) THEN
4110 print_debug('2.4 - Error returned from Crossdock_MOL API: '
4111 || x_return_status);
4112 END IF;
4113 --RAISE fnd_api.g_exc_error;
4114 -- If an exception occurs while modifying a database record, rollback the changes
4115 -- and just go to the next WDD record or reservation to crossdock.
4116 ROLLBACK TO Existing_Reservation_sp;
4117 -- We need to also rollback changes done to local PLSQL data structures
4118 IF (l_split_wdd_index IS NOT NULL) THEN
4119 p_wsh_release_table.DELETE(l_split_wdd_index);
4120 END IF;
4121 IF (l_split_delivery_index IS NOT NULL) THEN
4122 p_del_detail_id.DELETE(l_split_delivery_index);
4123 p_trolin_delivery_ids.DELETE(l_split_delivery_index);
4124 END IF;
4125 IF (l_xdocked_wdd_index IS NOT NULL) THEN
4126 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
4127 END IF;
4128 p_wsh_release_table(l_wdd_index).requested_quantity :=
4129 l_orig_wdd_values_rec.requested_quantity;
4130 p_wsh_release_table(l_wdd_index).requested_quantity2 :=
4131 l_orig_wdd_values_rec.requested_quantity2;
4132 p_wsh_release_table(l_wdd_index).released_status :=
4133 l_orig_wdd_values_rec.released_status;
4134 p_wsh_release_table(l_wdd_index).move_order_line_id :=
4135 l_orig_wdd_values_rec.move_order_line_id;
4136
4137 -- Skip to the next WDD record or reservation to crossdock
4138 IF (l_error_code = 'UOM') THEN
4139 GOTO next_reservation;
4140 ELSE -- l_error_code = 'DB'
4141 GOTO next_record;
4142 END IF;
4143 ELSE
4144 IF (l_debug = 1) THEN
4145 print_debug('2.4 - Successfully crossdocked/split the MOL record');
4146 END IF;
4147 END IF;
4148
4149 -- Store this LPN in the crossdocked LPNs table so we can call the pre_generate
4150 -- API later on for the entire set of LPN's instead of once for each MOL that
4151 -- is crossdocked.
4152 IF (NOT l_crossdocked_lpns_tb.EXISTS(l_mol_lpn_id)) THEN
4153 l_crossdocked_lpns_tb(l_mol_lpn_id) := TRUE;
4154 IF (l_debug = 1) THEN
4155 print_debug('2.4 - Successfully stored the crossdocked LPN: ' || l_mol_lpn_id);
4156 END IF;
4157 END IF;
4158 l_progress := '320';
4159
4160 END IF; -- End of l_mol_line_id IS NOT NULL for receiving supply type
4161
4162
4163 -- Exit out of loop if the WDD line has been fully crossdocked or the
4164 -- reservation has been fully consumed
4165 IF (p_wsh_release_table(l_wdd_index).released_status = 'S' OR l_rsv_qty = 0) THEN
4166 EXIT;
4167 END IF;
4168
4169 -- Exit out of loop for non-receiving supply types.
4170 IF (l_supply_type_id <> 27) THEN
4171 EXIT;
4172 END IF;
4173
4174 -- Exit when all supply lines (receiving MOL's for this case) have been considered
4175 EXIT WHEN l_supply_index = l_rcv_lines_tb.LAST;
4176 l_supply_index := l_rcv_lines_tb.NEXT(l_supply_index);
4177 END LOOP; -- End looping through supply line(s)
4178 IF (l_supply_type_id = 27 AND l_rcv_lines_tb.COUNT > 0) THEN
4179 -- Clear the receiving lines table if the supply type is Receiving
4180 l_rcv_lines_tb.DELETE;
4181 END IF;
4182 l_progress := '330';
4183
4184 -- Exit out of existing reservations loop if the WDD line has been fully crossdocked.
4185 -- There is no need to consider anymore existing reservations.
4186 IF (p_wsh_release_table(l_wdd_index).released_status = 'S') THEN
4187 EXIT;
4188 END IF;
4189 -- {{
4190 -- Test for existing reservation cases where RSV qty >, =, < WDD qty. }}
4191
4192 <<next_reservation>>
4193 EXIT WHEN l_rsv_index = l_existing_rsvs_tb.LAST;
4194 l_rsv_index := l_existing_rsvs_tb.NEXT(l_rsv_index);
4195 END LOOP; -- End looping through existing reservations
4196 l_progress := '340';
4197
4198 -- 2.5 - After processing through all existing reservations, check the prior reservations
4199 -- only flag on the picking batch. If 'Y', we are done with the current demand line.
4200 -- {{
4201 -- Test for picking batch where we only want to allocate against existing reservations.
4202 -- If that is the case, stop crossdocking after trying to crossdock existing reservations. }}
4203 <<after_existing_rsvs>>
4204 IF (l_debug = 1) THEN
4205 print_debug('2.5 - Check the allocate against existing reservations only flag');
4206 print_debug('2.5 - Existing RSVs Only Flag: ==> ' || l_existing_rsvs_only);
4207 print_debug('2.5 - WDD line released status: => ' ||
4208 p_wsh_release_table(l_wdd_index).released_status);
4209 END IF;
4210 IF (l_existing_rsvs_only = 'Y' OR
4211 p_wsh_release_table(l_wdd_index).released_status = 'S') THEN
4212 GOTO next_record;
4213 END IF;
4214 l_progress := '350';
4215
4216 -- 2.6 - If quantity still remains on the WDD to be crossdocked, see how much reservable
4217 -- quantity on the demand is actually available for crossdocking.
4218 -- This API will return quantity in the primary UOM.
4219 IF (l_debug = 1) THEN
4220 print_debug('2.6 - Calculate the ATR qty on the demand line for crossdocking');
4221 END IF;
4222 INV_RESERVATION_AVAIL_PVT.Available_demand_to_reserve
4223 (p_api_version_number => 1.0,
4224 p_init_msg_lst => fnd_api.g_false,
4225 x_return_status => x_return_status,
4226 x_msg_count => x_msg_count,
4227 x_msg_data => x_msg_data,
4228 p_primary_uom_code => l_primary_uom_code,
4229 p_demand_source_type_id => l_demand_type_id,
4230 p_demand_source_header_id => l_demand_so_header_id,
4231 p_demand_source_line_id => l_demand_line_id,
4232 p_demand_source_line_detail => l_demand_line_detail_id,
4233 p_project_id => l_demand_project_id,
4234 p_task_id => l_demand_task_id,
4235 x_qty_available_to_reserve => l_demand_atr_prim_qty,
4236 x_qty_available => l_demand_available_qty);
4237
4238 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
4239 IF (l_debug = 1) THEN
4240 print_debug('2.6 - Error returned from available_demand_to_reserve API: '
4241 || x_return_status);
4242 END IF;
4243 GOTO next_record;
4244 --RAISE fnd_api.g_exc_error;
4245 END IF;
4246 IF (l_debug = 1) THEN
4247 print_debug('2.6 - Available qty to reserve (primary) for demand: ' ||
4248 l_demand_atr_prim_qty || ' ' || l_primary_uom_code);
4249 END IF;
4250 l_progress := '360';
4251
4252 -- Check how much quantity is available to be crossdocked.
4253 -- {{
4254 -- Test for case where the WDD line, after considering existing reservations, does not
4255 -- have any reservable quantity. This line cannot be crossdocked and we should move
4256 -- on to the next record. }}
4257 IF (l_demand_atr_prim_qty <= 0) THEN
4258 GOTO next_record;
4259 ELSE
4260 -- Convert the ATR primary quantity to the UOM on the WDD demand line
4261 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
4262 l_primary_uom_code, l_demand_uom_code);
4263 IF (l_conversion_rate < 0) THEN
4264 IF (l_debug = 1) THEN
4265 print_debug('2.6 - Error while obtaining Primary UOM conversion rate for WDD');
4266 END IF;
4267 GOTO next_record;
4268 END IF;
4269 -- Round the converted quantity to the standard precision
4270 l_demand_atr_qty := ROUND(l_conversion_rate * l_demand_atr_prim_qty, l_conversion_precision);
4271 IF (l_debug = 1) THEN
4272 print_debug('2.6 - Available qty to reserve for demand: ' || l_demand_atr_qty ||
4273 ' ' || l_demand_uom_code);
4274 END IF;
4275 l_progress := '370';
4276
4277 -- Instead of splitting the WDD record here with the ATR quantity, just keep track
4278 -- of that qty and use it later on when determining the available to detail qty.
4279 -- In this way, we can minimize the amount of WDD splitting, doing it only when
4280 -- absolutely necessary.
4281 END IF;
4282
4283 -- Section 3: Build the set of available supply lines for the demand
4284 -- 3.1 - Query and cache the available supply source types for crossdocking based on the
4285 -- current crossdock criteria.
4286 -- 3.2 - For each supply source type, retrieve the available supply lines.
4287 -- 3.3 - For each supply line retrieved, determine the expected receipt time.
4288 -- 3.4 - Insert the available supply lines into the global temp table.
4289 -- 3.5 - Retrieve all of the supply lines that fall within the crossdock window and
4290 -- store it in the shopping basket table. If prioritize documents, order this
4291 -- by the source type.
4292 -- 3.6 - Sort the supply lines in the shopping basket table based on the crossdocking
4293 -- goals.
4294
4295 -- 3.1 - Query and cache the available supply source types for crossdocking based on the
4296 -- current crossdock criteria.
4297 IF (l_debug = 1) THEN
4298 print_debug('3.1 - Query and cache the available supply source types for crossdocking');
4299 END IF;
4300 IF (NOT l_supply_src_types_tb.EXISTS(l_crossdock_criteria_id)) THEN
4301 BEGIN
4302 OPEN supply_src_types_cursor;
4303 FETCH supply_src_types_cursor BULK COLLECT INTO
4304 l_supply_src_types_tb(l_crossdock_criteria_id);
4305 CLOSE supply_src_types_cursor;
4306 EXCEPTION
4307 WHEN OTHERS THEN
4308 IF (l_debug = 1) THEN
4309 print_debug('3.1 - Exception retrieving the eligible supply source types');
4310 END IF;
4311 GOTO next_record;
4312 --RAISE fnd_api.g_exc_unexpected_error;
4313 END;
4314 IF (l_debug = 1) THEN
4315 print_debug('3.1 - Successfully retrieved the eligible supply source types for criteria: '
4316 || l_crossdock_criteria_id);
4317 END IF;
4318 END IF;
4319 l_progress := '380';
4320
4321 -- 3.2 - For each supply source type, retrieve the available supply lines.
4322 IF (l_debug = 1) THEN
4323 print_debug('3.2 - For each supply source type, retrieve the available supply lines');
4324 END IF;
4325
4326 -- Set a savepoint in case an error occurs while inserting supply line records
4327 -- into the global temp table.
4328 SAVEPOINT Supply_Lines_sp;
4329
4330 FOR i IN 1 .. l_supply_src_types_tb(l_crossdock_criteria_id).COUNT LOOP
4331 -- Store the current supply source code
4332 l_supply_src_code := l_supply_src_types_tb(l_crossdock_criteria_id)(i);
4333
4334 -- Retrieve the available supply lines for the current supply source type and item
4335 -- combination if it has not been done already. Here we do not care about project/task
4336 -- and will retrieve all of the valid supply lines for the org/item regardless of the
4337 -- project/task. Each demand line could have a different project/task to match to. That
4338 -- logic should be done in the get_supply_lines cursor when building the shopping cart
4339 -- table.
4340 -- {{
4341 -- Test to make sure that if a supply source type for a given item has already been
4342 -- retrieved, do not requery the information again. }}
4343 IF ((l_src_types_retrieved_tb.EXISTS(l_inventory_item_id) AND
4344 NOT l_src_types_retrieved_tb(l_inventory_item_id).EXISTS(l_supply_src_code)) OR
4345 NOT l_src_types_retrieved_tb.EXISTS(l_inventory_item_id)) THEN
4346
4347 IF (l_debug = 1) THEN
4348 IF (l_supply_src_code = G_PLAN_SUP_PO_APPR) THEN
4349 print_debug('3.2 - Supply source type to retrieve: Approved PO');
4350 ELSIF (l_supply_src_code = G_PLAN_SUP_ASN) THEN
4351 print_debug('3.2 - Supply source type to retrieve: ASN');
4352 ELSIF (l_supply_src_code = G_PLAN_SUP_REQ) THEN
4353 print_debug('3.2 - Supply source type to retrieve: Internal Requisition');
4354 ELSIF (l_supply_src_code = G_PLAN_SUP_INTR) THEN
4355 print_debug('3.2 - Supply source type to retrieve: In Transit Shipment');
4356 ELSIF (l_supply_src_code = G_PLAN_SUP_RCV) THEN
4357 print_debug('3.2 - Supply source type to retrieve: In Receiving');
4358 ELSE
4359 print_debug('3.2 - Supply source type to retrieve: INVALID SUPPLY!');
4360 END IF;
4361 END IF;
4362
4363 -- Initialize the tables we are BULK fetching into
4364 l_header_id_tb.DELETE;
4365 l_line_id_tb.DELETE;
4366 l_line_detail_id_tb.DELETE;
4367 l_dock_start_time_tb.DELETE;
4368 l_dock_mean_time_tb.DELETE;
4369 l_dock_end_time_tb.DELETE;
4370 l_expected_time_tb.DELETE;
4371 l_quantity_tb.DELETE;
4372 l_uom_code_tb.DELETE;
4373 l_primary_quantity_tb.DELETE;
4374 l_secondary_quantity_tb.DELETE;
4375 l_secondary_uom_code_tb.DELETE;
4376 l_project_id_tb.DELETE;
4377 l_task_id_tb.DELETE;
4378 l_lpn_id_tb.DELETE;
4379
4380 -- Bulk collect the supply line cursors into the PLSQL tables based on
4381 -- the current crossdock supply source type.
4382 IF (l_supply_src_code = G_PLAN_SUP_PO_APPR) THEN
4383 -- PO
4384 BEGIN
4385 OPEN po_approved_lines;
4386 FETCH po_approved_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
4387 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb, l_primary_quantity_tb,
4388 l_secondary_quantity_tb, l_secondary_uom_code_tb,
4389 l_project_id_tb, l_task_id_tb, l_lpn_id_tb;
4390 CLOSE po_approved_lines;
4391 EXCEPTION
4392 WHEN OTHERS THEN
4393 IF (l_debug = 1) THEN
4394 print_debug('3.2 - Could not retrieve the PO supply lines');
4395 END IF;
4396 -- If we cannot retrieve the available supply lines, do not error out.
4397 -- Just go to the next record and try to crossdock that.
4398 -- Rollback any db changes that might have occurred (currently none).
4399 ROLLBACK TO Supply_Lines_sp;
4400 GOTO next_record;
4401 END;
4402 l_supply_type_id := 1;
4403 ELSIF (l_supply_src_code = G_PLAN_SUP_ASN) THEN
4404 -- ASN
4405 BEGIN
4406 OPEN po_asn_lines;
4407 FETCH po_asn_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
4408 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb, l_primary_quantity_tb,
4409 l_secondary_quantity_tb, l_secondary_uom_code_tb,
4410 l_project_id_tb, l_task_id_tb, l_lpn_id_tb;
4411 CLOSE po_asn_lines;
4412 EXCEPTION
4413 WHEN OTHERS THEN
4414 IF (l_debug = 1) THEN
4415 print_debug('3.2 - Could not retrieve the ASN supply lines');
4416 END IF;
4417 -- If we cannot retrieve the available supply lines, do not error out.
4418 -- Just go to the next record and try to crossdock that.
4419 -- Rollback any db changes that might have occurred (currently none).
4420 ROLLBACK TO Supply_Lines_sp;
4421 GOTO next_record;
4422 END;
4423 l_supply_type_id := 25;
4424 ELSIF (l_supply_src_code = G_PLAN_SUP_REQ) THEN
4425 -- Internal Requisition
4426 BEGIN
4427 OPEN internal_req_lines;
4428 FETCH internal_req_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
4429 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb, l_primary_quantity_tb,
4430 l_secondary_quantity_tb, l_secondary_uom_code_tb,
4431 l_project_id_tb, l_task_id_tb, l_lpn_id_tb;
4432 CLOSE internal_req_lines;
4433 EXCEPTION
4434 WHEN OTHERS THEN
4435 IF (l_debug = 1) THEN
4436 print_debug('3.2 - Could not retrieve the Internal Req supply lines');
4437 END IF;
4438 -- If we cannot retrieve the available supply lines, do not error out.
4439 -- Just go to the next record and try to crossdock that.
4440 -- Rollback any db changes that might have occurred (currently none).
4441 ROLLBACK TO Supply_Lines_sp;
4442 GOTO next_record;
4443 END;
4444 l_supply_type_id := 7;
4445 ELSIF (l_supply_src_code = G_PLAN_SUP_INTR) THEN
4446 -- In Transit Shipment
4447 BEGIN
4448 OPEN intship_lines;
4449 FETCH intship_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
4450 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb, l_primary_quantity_tb,
4451 l_secondary_quantity_tb, l_secondary_uom_code_tb,
4452 l_project_id_tb, l_task_id_tb, l_lpn_id_tb;
4453 CLOSE intship_lines;
4454 EXCEPTION
4455 WHEN OTHERS THEN
4456 IF (l_debug = 1) THEN
4457 print_debug('3.2 - Could not retrieve the In Transit Shipment supply lines');
4458 END IF;
4459 -- If we cannot retrieve the available supply lines, do not error out.
4460 -- Just go to the next record and try to crossdock that.
4461 -- Rollback any db changes that might have occurred (currently none).
4462 ROLLBACK TO Supply_Lines_sp;
4463 GOTO next_record;
4464 END;
4465 l_supply_type_id := 26;
4466 ELSIF (l_supply_src_code = G_PLAN_SUP_RCV) THEN
4467 -- In Receiving
4468 BEGIN
4469 OPEN in_receiving_lines;
4470 FETCH in_receiving_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
4471 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb, l_primary_quantity_tb,
4472 l_secondary_quantity_tb, l_secondary_uom_code_tb,
4473 l_project_id_tb, l_task_id_tb, l_lpn_id_tb;
4474 CLOSE in_receiving_lines;
4475 EXCEPTION
4476 WHEN OTHERS THEN
4477 IF (l_debug = 1) THEN
4478 print_debug('3.2 - Could not retrieve the In Receiving supply lines');
4479 END IF;
4480 -- If we cannot retrieve the available supply lines, do not error out.
4481 -- Just go to the next record and try to crossdock that.
4482 -- Rollback any db changes that might have occurred (currently none).
4483 ROLLBACK TO Supply_Lines_sp;
4484 GOTO next_record;
4485 END;
4486 l_supply_type_id := 27;
4487 ELSE
4488 -- Invalid supply type for crossdocking
4489 -- Rollback any db changes that might have occurred (currently none).
4490 ROLLBACK TO Supply_Lines_sp;
4491 GOTO next_record;
4492 END IF; -- End retrieving supply lines for different supply source types
4493 IF (l_debug = 1) THEN
4494 IF (l_supply_src_code = G_PLAN_SUP_PO_APPR) THEN
4495 print_debug('3.2 - Successfully retrieved ' || l_header_id_tb.COUNT ||
4496 ' available line(s) for Approved PO');
4497 ELSIF (l_supply_src_code = G_PLAN_SUP_ASN) THEN
4498 print_debug('3.2 - Successfully retrieved ' || l_header_id_tb.COUNT ||
4499 ' available line(s) for ASN');
4500 ELSIF (l_supply_src_code = G_PLAN_SUP_REQ) THEN
4501 print_debug('3.2 - Successfully retrieved ' || l_header_id_tb.COUNT ||
4502 ' available line(s) for Internal Requisition');
4503 ELSIF (l_supply_src_code = G_PLAN_SUP_INTR) THEN
4504 print_debug('3.2 - Successfully retrieved ' || l_header_id_tb.COUNT ||
4505 ' available line(s) for In Transit Shipment');
4506 ELSIF (l_supply_src_code = G_PLAN_SUP_RCV) THEN
4507 print_debug('3.2 - Successfully retrieved ' || l_header_id_tb.COUNT ||
4508 ' available line(s) for In Receiving');
4509 END IF;
4510 END IF;
4511 ELSE
4512 -- Supply source type has already been retrieved
4513 IF (l_debug = 1) THEN
4514 IF (l_supply_src_code = G_PLAN_SUP_PO_APPR) THEN
4515 print_debug('3.2 - Supply source has already been retrieved: Approved PO');
4516 ELSIF (l_supply_src_code = G_PLAN_SUP_ASN) THEN
4517 print_debug('3.2 - Supply source has already been retrieved: ASN');
4518 ELSIF (l_supply_src_code = G_PLAN_SUP_REQ) THEN
4519 print_debug('3.2 - Supply source has already been retrieved: Internal Requisition');
4520 ELSIF (l_supply_src_code = G_PLAN_SUP_INTR) THEN
4521 print_debug('3.2 - Supply source has already been retrieved: In Transit Shipment');
4522 ELSIF (l_supply_src_code = G_PLAN_SUP_RCV) THEN
4523 print_debug('3.2 - Supply source has already been retrieved: In Receiving');
4524 END IF;
4525 END IF;
4526 END IF;
4527 l_progress := '390';
4528
4529 -- 3.3 - For each supply line retrieved, determine the expected receipt time.
4530 -- Do the logic in section 3.3 and 3.4 only if records are retrieved
4531 -- for the current supply source type.
4532 IF (l_header_id_tb.COUNT > 0) THEN
4533 IF (l_debug = 1) THEN
4534 print_debug('3.3 - For each supply line retrieved, calculate the expected receipt time');
4535 END IF;
4536 FOR j IN 1 .. l_header_id_tb.COUNT LOOP
4537 -- Call the Get_Expected_Time API if the supply type is not In Receiving
4538 IF (l_supply_type_id <> 27) THEN
4539 -- Do not pass the crossdock criteria ID since we want to be able to reuse
4540 -- the supply lines for other demand lines which might have different
4541 -- crossdock criteria values. If a dock appointment time is found, it will
4542 -- be passed in the output dock time variables.
4543 Get_Expected_Time
4544 (p_source_type_id => l_supply_type_id,
4545 p_source_header_id => l_header_id_tb(j),
4546 p_source_line_id => l_line_id_tb(j),
4547 p_source_line_detail_id => l_line_detail_id_tb(j),
4548 p_supply_or_demand => G_SRC_TYPE_SUP,
4549 p_crossdock_criterion_id => NULL,
4550 x_return_status => x_return_status,
4551 x_msg_count => x_msg_count,
4552 x_msg_data => x_msg_data,
4553 x_dock_start_time => l_dock_start_time_tb(j),
4554 x_dock_mean_time => l_dock_mean_time_tb(j),
4555 x_dock_end_time => l_dock_end_time_tb(j),
4556 x_expected_time => l_expected_time_tb(j));
4557
4558 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
4559 IF (l_debug = 1) THEN
4560 print_debug('3.3 - Success returned from Get_Expected_Time API');
4561 END IF;
4562 ELSE
4563 IF (l_debug = 1) THEN
4564 print_debug('3.3 - Failure returned from Get_Expected_Time API');
4565 END IF;
4566 -- Rollback any db changes that might have occurred (currently none).
4567 ROLLBACK TO Supply_Lines_sp;
4568 GOTO next_record;
4569 --RAISE fnd_api.g_exc_error;
4570 END IF;
4571 ELSE
4572 -- In Receiving supply types have an expected time of SYSDATE
4573 -- since it has already been received. Just set the dock expected times
4574 -- since this is what the Get_Expected_Time API would do if the crossdock
4575 -- criterion is not passed. We want to go against the 'dock' time as the exact
4576 -- time and not use the expected time (in case the 'Supply Reschedule Method' is used).
4577 l_dock_start_time_tb(j) := SYSDATE;
4578 l_dock_mean_time_tb(j) := SYSDATE;
4579 l_dock_end_time_tb(j) := SYSDATE;
4580 l_expected_time_tb(j) := NULL;
4581 END IF;
4582
4583 END LOOP; -- End looping through supply lines retrieved
4584 IF (l_debug = 1) THEN
4585 print_debug('3.3 - Finished calculating expected time for all supply lines');
4586 END IF;
4587 l_progress := '400';
4588
4589 -- 3.4 - Insert the available supply lines into the global temp table.
4590 -- {{
4591 -- Make sure the valid supply lines are properly inserted into the
4592 -- global temp table. }}
4593 IF (l_debug = 1) THEN
4594 print_debug('3.4 - Insert the available supply lines into the global temp table');
4595 END IF;
4596 BEGIN
4597 FORALL k IN 1 .. l_header_id_tb.COUNT
4598 INSERT INTO wms_xdock_pegging_gtmp
4599 (inventory_item_id,
4600 xdock_source_code,
4601 source_type_id,
4602 source_header_id,
4603 source_line_id,
4604 source_line_detail_id,
4605 dock_start_time,
4606 dock_mean_time,
4607 dock_end_time,
4608 expected_time,
4609 quantity,
4610 uom_code,
4611 primary_quantity,
4612 secondary_quantity,
4613 secondary_uom_code,
4614 project_id,
4615 task_id,
4616 lpn_id
4617 )
4618 VALUES
4619 (l_inventory_item_id,
4620 l_supply_src_code,
4621 l_supply_type_id,
4622 l_header_id_tb(k),
4623 l_line_id_tb(k),
4624 l_line_detail_id_tb(k),
4625 l_dock_start_time_tb(k),
4626 l_dock_mean_time_tb(k),
4627 l_dock_end_time_tb(k),
4628 l_expected_time_tb(k),
4629 l_quantity_tb(k),
4630 l_uom_code_tb(k),
4631 l_primary_quantity_tb(k),
4632 l_secondary_quantity_tb(k),
4633 l_secondary_uom_code_tb(k),
4634 l_project_id_tb(k),
4635 l_task_id_tb(k),
4636 l_lpn_id_tb(k)
4637 );
4638 EXCEPTION
4639 WHEN OTHERS THEN
4640 IF (l_debug = 1) THEN
4641 print_debug('3.4 - Error inserting available supply lines into temp table');
4642 END IF;
4643 --RAISE fnd_api.g_exc_error;
4644 -- If an exception occurs while inserting supply line records, just
4645 -- rollback the changes and go to the next WDD record to crossdock.
4646 ROLLBACK TO Supply_Lines_sp;
4647 GOTO next_record;
4648 END;
4649 IF (l_debug = 1) THEN
4650 print_debug('3.4 - Successfully inserted ' || l_header_id_tb.COUNT ||
4651 ' available supply lines into temp table');
4652 END IF;
4653 l_progress := '410';
4654
4655 -- Clear the PLSQL tables used once the data is inserted into the global temp table
4656 l_header_id_tb.DELETE;
4657 l_line_id_tb.DELETE;
4658 l_line_detail_id_tb.DELETE;
4659 l_dock_start_time_tb.DELETE;
4660 l_dock_mean_time_tb.DELETE;
4661 l_dock_end_time_tb.DELETE;
4662 l_expected_time_tb.DELETE;
4663 l_quantity_tb.DELETE;
4664 l_uom_code_tb.DELETE;
4665 l_primary_quantity_tb.DELETE;
4666 l_secondary_quantity_tb.DELETE;
4667 l_secondary_uom_code_tb.DELETE;
4668 l_project_id_tb.DELETE;
4669 l_task_id_tb.DELETE;
4670 l_lpn_id_tb.DELETE;
4671 END IF; -- END IF matches: IF (l_header_id_tb.COUNT > 0) THEN
4672
4673 -- Set the marker indicating we have retrieved the supply lines for the
4674 -- current source type and item. This value could already exist if the supply source
4675 -- type and item was retrieved previously. However it is okay to set this again.
4676 l_src_types_retrieved_tb(l_inventory_item_id)(l_supply_src_code) := TRUE;
4677 l_progress := '420';
4678
4679 END LOOP; -- End looping through eligible supply source types
4680
4681 -- 3.5 - Retrieve all of the supply lines that fall within the crossdock window and
4682 -- store it in the shopping basket table. If prioritize documents, order this
4683 -- by the source type.
4684 IF (l_debug = 1) THEN
4685 print_debug('3.5 - Retrieve all of the supply lines that are valid for crossdocking');
4686 END IF;
4687
4688 -- Iniitialize the shopping basket table which will store the valid supply lines
4689 -- for crossdocking to the current demand line.
4690 l_shopping_basket_tb.DELETE;
4691
4692 -- Initialize the available supply source types to retrieve
4693 l_po_sup := -1;
4694 l_asn_sup := -1;
4695 l_intreq_sup := -1;
4696 l_intship_sup := -1;
4697 l_rcv_sup := -1;
4698
4699 -- Initialize the supply document priority variables
4700 l_po_priority := 99;
4701 l_asn_priority := 99;
4702 l_intreq_priority := 99;
4703 l_intship_priority := 99;
4704 l_rcv_priority := 99;
4705
4706 -- Get the valid supply source types to retrieve.
4707 -- The supply source types are cached in the order of the document priority already.
4708 -- Just use the same index value for the document priority variable.
4709 FOR i IN 1 .. l_supply_src_types_tb(l_crossdock_criteria_id).COUNT LOOP
4710 IF (l_supply_src_types_tb(l_crossdock_criteria_id)(i) = G_PLAN_SUP_PO_APPR) THEN
4711 l_po_sup := G_PLAN_SUP_PO_APPR;
4712 l_po_priority := i;
4713 ELSIF (l_supply_src_types_tb(l_crossdock_criteria_id)(i) = G_PLAN_SUP_ASN) THEN
4714 l_asn_sup := G_PLAN_SUP_ASN;
4715 l_asn_priority := i;
4716 ELSIF (l_supply_src_types_tb(l_crossdock_criteria_id)(i) = G_PLAN_SUP_REQ) THEN
4717 l_intreq_sup := G_PLAN_SUP_REQ;
4718 l_intreq_priority := i;
4719 ELSIF (l_supply_src_types_tb(l_crossdock_criteria_id)(i) = G_PLAN_SUP_INTR) THEN
4720 l_intship_sup := G_PLAN_SUP_INTR;
4721 l_intship_priority := i;
4722 ELSIF (l_supply_src_types_tb(l_crossdock_criteria_id)(i) = G_PLAN_SUP_RCV) THEN
4723 l_rcv_sup := G_PLAN_SUP_RCV;
4724 l_rcv_priority := i;
4725 END IF;
4726 END LOOP;
4727
4728 -- If we do not need to prioritize documents, reset the supply document
4729 -- priority variables to the same default value
4730 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).prioritize_documents_flag = 2) THEN
4731 l_po_priority := 99;
4732 l_asn_priority := 99;
4733 l_intreq_priority := 99;
4734 l_intship_priority := 99;
4735 l_rcv_priority := 99;
4736 END IF;
4737
4738 -- Now get the valid supply lines for crossdocking and store it in the
4739 -- shopping basket table. Only pick up supply lines that match the project/task
4740 -- on the demand (if necessary).
4741 -- {{
4742 -- Make sure the supply lines are retrieved properly into the shopping basket table.
4743 -- Do this both with and without enforcing document priority. Also use various
4744 -- available supply types. }}
4745 BEGIN
4746 OPEN get_supply_lines
4747 (p_xdock_start_time => l_xdock_start_time,
4748 p_xdock_end_time => l_xdock_end_time,
4749 p_sup_resched_flag => g_crossdock_criteria_tb(l_crossdock_criteria_id).allow_supply_reschedule_flag,
4750 p_sup_sched_method => g_crossdock_criteria_tb(l_crossdock_criteria_id).supply_schedule_method,
4751 p_crossdock_goal => g_crossdock_criteria_tb(l_crossdock_criteria_id).crossdock_goal,
4752 p_past_due_interval => l_past_due_interval,
4753 p_past_due_time => l_past_due_time,
4754 p_po_sup => l_po_sup,
4755 p_po_priority => l_po_priority,
4756 p_asn_sup => l_asn_sup,
4757 p_asn_priority => l_asn_priority,
4758 p_intreq_sup => l_intreq_sup,
4759 p_intreq_priority => l_intreq_priority,
4760 p_intship_sup => l_intship_sup,
4761 p_intship_priority => l_intship_priority,
4762 p_rcv_sup => l_rcv_sup,
4763 p_rcv_priority => l_rcv_priority,
4764 p_demand_prim_qty => l_demand_atr_prim_qty,
4765 p_project_id => l_demand_project_id,
4766 p_task_id => l_demand_task_id);
4767 FETCH get_supply_lines BULK COLLECT INTO l_shopping_basket_tb;
4768 CLOSE get_supply_lines;
4769 EXCEPTION
4770 WHEN OTHERS THEN
4771 IF (l_debug = 1) THEN
4772 print_debug('3.5 - Could not retrieve the valid supply lines for available source types');
4773 END IF;
4774 -- If we cannot retrieve the valid supply lines, do not error out.
4775 -- Just go to the next record and try to crossdock that.
4776 GOTO next_record;
4777 END;
4778 IF (l_debug = 1) THEN
4779 print_debug('3.5 - Successfully populated the shopping basket table with ' ||
4780 l_shopping_basket_tb.COUNT || ' crossdockable supply lines');
4781 END IF;
4782 l_progress := '430';
4783
4784 -- 3.6 - Sort the supply lines in the shopping basket table based on the crossdocking
4785 -- goals.
4786 -- For crossdock goals of Minimize Wait and Maximize Crossdock, the supply lines in the
4787 -- shopping basket have already been sorted.
4788 -- {{
4789 -- Test out the custom crossdock goal method of sorting the shopping basket lines.
4790 -- The not implemented stub version should just pass back the inputted shopping basket
4791 -- table without sorting them. }}
4792 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).crossdock_goal = G_CUSTOM_GOAL) THEN
4793 -- For each record in the shopping basket table, call the available to reserve API
4794 -- to determine how much quantity from each supply line is available for crossdocking.
4795 -- We need to do this since the custom logic might decide which supply lines to consume
4796 -- based on the reservable quantity (e.g. Best Fit SPQ type of logic).
4797 -- Do this only if the value is not available yet in the shopping basket supply record.
4798 IF (l_debug = 1) THEN
4799 print_debug('3.6 - Use custom logic to sort the supply lines');
4800 END IF;
4801
4802 FOR i IN 1 .. l_shopping_basket_tb.COUNT LOOP
4803
4804 IF (l_shopping_basket_tb(i).reservable_quantity IS NULL) THEN
4805 -- Reservable Quantity value has not been calculated yet for this supply.
4806 -- This API will return available to reserve quantity in the primary UOM.
4807 IF (l_debug = 1) THEN
4808 print_debug('3.6 - Call the Available_supply_to_reserve API');
4809 END IF;
4810 INV_RESERVATION_AVAIL_PVT.Available_supply_to_reserve
4811 (p_api_version_number => 1.0,
4812 p_init_msg_lst => fnd_api.g_false,
4813 x_return_status => x_return_status,
4814 x_msg_count => x_msg_count,
4815 x_msg_data => x_msg_data,
4816 p_organization_id => l_organization_id,
4817 p_item_id => l_inventory_item_id,
4818 p_supply_source_type_id => l_shopping_basket_tb(i).source_type_id,
4819 p_supply_source_header_id => l_shopping_basket_tb(i).source_header_id,
4820 p_supply_source_line_id => l_shopping_basket_tb(i).source_line_id,
4821 p_supply_source_line_detail => l_shopping_basket_tb(i).source_line_detail_id,
4822 p_project_id => l_shopping_basket_tb(i).project_id,
4823 p_task_id => l_shopping_basket_tb(i).task_id,
4824 x_qty_available_to_reserve => l_supply_atr_prim_qty,
4825 x_qty_available => l_supply_available_qty);
4826
4827 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
4828 IF (l_debug = 1) THEN
4829 print_debug('3.6 - Error returned from available_supply_to_reserve API: '
4830 || x_return_status);
4831 END IF;
4832 -- Instead of erroring out and going to the next WDD record to crossdock,
4833 -- just delete the supply line from the shopping basket table. Shopping basket
4834 -- table can therefore be a sparsely populated table after running custom logic.
4835 l_shopping_basket_tb.DELETE(i);
4836 GOTO next_custom_supply;
4837 --GOTO next_record;
4838 --RAISE fnd_api.g_exc_error;
4839 END IF;
4840
4841 -- If the supply is 'In Receiving', the ATR qty returned is for all of receiving.
4842 -- Since we're working on a specific MOL supply line, we need to use a LEAST
4843 -- to get the min qty value.
4844 IF (l_shopping_basket_tb(i).source_type_id = 27) THEN
4845 l_supply_atr_prim_qty := LEAST(l_shopping_basket_tb(i).primary_quantity,
4846 l_supply_atr_prim_qty);
4847 END IF;
4848
4849 -- Convert the ATR primary quantity to the UOM on the supply line
4850 l_supply_uom_code := l_shopping_basket_tb(i).uom_code;
4851 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
4852 l_primary_uom_code, l_supply_uom_code);
4853 IF (l_conversion_rate < 0) THEN
4854 IF (l_debug = 1) THEN
4855 print_debug('3.6 - Error while obtaining Primary UOM conversion rate for supply line');
4856 END IF;
4857 -- Instead of erroring out and going to the next WDD record to crossdock,
4858 -- just delete the supply line from the shopping basket table. Shopping basket
4859 -- table can therefore be a sparsely populated table after running custom logic.
4860 l_shopping_basket_tb.DELETE(i);
4861 GOTO next_custom_supply;
4862 END IF;
4863 -- Round the converted quantity to the standard precision
4864 l_supply_atr_qty := ROUND(l_conversion_rate * l_supply_atr_prim_qty, l_conversion_precision);
4865 IF (l_debug = 1) THEN
4866 print_debug('3.6 - Supply line ATR qty: ' || l_supply_atr_qty || ' ' ||
4867 l_supply_uom_code);
4868 END IF;
4869
4870 ELSIF (l_shopping_basket_tb(i).reservable_quantity IS NOT NULL) THEN
4871 -- Reservable Quantity value has alraedy been calculated for this supply.
4872 l_supply_atr_qty := l_shopping_basket_tb(i).reservable_quantity;
4873 END IF;
4874
4875 -- Set the quantity field to be equal to the ATR quanitty for the current supply line
4876 -- record in the shopping basket. We do not want to set this value in
4877 -- the reservable_quantity column since this is also used to indicate if the supply line
4878 -- record has been locked already. Since we are not locking the supply line records yet
4879 -- here when using custom logic, we will make use of the quantity field instead.
4880 -- The custom API should make use of the quantity value instead when sorting the supply
4881 -- lines.
4882 l_shopping_basket_tb(i).quantity := l_supply_atr_qty;
4883
4884 <<next_custom_supply>>
4885 NULL; -- Need an executable statment for the branching label above
4886 END LOOP; -- End retrieving ATR quantity for all supply lines in shopping basket table
4887 -- At this stage, the shopping basket table will have the ATR quantity stamped on all of
4888 -- the records. The table can be sparse so the custom logic to sort the shopping basket
4889 -- must keep this in mind. This will be documented in the custom logic API.
4890 l_progress := '440';
4891
4892 -- Call the Custom logic to sort the shopping basket table.
4893 -- If the API is not implemented, the lines will not be sorted at all.
4894 -- {{
4895 -- Test that invalid custom logic to sort demand lines is caught. No sorting
4896 -- should be done if this is the case. }}
4897 IF (l_debug = 1) THEN
4898 print_debug('3.6 - Call the Sort_Supply_Lines API');
4899 END IF;
4900 WMS_XDOCK_CUSTOM_APIS_PUB.Sort_Supply_Lines
4901 (p_wdd_release_record => p_wsh_release_table(l_wdd_index),
4902 p_prioritize_documents => g_crossdock_criteria_tb(l_crossdock_criteria_id).prioritize_documents_flag,
4903 p_shopping_basket_tb => l_shopping_basket_tb,
4904 x_return_status => x_return_status,
4905 x_msg_count => x_msg_count,
4906 x_msg_data => x_msg_data,
4907 x_api_is_implemented => l_api_is_implemented,
4908 x_sorted_order_tb => l_sorted_order_tb);
4909
4910 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
4911 IF (l_debug = 1) THEN
4912 print_debug('3.6 - Success returned from Sort_Supply_Lines API');
4913 END IF;
4914 ELSE
4915 IF (l_debug = 1) THEN
4916 print_debug('3.6 - Failure returned from Sort_Supply_Lines API');
4917 END IF;
4918 -- In case of exception, do not error out. Just use whatever order the
4919 -- supply lines are in when the shopping basket table was created.
4920 --RAISE fnd_api.g_exc_error;
4921 l_sorted_order_tb.DELETE;
4922 END IF;
4923 l_progress := '450';
4924
4925 IF (NOT l_api_is_implemented) THEN
4926 IF (l_debug = 1) THEN
4927 print_debug('3.6 - Custom API is NOT implemented even though Custom Goal is selected!');
4928 END IF;
4929 ELSE
4930 IF (l_debug = 1) THEN
4931 print_debug('3.6 - Custom API is implemented so custom sorting logic is used');
4932 END IF;
4933 END IF;
4934
4935 -- Validate that the output l_sorted_order_tb is not larger in size than
4936 -- the shopping basket table and that values exist in l_sorted_order_tb.
4937 IF (l_debug = 1) THEN
4938 print_debug('3.6 - Rebuild the shopping basket table based on the sorting order returned');
4939 END IF;
4940 IF (l_sorted_order_tb.COUNT > l_shopping_basket_tb.COUNT OR
4941 l_sorted_order_tb.COUNT = 0) THEN
4942 -- Invalid condition from the custom logic API.
4943 -- Do not sort the shopping basket table and just use the current order
4944 -- the lines are in.
4945 IF (l_debug = 1) THEN
4946 print_debug('3.6 - Invalid output from Sort_Supply_Lines API');
4947 print_debug('3.6 - Do not sort the supply lines in the shopping basket');
4948 END IF;
4949 ELSE
4950 -- Sort and rebuild the shopping basket table
4951 l_index := l_sorted_order_tb.FIRST;
4952 -- Initialize the indices used table and the temp shopping basket table
4953 l_indices_used_tb.DELETE;
4954 l_shopping_basket_temp_tb.DELETE;
4955 LOOP
4956 -- Make sure the current entry has not already been used.
4957 -- Also make sure the index refered to in l_sorted_order_tb is a valid one
4958 -- in the shopping basket table.
4959 IF (l_indices_used_tb.EXISTS(l_sorted_order_tb(l_index)) OR
4960 NOT l_shopping_basket_tb.EXISTS(l_sorted_order_tb(l_index))) THEN
4961 IF (l_debug = 1) THEN
4962 print_debug('3.6 - Sorted order table is invalid so do not sort the supply lines');
4963 END IF;
4964 -- Clear the temp shopping basket table
4965 l_shopping_basket_temp_tb.DELETE;
4966 -- Exit out of the loop. No sorting will be done.
4967 GOTO invalid_sorting;
4968 END IF;
4969
4970 -- Mark the current pointer index to the shopping basket table as used
4971 l_indices_used_tb(l_sorted_order_tb(l_index)) := TRUE;
4972
4973 -- Add this entry to the temp shopping basket table.
4974 l_shopping_basket_temp_tb(l_shopping_basket_temp_tb.COUNT + 1) :=
4975 l_shopping_basket_tb(l_sorted_order_tb(l_index));
4976
4977 EXIT WHEN l_index = l_sorted_order_tb.LAST;
4978 l_index := l_sorted_order_tb.NEXT(l_index);
4979 END LOOP;
4980
4981 -- Set the shopping basket table to point to the new sorted one
4982 l_shopping_basket_tb := l_shopping_basket_temp_tb;
4983 l_shopping_basket_temp_tb.DELETE;
4984 IF (l_debug = 1) THEN
4985 print_debug('3.6 - Finished sorting and rebuilding the shopping basket table');
4986 END IF;
4987
4988 -- In case of an invalid sorted order table, jump to this label below and
4989 -- do not sort the shopping basket at all.
4990 <<invalid_sorting>>
4991 NULL; -- Need an executable statement for the above label to work
4992 END IF;
4993 l_progress := '460';
4994
4995 END IF; -- End of crossdocking goal = CUSTOM
4996
4997 -- Section 4: Consume the valid supply lines for crossdocking to the demand line
4998 -- 4.1 - Lock the supply line record(s).
4999 -- 4.2 - Call the available to reserve API to see how much quantity from the supply
5000 -- is valid for crossdocking.
5001 -- 4.3 - Crossdock the demand and supply line records.
5002 -- 4.4 - Create a crossdocked reservation tying the demand to the supply line.
5003 -- 4.5 - Bulk update the reservable_quantity for all crossdocked supply lines in the
5004 -- global temp table, wms_xdock_pegging_gtmp.
5005
5006 -- Check if there are valid supply lines found for crossdocking.
5007 -- If none exist, move on to the next WDD record to crossdock.
5008 IF (l_shopping_basket_tb.COUNT = 0) THEN
5009 IF (l_debug = 1) THEN
5010 print_debug('4.1 - No valid supply lines for crossdocking were found');
5011 END IF;
5012 GOTO next_record;
5013 END IF;
5014
5015 -- Initialize the shopping basket supply lines index. This should not be a NULL value.
5016 l_supply_index := NVL(l_shopping_basket_tb.FIRST, 1);
5017
5018 -- Initialize the supply ATR tables used to do a bulk update for the supply lines
5019 -- crossdocked sucessfully for the reservable_quantity column.
5020 l_supply_rowid_tb.DELETE;
5021 l_supply_atr_qty_tb.DELETE;
5022
5023 -- Define a savepoint so if an exception occurs when performing the bulk update
5024 -- of supply lines in wms_xdock_pegging_gtmp after the supply lines shopping basket loop,
5025 -- we want to rollback all crossdock changes done within the loop.
5026 SAVEPOINT Before_Supply_Loop_sp;
5027
5028 -- Loop through the valid supply lines to crossdock the current WDD demand
5029 LOOP
5030 -- Define a savepoint so if an exception occurs while updating database records such as
5031 -- WDD, RSV, or MOL, we need to rollback the changes and goto the next WDD record
5032 -- to crossdock. Put this inside the supply lines loop so if one supply line
5033 -- is crossdocked successfully but another one errors out, we can still crossdock
5034 -- the first one.
5035 SAVEPOINT Crossdock_Supply_sp;
5036
5037 -- Initialize the variables to store the original WDD values in case
5038 -- we need to rollback the changes to local PLSQL data structures
5039 l_split_wdd_index := NULL;
5040 l_split_delivery_index := NULL;
5041 l_xdocked_wdd_index := NULL;
5042 l_orig_wdd_values_rec := NULL;
5043
5044 -- Initialize the supply ATR index variable which is used to update
5045 -- the ATR qty for the supply lines used in this loop when crossdocked.
5046 l_supply_atr_index := NULL;
5047
5048 -- Retrieve needed values from the current supply line
5049 l_supply_type_id := l_shopping_basket_tb(l_supply_index).source_type_id;
5050 l_supply_header_id := l_shopping_basket_tb(l_supply_index).source_header_id;
5051 l_supply_line_id := l_shopping_basket_tb(l_supply_index).source_line_id;
5052 l_supply_line_detail_id := l_shopping_basket_tb(l_supply_index).source_line_detail_id;
5053 IF (l_debug = 1) THEN
5054 print_debug('4.1 - Current supply line to consider for crossdocking');
5055 print_debug('4.1 - Supply Source Type ID: => ' || l_supply_type_id);
5056 print_debug('4.1 - Supply Header ID: ======> ' || l_supply_header_id);
5057 print_debug('4.1 - Supply Line ID: ========> ' || l_supply_line_id);
5058 print_debug('4.1 - Supply Line Detail ID: => ' || l_supply_line_detail_id);
5059 END IF;
5060
5061 -- If the supply type is In Receiving, retrieve the necessary MOL values.
5062 -- They will be used to update/split the MOL supply line used for crossdocking.
5063 IF (l_supply_type_id = 27) THEN
5064 l_mol_header_id := l_supply_header_id;
5065 l_mol_line_id := l_supply_line_id;
5066 l_mol_qty := l_shopping_basket_tb(l_supply_index).quantity;
5067 l_mol_prim_qty := l_shopping_basket_tb(l_supply_index).primary_quantity;
5068 l_mol_qty2 := l_shopping_basket_tb(l_supply_index).secondary_quantity;
5069 l_mol_uom_code2 := l_shopping_basket_tb(l_supply_index).secondary_uom_code;
5070 l_mol_lpn_id := l_shopping_basket_tb(l_supply_index).lpn_id;
5071 ELSE
5072 l_mol_line_id := NULL;
5073 END IF;
5074
5075 -- For non-existing reservations, we do not need to match the UOM code on the supply line
5076 l_supply_uom_code := NULL;
5077
5078 -- In case the supply is of type 'In Receiving' and the org is not PJM enabled OR
5079 -- cross project allocation is allowed, set the supply project and task ID to the
5080 -- dummy values. This is used to see if the set of MOLs for the project/task have been
5081 -- locked already or not. For supply types other than In Receiving, this is not used.
5082 IF (l_project_ref_enabled = 2 OR l_allow_cross_proj_issues = 'Y') THEN
5083 l_supply_project_id := l_dummy_project_id;
5084 l_supply_task_id := l_dummy_task_id;
5085 ELSE
5086 l_supply_project_id := l_shopping_basket_tb(l_supply_index).project_id;
5087 l_supply_task_id := l_shopping_basket_tb(l_supply_index).task_id;
5088 END IF;
5089
5090 -- 4.1 - Lock the supply line record(s).
5091 -- Do this only if the supply line has not already been locked.
5092 -- For non-Receiving supply types, we can just check if the reservable_quantity field is null.
5093 -- For Receiving supply types, since we lock an entire set of MOLs at once, we do not want to
5094 -- do this again if not necessary. For example, say there are two valid MOLs for Item1, call
5095 -- them MOL1 and MOL2. Both records are pulled into the shopping basket table. When we
5096 -- first encounter MOL1, the MOLs associated with Item1 have not been locked yet. The set
5097 -- of MOLs we will lock also includes MOL2. When we next use MOL2 as a supply line for
5098 -- crossdocking, it is unnecessary to lock this record since it has already been done.
5099 -- We might still have to calculate the ATR qty even though the record has been locked.
5100 -- That is why for MOLs, we cannot rely on the reservable_quantity field.
5101 IF ((l_supply_type_id <> 27 AND l_shopping_basket_tb(l_supply_index).reservable_quantity IS NULL)
5102 OR
5103 (l_supply_type_id = 27 AND l_shopping_basket_tb(l_supply_index).reservable_quantity IS NULL
5104 AND NOT (l_locked_mols_tb.EXISTS(l_inventory_item_id) AND
5105 l_locked_mols_tb(l_inventory_item_id).EXISTS(l_supply_project_id) AND
5106 l_locked_mols_tb(l_inventory_item_id)(l_supply_project_id).EXISTS(l_supply_task_id))))
5107 THEN
5108 -- We do not need to use these cursors to retrieve the supply line UOM code, project
5109 -- and task ID since that information is already stored in the shopping basket table.
5110 -- We are doing that here so we can reuse the same locking cursors used for crossdocking
5111 -- existing reservations.
5112 IF (l_supply_type_id = 1) THEN
5113 -- PO
5114 BEGIN
5115 OPEN lock_po_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
5116 FETCH lock_po_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
5117 IF (lock_po_record%NOTFOUND) THEN
5118 -- If a record is not found, do not error out. This error condition should not
5119 -- occur since the supply lines retrieved should already satisfy the project
5120 -- and task restrictions. Skip this supply line and move on to the next one.
5121 IF (l_debug = 1) THEN
5122 print_debug('4.1 - Supply record not found. UOM/project/task values do not match');
5123 END IF;
5124 CLOSE lock_po_record;
5125 -- Rollback any db changes that might have occurred (currently none).
5126 ROLLBACK TO Crossdock_Supply_sp;
5127 GOTO next_supply;
5128 END IF;
5129 CLOSE lock_po_record;
5130 EXCEPTION
5131 WHEN OTHERS THEN
5132 IF (l_debug = 1) THEN
5133 print_debug('4.1 - Could not lock the PO supply line record');
5134 END IF;
5135 -- If we cannot lock the supply line, do not error out. Just go to the
5136 -- next available supply and try to crossdock that.
5137 -- Rollback any db changes that might have occurred (currently none).
5138 ROLLBACK TO Crossdock_Supply_sp;
5139 GOTO next_supply;
5140 END;
5141 ELSIF (l_supply_type_id = 7) THEN
5142 -- Internal Requisition
5143 BEGIN
5144 OPEN lock_intreq_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
5145 -- Multiple records could be returned from this cursor. We only care about existence.
5146 FETCH lock_intreq_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
5147 IF (lock_intreq_record%NOTFOUND) THEN
5148 -- If a record is not found, do not error out. This error condition should not
5149 -- occur since the supply lines retrieved should already satisfy the project
5150 -- and task restrictions. Skip this supply line and move on to the next one.
5151 IF (l_debug = 1) THEN
5152 print_debug('4.1 - Supply record not found. UOM/project/task values do not match');
5153 END IF;
5154 CLOSE lock_intreq_record;
5155 -- Rollback any db changes that might have occurred (currently none).
5156 ROLLBACK TO Crossdock_Supply_sp;
5157 GOTO next_supply;
5158 END IF;
5159 CLOSE lock_intreq_record;
5160 EXCEPTION
5161 WHEN OTHERS THEN
5162 IF (l_debug = 1) THEN
5163 print_debug('4.1 - Could not lock the Internal Req supply line record');
5164 END IF;
5165 -- If we cannot lock the supply line, do not error out. Just go to the
5166 -- next available supply and try to crossdock that.
5167 -- Rollback any db changes that might have occurred (currently none).
5168 ROLLBACK TO Crossdock_Supply_sp;
5169 GOTO next_supply;
5170 END;
5171 ELSIF (l_supply_type_id = 25) THEN
5172 -- ASN
5173 BEGIN
5174 OPEN lock_asn_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
5175 FETCH lock_asn_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
5176 IF (lock_asn_record%NOTFOUND) THEN
5177 -- If a record is not found, do not error out. This error condition should not
5178 -- occur since the supply lines retrieved should already satisfy the project
5179 -- and task restrictions. Skip this supply line and move on to the next one.
5180 IF (l_debug = 1) THEN
5181 print_debug('4.1 - Supply record not found. UOM/project/task values do not match');
5182 END IF;
5183 CLOSE lock_asn_record;
5184 -- Rollback any db changes that might have occurred (currently none).
5185 ROLLBACK TO Crossdock_Supply_sp;
5186 GOTO next_supply;
5187 END IF;
5188 CLOSE lock_asn_record;
5189 EXCEPTION
5190 WHEN OTHERS THEN
5191 IF (l_debug = 1) THEN
5192 print_debug('4.1 - Could not lock the ASN supply line record');
5193 END IF;
5194 -- If we cannot lock the supply line, do not error out. Just go to the
5195 -- next available supply and try to crossdock that.
5196 -- Rollback any db changes that might have occurred (currently none).
5197 ROLLBACK TO Crossdock_Supply_sp;
5198 GOTO next_supply;
5199 END;
5200 ELSIF (l_supply_type_id = 26) THEN
5201 -- In Transit Shipment
5202 BEGIN
5203 OPEN lock_intship_record(l_supply_uom_code, l_demand_project_id, l_demand_task_id);
5204 FETCH lock_intship_record INTO l_supply_uom_code, l_supply_project_id, l_supply_task_id;
5205 IF (lock_intship_record%NOTFOUND) THEN
5206 -- If a record is not found, do not error out. This error condition should not
5207 -- occur since the supply lines retrieved should already satisfy the project
5208 -- and task restrictions. Skip this supply line and move on to the next one.
5209 IF (l_debug = 1) THEN
5210 print_debug('4.1 - Supply record not found. UOM/project/task values do not match');
5211 END IF;
5212 CLOSE lock_intship_record;
5213 -- Rollback any db changes that might have occurred (currently none).
5214 ROLLBACK TO Crossdock_Supply_sp;
5215 GOTO next_supply;
5216 END IF;
5217 CLOSE lock_intship_record;
5218 EXCEPTION
5219 WHEN OTHERS THEN
5220 IF (l_debug = 1) THEN
5221 print_debug('4.1 - Could not lock the In Transit Shipment supply line record');
5222 END IF;
5223 -- If we cannot lock the supply line, do not error out. Just go to the
5224 -- next available supply and try to crossdock that.
5225 -- Rollback any db changes that might have occurred (currently none).
5226 ROLLBACK TO Crossdock_Supply_sp;
5227 GOTO next_supply;
5228 END;
5229 ELSIF (l_supply_type_id = 27) THEN
5230 -- In Receiving
5231 -- We need to lock the set of MOLs that match the given crossdocking criteria for:
5232 -- org, item, UOM, project and task.
5233 -- Initialize the table we are fetching records into. For this case, we do not need
5234 -- to use the values stored there since we are going against the shopping basket
5235 -- supply line records directly.
5236 l_rcv_lines_tb.DELETE;
5237 BEGIN
5238 OPEN lock_receiving_lines(l_supply_uom_code, l_demand_atr_prim_qty,
5239 l_demand_project_id, l_demand_task_id);
5240 FETCH lock_receiving_lines BULK COLLECT INTO l_rcv_lines_tb;
5241 -- If a record is not found, do not error out. This error condition should not
5242 -- occur since the supply lines retrieved should already satisfy the project
5243 -- and task restrictions. Skip this supply line and move on to the next one.
5244 IF (l_rcv_lines_tb.COUNT = 0) THEN
5245 IF (l_debug = 1) THEN
5246 print_debug('4.1 - No valid receiving supply lines found');
5247 END IF;
5248 CLOSE lock_receiving_lines;
5249 -- Rollback any db changes that might have occurred (currently none).
5250 ROLLBACK TO Crossdock_Supply_sp;
5251 GOTO next_supply;
5252 END IF;
5253 CLOSE lock_receiving_lines;
5254 EXCEPTION
5255 WHEN OTHERS THEN
5256 IF (l_debug = 1) THEN
5257 print_debug('4.1 - Could not lock the Receiving supply line records');
5258 END IF;
5259 -- If we cannot lock the supply lines, do not error out. Just go to the
5260 -- next available supply and try to crossdock that.
5261 -- Rollback any db changes that might have occurred (currently none).
5262 ROLLBACK TO Crossdock_Supply_sp;
5263 GOTO next_supply;
5264 END;
5265 -- Clear the table since we do not need to use it
5266 l_rcv_lines_tb.DELETE;
5267
5268 -- Indicate that this set of MOLs for the given item has already been locked.
5269 IF (l_project_ref_enabled = 2 OR l_allow_cross_proj_issues = 'Y') THEN
5270 -- No need to store the project/task info so just use the
5271 -- dummy project/task ID values.
5272 l_locked_mols_tb(l_inventory_item_id)(l_dummy_project_id)(l_dummy_task_id) := TRUE;
5273 ELSE
5274 -- We need to store the specific project/task info.
5275 -- Since we have to match the project/task here, the supply line in the
5276 -- shopping basket should have the same values as the demand.
5277 l_locked_mols_tb(l_inventory_item_id)(NVL(l_demand_project_id, -999))(NVL(l_demand_task_id, -999)) := TRUE;
5278 END IF;
5279 ELSE
5280 -- Invalid supply for crossdocking. Should not reach this condition.
5281 -- Rollback any db changes that might have occurred (currently none).
5282 ROLLBACK TO Crossdock_Supply_sp;
5283 GOTO next_supply;
5284 END IF; -- End locking supply line(s) from different source types
5285 END IF; -- End check if reservable_quantity IS NOT NULL
5286
5287 -- Reset these values to the ones stored in the shopping basket table.
5288 -- The values could differ if the supply line is In Receiving since multiple
5289 -- MOLs are locked/retrieved for the current supply line (MOL) in the shopping basket.
5290 l_supply_uom_code := l_shopping_basket_tb(l_supply_index).uom_code;
5291 l_supply_project_id := l_shopping_basket_tb(l_supply_index).project_id;
5292 l_supply_task_id := l_shopping_basket_tb(l_supply_index).task_id;
5293 IF (l_debug = 1) THEN
5294 print_debug('4.1 - Successfully locked and validated the supply line record(s)');
5295 print_debug('4.1 - Supply UOM Code: ===> ' || l_supply_uom_code);
5296 print_debug('4.1 - Supply Project ID: => ' || l_supply_project_id);
5297 print_debug('4.1 - Supply Task ID: ====> ' || l_supply_task_id);
5298 END IF;
5299 l_progress := '470';
5300
5301 -- 4.2 - Call the available to reserve API to see how much quantity from the supply
5302 -- is valid for crossdocking.
5303 -- Check if this value has already been queried and stored in the global temp table.
5304 -- The shopping basket record for the supply line will have a non null value for the
5305 -- reservable_quantity field. This means the supply line was locked and used for
5306 -- crossdocking previously. In that case, we do not need to call the available to
5307 -- reserve API's again.
5308 IF (l_shopping_basket_tb(l_supply_index).reservable_quantity IS NULL) THEN
5309 IF (l_debug = 1) THEN
5310 print_debug('4.2 - Call the Available_supply_to_reserve API');
5311 END IF;
5312 INV_RESERVATION_AVAIL_PVT.Available_supply_to_reserve
5313 (p_api_version_number => 1.0,
5314 p_init_msg_lst => fnd_api.g_false,
5315 x_return_status => x_return_status,
5316 x_msg_count => x_msg_count,
5317 x_msg_data => x_msg_data,
5318 p_organization_id => l_organization_id,
5319 p_item_id => l_inventory_item_id,
5320 p_supply_source_type_id => l_supply_type_id,
5321 p_supply_source_header_id => l_supply_header_id,
5322 p_supply_source_line_id => l_supply_line_id,
5323 p_supply_source_line_detail => l_supply_line_detail_id,
5324 p_project_id => l_supply_project_id,
5325 p_task_id => l_supply_task_id,
5326 x_qty_available_to_reserve => l_supply_atr_prim_qty,
5327 x_qty_available => l_supply_available_qty);
5328
5329 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
5330 IF (l_debug = 1) THEN
5331 print_debug('4.2 - Error returned from available_supply_to_reserve API: '
5332 || x_return_status);
5333 END IF;
5334 -- Rollback any db changes that might have occurred (currently none).
5335 ROLLBACK TO Crossdock_Supply_sp;
5336 GOTO next_supply;
5337 --RAISE fnd_api.g_exc_error;
5338 END IF;
5339
5340 -- If the supply is 'In Receiving', the ATR qty returned is for all of receiving.
5341 -- Since we're working on a specific MOL supply line, we need to use a LEAST
5342 -- to get the min qty value.
5343 IF (l_supply_type_id = 27) THEN
5344 l_supply_atr_prim_qty := LEAST(l_mol_prim_qty, l_supply_atr_prim_qty);
5345 END IF;
5346
5347 -- Convert the ATR primary quantity to the UOM on the supply line
5348 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
5349 l_primary_uom_code, l_supply_uom_code);
5350 IF (l_conversion_rate < 0) THEN
5351 IF (l_debug = 1) THEN
5352 print_debug('4.2 - Error while obtaining Primary UOM conversion rate for supply line');
5353 END IF;
5354 -- Rollback any db changes that might have occurred (currently none).
5355 ROLLBACK TO Crossdock_Supply_sp;
5356 GOTO next_supply;
5357 END IF;
5358 -- Round the converted quantity to the standard precision
5359 l_supply_atr_qty := ROUND(l_conversion_rate * l_supply_atr_prim_qty, l_conversion_precision);
5360
5361 -- Set the reservable quantity field for the current supply line
5362 -- in the shopping basket table.
5363 l_shopping_basket_tb(l_supply_index).reservable_quantity := l_supply_atr_qty;
5364
5365 ELSIF (l_shopping_basket_tb(l_supply_index).reservable_quantity IS NOT NULL) THEN
5366 -- ATR quantity has already been calculated for this supply line
5367 l_supply_atr_qty := l_shopping_basket_tb(l_supply_index).reservable_quantity;
5368 END IF; -- End retrieving the ATR supply quantity
5369 IF (l_debug = 1) THEN
5370 print_debug('4.2 - Supply line ATR qty: ' || l_supply_atr_qty || ' ' ||
5371 l_supply_uom_code);
5372 END IF;
5373 -- If the current supply line has no reservable quantity,
5374 -- skip it and go to the next available supply line.
5375 IF (l_supply_atr_qty <= 0) THEN
5376 IF (l_debug = 1) THEN
5377 print_debug('4.2 - Supply ATR qty <= 0 so skip to next available supply');
5378 END IF;
5379 -- Rollback any db changes that might have occurred (currently none).
5380 ROLLBACK TO Crossdock_Supply_sp;
5381 GOTO next_supply;
5382 END IF;
5383 l_progress := '480';
5384
5385 -- 4.3 - Crossdock the demand and supply line records.
5386 IF (l_debug = 1) THEN
5387 print_debug('4.3 - Crossdock the demand and supply line records');
5388 END IF;
5389
5390 -- Convert the WDD ATR qty to the UOM on the supply line. This value should not be zero if
5391 -- we have reached this point. If this was calculated as zero previously in section 2.6,
5392 -- we would have skipped to the next WDD record to crossdock.
5393 -- Also convert the WDD qty to the UOM on the supply line. Since they use the same
5394 -- conversion rate, we just need to retrieve that value once.
5395 -- This is required so we know if the WDD line needs to be split or not. That would depend
5396 -- on the WDD qty, not the WDD ATR qty.
5397 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
5398 l_demand_uom_code, l_supply_uom_code);
5399 IF (l_conversion_rate < 0) THEN
5400 IF (l_debug = 1) THEN
5401 print_debug('4.3 - Error while obtaining UOM conversion rate for WDD qty');
5402 END IF;
5403 -- Rollback any db changes that might have occurred (currently none).
5404 ROLLBACK TO Crossdock_Supply_sp;
5405 GOTO next_supply;
5406 END IF;
5407 -- Round the converted quantity to the standard precision
5408 l_wdd_atr_txn_qty := ROUND(l_conversion_rate * l_demand_atr_qty, l_conversion_precision);
5409 l_wdd_txn_qty := ROUND(l_conversion_rate * l_demand_qty, l_conversion_precision);
5410 IF (l_debug = 1) THEN
5411 print_debug('4.3 - WDD ATR txn qty: => ' || l_wdd_atr_txn_qty || ' ' || l_supply_uom_code);
5412 print_debug('4.3 - WDD txn qty: =====> ' || l_wdd_txn_qty || ' ' || l_supply_uom_code);
5413 END IF;
5414 l_progress := '490';
5415
5416 -- Calculate the Available to Detail quantity.
5417 -- {{
5418 -- Test that the available to detail quantity is calculated properly,
5419 -- i.e. is lower than WDD ATR qty and supply line qty, and is an integer value if
5420 -- UOM integrity = 'Y'. }}
5421 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).uom_integrity_flag = 1) THEN
5422 -- UOM Integrity is 'Yes'
5423 l_atd_qty := LEAST(FLOOR(l_wdd_atr_txn_qty), FLOOR(l_supply_atr_qty));
5424 ELSE
5425 -- UOM Integrity is 'No'
5426 l_atd_qty := LEAST(l_wdd_atr_txn_qty, l_supply_atr_qty);
5427 END IF;
5428 IF (l_debug = 1) THEN
5429 print_debug('4.3 - Available to detail qty: ' || l_atd_qty || ' ' ||
5430 l_supply_uom_code);
5431 END IF;
5432 -- If the ATD qty is 0, then goto the next supply line to crossdock.
5433 -- This is possible if the UOM integrity flag is 'Y' and the resultant quantities
5434 -- were floored to 0.
5435 -- {{
5436 -- Test for ATD qty = 0. This can come about if UOM integrity is Yes and the
5437 -- demand or supply line with available to reserve qty gets floored to 0. }}
5438 IF (l_atd_qty = 0) THEN
5439 IF (l_debug = 1) THEN
5440 print_debug('4.3 - ATD qty = 0 so skip to the next available supply');
5441 END IF;
5442 -- Rollback any db changes that might have occurred (currently none).
5443 ROLLBACK TO Crossdock_Supply_sp;
5444 GOTO next_supply;
5445 END IF;
5446 l_progress := '500';
5447
5448 -- Update the supply line record in the global temp table with the reservable_quantity
5449 -- available after using up ATD qty from it for crossdocking.
5450 -- Do not do this if the supply is of type In Receiving or Internal Requisition.
5451 -- The reason is there can be multiple supply lines of these types in the shopping
5452 -- basket table. However, when we create reservations, they will not be at that
5453 -- line level detail. e.g. Receiving supply reservations will only be at the org/item
5454 -- level while Internal Reqs will be at the Req header/line level (and not the shipment
5455 -- line level). Availability to reserve needs to take the whole set of lines into account
5456 -- so it should be recalculated each time.
5457 IF (l_supply_type_id NOT IN (7, 27)) THEN
5458 IF (l_debug = 1) THEN
5459 print_debug('4.3 - Update the ATR qty for the crossdocked supply line');
5460 END IF;
5461 -- Instead of updating the supply line record here within the supply lines loop,
5462 -- just store the values for the record that needs to be updated. We will do a
5463 -- bulk update outside the loop. In case of exception for the current supply line
5464 -- used for crossdocking, we should remove that record from these tables so the
5465 -- global temp table won't be updated incorrectly. This needs to be only done
5466 -- when we are still staying within the supply lines loop. For exceptions where
5467 -- we go to the next_record, we do not need to remove the current supply line record.
5468 -- The reason is because the bulk update logic after the supply lines loop is skipped.
5469 l_supply_atr_index := l_supply_rowid_tb.COUNT + 1;
5470 l_supply_rowid_tb(l_supply_atr_index) := l_shopping_basket_tb(l_supply_index).ROWID;
5471 l_supply_atr_qty_tb(l_supply_atr_index) := l_supply_atr_qty - l_atd_qty;
5472
5473 -- Commented the below out since we will do a bulk update instead outside
5474 -- the supply lines loop
5475 /*BEGIN
5476 UPDATE wms_xdock_pegging_gtmp
5477 SET reservable_quantity = l_supply_atr_qty - l_atd_qty
5478 WHERE ROWID = l_shopping_basket_tb(l_supply_index).ROWID;
5479 EXCEPTION
5480 WHEN OTHERS THEN
5481 IF (l_debug = 1) THEN
5482 print_debug('4.3 - Could not update the ATR quantity for the supply line');
5483 END IF;
5484 -- If we cannot udpate the qty on the supply line, do not error out.
5485 -- Just go to the next available supply and try to crossdock that.
5486 -- Null out the reservable qty value set in the shopping basket table.
5487 l_shopping_basket_tb(l_supply_index).reservable_quantity := NULL;
5488 -- Rollback any db changes that might have occurred
5489 ROLLBACK TO Crossdock_Supply_sp;
5490 GOTO next_supply;
5491 END;*/
5492 END IF;
5493 l_progress := '510';
5494
5495 -- Convert l_atd_qty to the primary UOM
5496 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
5497 l_supply_uom_code, l_primary_uom_code);
5498 IF (l_conversion_rate < 0) THEN
5499 IF (l_debug = 1) THEN
5500 print_debug('4.3 - Error while obtaining primary UOM conversion rate for ATD qty');
5501 END IF;
5502 -- Rollback any db changes that might have occurred (currently none).
5503 ROLLBACK TO Crossdock_Supply_sp;
5504 -- Remove the supply line from these tables so the ATR qty is not updated
5505 IF (l_supply_atr_index IS NOT NULL) THEN
5506 l_supply_rowid_tb.DELETE(l_supply_atr_index);
5507 l_supply_atr_qty_tb.DELETE(l_supply_atr_index);
5508 END IF;
5509 GOTO next_supply;
5510 END IF;
5511 -- Convert l_atd_qty to the primary UOM
5512 -- Bug 5608611: Use quantity from demand document where possible
5513 IF (l_atd_qty = l_wdd_atr_txn_qty AND l_demand_uom_code = l_primary_uom_code) THEN
5514 l_atd_prim_qty := l_demand_atr_qty;
5515 ELSE
5516 -- Round the converted quantity to the standard precision
5517 l_atd_prim_qty := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
5518 END IF;
5519 IF (l_debug = 1) THEN
5520 print_debug('4.3 - ATD qty in primary UOM: => ' || l_atd_prim_qty || ' ' ||
5521 l_primary_uom_code);
5522 END IF;
5523 l_progress := '520';
5524
5525 -- Store the original WDD values in case of rollback where we need
5526 -- to clean up the local PLSQL data structures
5527 l_orig_wdd_values_rec.requested_quantity :=
5528 p_wsh_release_table(l_wdd_index).requested_quantity;
5529 l_orig_wdd_values_rec.requested_quantity2 :=
5530 p_wsh_release_table(l_wdd_index).requested_quantity2;
5531 l_orig_wdd_values_rec.released_status :=
5532 p_wsh_release_table(l_wdd_index).released_status;
5533 l_orig_wdd_values_rec.move_order_line_id :=
5534 p_wsh_release_table(l_wdd_index).move_order_line_id;
5535
5536 -- Crossdock the WDD record, splitting it if necessary.
5537 IF (l_debug = 1) THEN
5538 print_debug('4.3 - Call the Crossdock_WDD API to crossdock/split the WDD');
5539 END IF;
5540 Crossdock_WDD
5541 (p_log_prefix => '4.3 - ',
5542 p_crossdock_type => G_CRT_TYPE_PLAN,
5543 p_batch_id => p_batch_id,
5544 p_wsh_release_table => p_wsh_release_table,
5545 p_trolin_delivery_ids => p_trolin_delivery_ids,
5546 p_del_detail_id => p_del_detail_id,
5547 l_wdd_index => l_wdd_index,
5548 l_debug => l_debug,
5549 l_inventory_item_id => l_inventory_item_id,
5550 l_wdd_txn_qty => l_wdd_txn_qty,
5551 l_atd_qty => l_atd_qty,
5552 l_atd_wdd_qty => l_atd_wdd_qty,
5553 l_atd_wdd_qty2 => l_atd_wdd_qty2,
5554 l_supply_uom_code => l_supply_uom_code,
5555 l_demand_uom_code => l_demand_uom_code,
5556 l_demand_uom_code2 => l_demand_uom_code2,
5557 l_conversion_rate => l_conversion_rate,
5558 l_conversion_precision => l_conversion_precision,
5559 l_demand_line_detail_id => l_demand_line_detail_id,
5560 l_index => l_index,
5561 l_detail_id_tab => l_detail_id_tab,
5562 l_action_prms => l_action_prms,
5563 l_action_out_rec => l_action_out_rec,
5564 l_split_wdd_id => l_split_wdd_id,
5565 l_detail_info_tab => l_detail_info_tab,
5566 l_in_rec => l_in_rec,
5567 l_out_rec => l_out_rec,
5568 l_mol_line_id => l_mol_line_id,
5569 l_split_wdd_index => l_split_wdd_index,
5570 l_split_delivery_index => l_split_delivery_index,
5571 l_split_wdd_rel_rec => l_split_wdd_rel_rec,
5572 l_allocation_method => l_allocation_method,
5573 l_demand_qty => l_demand_qty,
5574 l_demand_qty2 => l_demand_qty2,
5575 l_demand_atr_qty => l_demand_atr_qty,
5576 l_xdocked_wdd_index => l_xdocked_wdd_index,
5577 l_supply_type_id => l_supply_type_id,
5578 x_return_status => x_return_status,
5579 x_msg_count => x_msg_count,
5580 x_msg_data => x_msg_data,
5581 x_error_code => l_error_code
5582 );
5583
5584 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
5585 IF (l_debug = 1) THEN
5586 print_debug('4.3 - Error returned from Crossdock_WDD API: '
5587 || x_return_status);
5588 END IF;
5589 --RAISE fnd_api.g_exc_error;
5590 -- If an exception occurs while modifying a database record, rollback the changes
5591 -- and just go to the next WDD record or supply to crossdock.
5592 ROLLBACK TO Crossdock_Supply_sp;
5593 -- We need to also rollback changes done to local PLSQL data structures
5594 IF (l_split_wdd_index IS NOT NULL) THEN
5595 p_wsh_release_table.DELETE(l_split_wdd_index);
5596 END IF;
5597 IF (l_split_delivery_index IS NOT NULL) THEN
5598 p_del_detail_id.DELETE(l_split_delivery_index);
5599 p_trolin_delivery_ids.DELETE(l_split_delivery_index);
5600 END IF;
5601 IF (l_xdocked_wdd_index IS NOT NULL) THEN
5602 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
5603 END IF;
5604 p_wsh_release_table(l_wdd_index).requested_quantity :=
5605 l_orig_wdd_values_rec.requested_quantity;
5606 p_wsh_release_table(l_wdd_index).requested_quantity2 :=
5607 l_orig_wdd_values_rec.requested_quantity2;
5608 p_wsh_release_table(l_wdd_index).released_status :=
5609 l_orig_wdd_values_rec.released_status;
5610 p_wsh_release_table(l_wdd_index).move_order_line_id :=
5611 l_orig_wdd_values_rec.move_order_line_id;
5612
5613 -- Skip to the next WDD record or supply to crossdock
5614 IF (l_error_code = 'UOM') THEN
5615 GOTO next_supply;
5616 ELSE -- l_error_code = 'DB'
5617 GOTO next_record;
5618 END IF;
5619 ELSE
5620 IF (l_debug = 1) THEN
5621 print_debug('4.3 - Successfully crossdocked/split the WDD record');
5622 END IF;
5623 END IF;
5624 l_progress := '530';
5625
5626
5627 -- Crossdock and split the MOL supply line if necessary
5628 IF (l_mol_line_id IS NOT NULL) THEN
5629 IF (l_debug = 1) THEN
5630 print_debug('4.3 - Call the Crossdock_MOL API to crossdock/split the MOL: '
5631 || l_mol_line_id);
5632 END IF;
5633 Crossdock_MOL
5634 (p_log_prefix => '4.3 - ',
5635 p_crossdock_type => G_CRT_TYPE_PLAN,
5636 l_debug => l_debug,
5637 l_inventory_item_id => l_inventory_item_id,
5638 l_mol_qty => l_mol_qty,
5639 l_mol_qty2 => l_mol_qty2,
5640 l_atd_qty => l_atd_qty,
5641 l_atd_mol_qty2 => l_atd_mol_qty2,
5642 l_supply_uom_code => l_supply_uom_code,
5643 l_mol_uom_code2 => l_mol_uom_code2,
5644 l_conversion_rate => l_conversion_rate,
5645 l_conversion_precision => l_conversion_precision,
5646 l_mol_prim_qty => l_mol_prim_qty,
5647 l_atd_prim_qty => l_atd_prim_qty,
5648 l_split_wdd_id => l_split_wdd_id,
5649 l_mol_header_id => l_mol_header_id,
5650 l_mol_line_id => l_mol_line_id,
5651 l_supply_atr_qty => l_supply_atr_qty,
5652 l_demand_type_id => l_demand_type_id,
5653 l_wip_entity_id => l_wip_entity_id,
5654 l_operation_seq_num => l_operation_seq_num,
5655 l_repetitive_schedule_id => l_repetitive_schedule_id,
5656 l_wip_supply_type => l_wip_supply_type,
5657 l_xdocked_wdd_index => l_xdocked_wdd_index,
5658 l_detail_info_tab => l_detail_info_tab,
5659 l_wdd_index => l_wdd_index,
5660 l_split_wdd_index => l_split_wdd_index,
5661 p_wsh_release_table => p_wsh_release_table,
5662 l_supply_type_id => l_supply_type_id,
5663 x_return_status => x_return_status,
5664 x_msg_count => x_msg_count,
5665 x_msg_data => x_msg_data,
5666 x_error_code => l_error_code
5667 );
5668
5669 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
5670 IF (l_debug = 1) THEN
5671 print_debug('4.3 - Error returned from Crossdock_MOL API: '
5672 || x_return_status);
5673 END IF;
5674 --RAISE fnd_api.g_exc_error;
5675 -- If an exception occurs while modifying a database record, rollback the changes
5676 -- and just go to the next WDD record or supply to crossdock.
5677 ROLLBACK TO Crossdock_Supply_sp;
5678 -- We need to also rollback changes done to local PLSQL data structures
5679 IF (l_split_wdd_index IS NOT NULL) THEN
5680 p_wsh_release_table.DELETE(l_split_wdd_index);
5681 END IF;
5682 IF (l_split_delivery_index IS NOT NULL) THEN
5683 p_del_detail_id.DELETE(l_split_delivery_index);
5684 p_trolin_delivery_ids.DELETE(l_split_delivery_index);
5685 END IF;
5686 IF (l_xdocked_wdd_index IS NOT NULL) THEN
5687 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
5688 END IF;
5689 p_wsh_release_table(l_wdd_index).requested_quantity :=
5690 l_orig_wdd_values_rec.requested_quantity;
5691 p_wsh_release_table(l_wdd_index).requested_quantity2 :=
5692 l_orig_wdd_values_rec.requested_quantity2;
5693 p_wsh_release_table(l_wdd_index).released_status :=
5694 l_orig_wdd_values_rec.released_status;
5695 p_wsh_release_table(l_wdd_index).move_order_line_id :=
5696 l_orig_wdd_values_rec.move_order_line_id;
5697
5698 -- Skip to the next WDD record or supply to crossdock
5699 IF (l_error_code = 'UOM') THEN
5700 GOTO next_supply;
5701 ELSE -- l_error_code = 'DB'
5702 GOTO next_record;
5703 END IF;
5704 ELSE
5705 IF (l_debug = 1) THEN
5706 print_debug('4.3 - Successfully crossdocked/split the MOL record');
5707 END IF;
5708 END IF;
5709
5710 -- Store this LPN in the crossdocked LPNs table so we can call the pre_generate
5711 -- API later on for the entire set of LPN's instead of once for each MOL that
5712 -- is crossdocked.
5713 IF (NOT l_crossdocked_lpns_tb.EXISTS(l_mol_lpn_id)) THEN
5714 l_crossdocked_lpns_tb(l_mol_lpn_id) := TRUE;
5715 IF (l_debug = 1) THEN
5716 print_debug('4.3 - Successfully stored the crossdocked LPN: ' || l_mol_lpn_id);
5717 END IF;
5718 END IF;
5719 l_progress := '540';
5720
5721 END IF; -- End of l_mol_line_id IS NOT NULL for receiving supply type
5722
5723
5724 -- 4.4 - Create a crossdocked reservation tying the demand to the supply line.
5725 -- Calculate the supply expected time
5726 IF (l_debug = 1) THEN
5727 print_debug('4.4 - Create a crossdock reservation peg to tie the demand to the supply');
5728 END IF;
5729 IF (l_shopping_basket_tb(l_supply_index).dock_start_time IS NOT NULL) THEN
5730 -- Get the supply dock schedule method to decide which
5731 -- dock appointment time to use as the supply expected time
5732 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).supply_schedule_method IS NULL OR
5733 g_crossdock_criteria_tb(l_crossdock_criteria_id).supply_schedule_method = G_APPT_MEAN_TIME) THEN
5734 l_supply_expected_time := l_shopping_basket_tb(l_supply_index).dock_mean_time;
5735 ELSIF (g_crossdock_criteria_tb(l_crossdock_criteria_id).supply_schedule_method = G_APPT_START_TIME) THEN
5736 l_supply_expected_time := l_shopping_basket_tb(l_supply_index).dock_start_time;
5737 ELSIF (g_crossdock_criteria_tb(l_crossdock_criteria_id).supply_schedule_method = G_APPT_END_TIME) THEN
5738 l_supply_expected_time := l_shopping_basket_tb(l_supply_index).dock_end_time;
5739 END IF;
5740 ELSE
5741 l_supply_expected_time := l_shopping_basket_tb(l_supply_index).expected_time;
5742 END IF;
5743 IF (l_debug = 1) THEN
5744 print_debug('4.4 - Supply line expected time: ' ||
5745 TO_CHAR(l_supply_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
5746 END IF;
5747
5748 -- Call the Create_RSV API to create a crossdock reservation
5749 IF (l_debug = 1) THEN
5750 print_debug('4.4 - Call the Create_RSV API to create a crossdock reservation');
5751 END IF;
5752 Create_RSV
5753 (p_log_prefix => '4.4 - ',
5754 p_crossdock_type => G_CRT_TYPE_PLAN,
5755 l_debug => l_debug,
5756 l_organization_id => l_organization_id,
5757 l_inventory_item_id => l_inventory_item_id,
5758 l_demand_type_id => l_demand_type_id,
5759 l_demand_so_header_id => l_demand_so_header_id,
5760 l_demand_line_id => l_demand_line_id,
5761 l_split_wdd_id => l_split_wdd_id,
5762 l_primary_uom_code => l_primary_uom_code,
5763 l_demand_uom_code2 => l_demand_uom_code2,
5764 l_supply_uom_code => l_supply_uom_code,
5765 l_atd_qty => l_atd_qty,
5766 l_atd_prim_qty => l_atd_prim_qty,
5767 l_atd_wdd_qty2 => l_atd_wdd_qty2,
5768 l_supply_type_id => l_supply_type_id,
5769 l_supply_header_id => l_supply_header_id,
5770 l_supply_line_id => l_supply_line_id,
5771 l_supply_line_detail_id => l_supply_line_detail_id,
5772 l_crossdock_criteria_id => l_crossdock_criteria_id,
5773 l_supply_expected_time => l_supply_expected_time,
5774 l_demand_expected_time => l_demand_expected_time,
5775 l_demand_project_id => l_demand_project_id,
5776 l_demand_task_id => l_demand_task_id,
5777 l_original_rsv_rec => l_original_rsv_rec,
5778 l_original_serial_number => l_original_serial_number,
5779 l_to_serial_number => l_to_serial_number,
5780 l_quantity_reserved => l_quantity_reserved,
5781 l_quantity_reserved2 => l_quantity_reserved2,
5782 l_rsv_id => l_rsv_id,
5783 x_return_status => x_return_status,
5784 x_msg_count => x_msg_count,
5785 x_msg_data => x_msg_data
5786 );
5787
5788 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
5789 IF (l_debug = 1) THEN
5790 print_debug('4.4 - Error returned from create_reservation API: '
5791 || x_return_status);
5792 END IF;
5793 --RAISE fnd_api.g_exc_error;
5794 -- If an exception occurs while modifying a database record, rollback the changes
5795 -- and just go to the next WDD record to crossdock.
5796 ROLLBACK TO Crossdock_Supply_sp;
5797 -- We need to also rollback changes done to local PLSQL data structures
5798 IF (l_split_wdd_index IS NOT NULL) THEN
5799 p_wsh_release_table.DELETE(l_split_wdd_index);
5800 END IF;
5801 IF (l_split_delivery_index IS NOT NULL) THEN
5802 p_del_detail_id.DELETE(l_split_delivery_index);
5803 p_trolin_delivery_ids.DELETE(l_split_delivery_index);
5804 END IF;
5805 IF (l_xdocked_wdd_index IS NOT NULL) THEN
5806 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
5807 END IF;
5808 p_wsh_release_table(l_wdd_index).requested_quantity :=
5809 l_orig_wdd_values_rec.requested_quantity;
5810 p_wsh_release_table(l_wdd_index).requested_quantity2 :=
5811 l_orig_wdd_values_rec.requested_quantity2;
5812 p_wsh_release_table(l_wdd_index).released_status :=
5813 l_orig_wdd_values_rec.released_status;
5814 p_wsh_release_table(l_wdd_index).move_order_line_id :=
5815 l_orig_wdd_values_rec.move_order_line_id;
5816
5817 -- Skip to the next WDD record to crossdock
5818 GOTO next_record;
5819 ELSE
5820 IF (l_debug = 1) THEN
5821 print_debug('4.4 - Successfully created a crossdock RSV record');
5822 END IF;
5823 END IF;
5824 l_progress := '550';
5825
5826
5827 -- Exit out of valid supply lines loop if the WDD line has been fully crossdocked.
5828 -- There is no need to consider anymore supply lines for crossdocking.
5829 IF (p_wsh_release_table(l_wdd_index).released_status = 'S') THEN
5830 EXIT;
5831 END IF;
5832
5833 <<next_supply>>
5834 -- Exit when all supply lines have been considered
5835 EXIT WHEN l_supply_index = l_shopping_basket_tb.LAST;
5836 l_supply_index := l_shopping_basket_tb.NEXT(l_supply_index);
5837 END LOOP; -- End looping through supply lines in shopping basket table
5838 l_progress := '560';
5839
5840 -- 4.5 - Bulk update the reservable_quantity for all crossdocked supply lines in
5841 -- global temp table, wms_xdock_pegging_gtmp.
5842 -- {{
5843 -- Test that the supply lines used in wms_xdock_pegging_gtmp have the reservable
5844 -- quantities updated properly. In this way, later demand lines to be crossdocked
5845 -- can just refer to this quantity instead of calling the availability APIs again. }}
5846 IF (l_supply_rowid_tb.COUNT > 0) THEN
5847 IF (l_debug = 1) THEN
5848 print_debug('4.5 - For all crossdocked supply lines, update the ATR qty in the temp table');
5849 END IF;
5850
5851 BEGIN
5852 FORALL i IN 1 .. l_supply_rowid_tb.COUNT
5853 UPDATE wms_xdock_pegging_gtmp
5854 SET reservable_quantity = l_supply_atr_qty_tb(i)
5855 WHERE ROWID = l_supply_rowid_tb(i);
5856 EXCEPTION
5857 WHEN OTHERS THEN
5858 IF (l_debug = 1) THEN
5859 print_debug('4.5 - Could not update the ATR qty for the crossdocked supply lines!');
5860 END IF;
5861 -- If an exception occurs while performing this bulk update, raise an exception.
5862 -- This error should not occur but if it does, we should stop the crossdock pegging
5863 -- process.
5864 RAISE fnd_api.g_exc_error;
5865 END;
5866 IF (l_debug = 1) THEN
5867 print_debug('4.5 - Successfully updated the ATR qty for ' || l_supply_rowid_tb.COUNT
5868 || ' (non RCV or Int Req) supply lines ');
5869 END IF;
5870 END IF;
5871 l_progress := '570';
5872
5873
5874 <<next_record>>
5875 EXIT WHEN l_wdd_index = p_wsh_release_table.LAST;
5876 l_wdd_index := p_wsh_release_table.NEXT(l_wdd_index);
5877 END LOOP; -- End looping through records in p_wsh_release_table
5878 l_progress := '580';
5879
5880 -- Section 5: Post crossdocking logic
5881 -- 5.1 - For all crossdocked WDD lines, call the shipping API to update the
5882 -- released_status and move_order_line_id columns.
5883 -- 5.2 - For all of the MOL's and the corresponding LPN's that were crossdocked,
5884 -- call the pre_generate API to create the crossdock tasks.
5885 -- 5.3 - If allocation method is 'C', Crossdock Only or 'X', Prioritize Crossdock,
5886 -- insert all crossdocked WDD lines into the delivery IN OUT tables:
5887 -- p_trolin_delivery_ids and p_del_detail_id.
5888 -- 5.4 - If allocation method is 'N', Prioritize Inventory, backorder all of the
5889 -- WDD lines that could not be allocated. Remove those entries from the
5890 -- delivery IN OUT tables: p_trolin_delivery_ids and p_del_detail_id.
5891 -- 5.5 - Bug 5194761: clear the temp table wms_xdock_pegging_gtmp
5892
5893 -- 5.1 - For all crossdocked WDD lines, call the shipping API to update the
5894 -- released_status and move_order_line_id columns.
5895 -- {{
5896 -- Make sure the shipping API to update crossdocked WDD lines is only called if necessary
5897 -- and properly updates the WDD records. }}
5898 IF (l_detail_info_tab.COUNT > 0) THEN
5899 IF (l_debug = 1) THEN
5900 print_debug('5.1 - Call the Create_Update_Delivery_Detail API for ' ||
5901 l_detail_info_tab.COUNT || ' crossdocked WDD records');
5902 END IF;
5903
5904 l_in_rec.caller := 'WMS_XDOCK_PEGGING_PUB';
5905 l_in_rec.action_code := 'UPDATE';
5906
5907 WSH_INTERFACE_EXT_GRP.Create_Update_Delivery_Detail
5908 (p_api_version_number => 1.0,
5909 p_init_msg_list => fnd_api.g_false,
5910 p_commit => fnd_api.g_false,
5911 x_return_status => x_return_status,
5912 x_msg_count => x_msg_count,
5913 x_msg_data => x_msg_data,
5914 p_detail_info_tab => l_detail_info_tab,
5915 p_in_rec => l_in_rec,
5916 x_out_rec => l_out_rec
5917 );
5918
5919 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
5920 IF (l_debug = 1) THEN
5921 print_debug('5.1 - Error returned from Create_Update_Delivery_Detail API: '
5922 || x_return_status);
5923 END IF;
5924 RAISE FND_API.G_EXC_ERROR;
5925 ELSE
5926 IF (l_debug = 1) THEN
5927 print_debug('5.1 - Successfully updated the crossdocked WDD records');
5928 END IF;
5929 END IF;
5930 END IF;
5931
5932 -- 5.2 - For all of the MOL's and the corresponding LPN's that were crossdocked,
5933 -- call the pre_generate API to create the crossdock tasks.
5934 -- {{
5935 -- Test calling the pre_generate API for crossdocked MOL supply lines used.
5936 -- Make sure the staging lane is stamped properly onto the MOL, operation plans and
5937 -- tasks are generated properly. }}
5938 l_lpn_index := l_crossdocked_lpns_tb.FIRST;
5939
5940 IF (l_crossdocked_lpns_tb.COUNT > 0) THEN
5941 LOOP
5942 -- Call the pre_generate API for the current crossdocked LPN
5943 IF (l_debug = 1) THEN
5944 print_debug('5.2 - Call the pre_generate API for LPN: ' || l_lpn_index);
5945 END IF;
5946 wms_putaway_suggestions.pre_generate
5947 (x_return_status => x_return_status,
5948 x_msg_count => x_msg_count,
5949 x_msg_data => x_msg_data,
5950 x_partial_success => l_partial_success,
5951 x_lpn_line_error_tbl => l_lpn_line_error_tbl,
5952 p_from_conc_pgm => 'N',
5953 p_commit => 'N',
5954 p_organization_id => l_organization_id,
5955 p_lpn_id => l_lpn_index);
5956
5957 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
5958 IF (l_debug = 1) THEN
5959 print_debug('5.2 - Error returned from pre_generate API: ' || l_lpn_index
5960 || ': ' || x_return_status);
5961 END IF;
5962 --RAISE fnd_api.g_exc_error;
5963 -- No need to throw an exception if the pre_generate API errors out.
5964 END IF;
5965
5966 EXIT WHEN l_lpn_index = l_crossdocked_lpns_tb.LAST;
5967 l_lpn_index := l_crossdocked_lpns_tb.NEXT(l_lpn_index);
5968 END LOOP; -- End looping through crossdocked LPN's to call the pre_generate API
5969 IF (l_debug = 1) THEN
5970 print_debug('5.2 - Finished calling pre_generate API for all crossdocked LPNs: ' ||
5971 l_crossdocked_lpns_tb.COUNT);
5972 END IF;
5973 l_progress := '590';
5974 END IF;
5975
5976 -- 5.3 - If allocation method is 'C', Crossdock Only or 'X', Prioritize Crossdock,
5977 -- insert all crossdocked WDD lines into the delivery IN OUT tables:
5978 -- p_trolin_delivery_ids and p_del_detail_id.
5979 -- {{
5980 -- Test for allocation method of Crossdock only or Prioritize Crossdock that crossdocked
5981 -- WDD lines are inserted into the delivery tables so shipping can pick them up and autocreate
5982 -- deliveries for them (if this option is set on the pick release form). }}
5983 IF (l_allocation_method = G_CROSSDOCK_ONLY OR
5984 l_allocation_method = G_PRIORITIZE_CROSSDOCK) THEN
5985 -- Initialize the necessary variables
5986 l_unable_to_crossdock := FALSE;
5987 l_wdd_index := p_wsh_release_table.FIRST;
5988 LOOP
5989 IF (p_wsh_release_table.COUNT = 0) THEN
5990 EXIT;
5991 END IF;
5992
5993 -- Insert the crossdocked WDD lines into the delivery tables
5994 IF (p_wsh_release_table(l_wdd_index).released_status = 'S') THEN
5995 l_index := NVL(p_del_detail_id.LAST, 0) + 1;
5996 p_del_detail_id(l_index) := p_wsh_release_table(l_wdd_index).delivery_detail_id;
5997 p_trolin_delivery_ids(l_index) := p_wsh_release_table(l_wdd_index).delivery_id;
5998 ELSIF (p_wsh_release_table(l_wdd_index).released_status IN ('R','B')) THEN
5999 -- For Allocation method of 'Crossdock Only', if any line is not able
6000 -- to be crossdocked, return a warning status to Shipping to alert the user.
6001 IF (l_allocation_method = G_CROSSDOCK_ONLY) THEN
6002 l_unable_to_crossdock := TRUE;
6003 END IF;
6004 END IF;
6005
6006 EXIT WHEN l_wdd_index = p_wsh_release_table.LAST;
6007 l_wdd_index := p_wsh_release_table.NEXT(l_wdd_index);
6008 END LOOP;
6009 IF (l_debug = 1) THEN
6010 print_debug('5.3 - Successfully inserted ' || p_del_detail_id.COUNT ||
6011 ' crossdocked WDD lines into delivery tables');
6012 END IF;
6013 END IF;
6014 l_progress := '600';
6015
6016 -- 5.4 - If allocation method is 'N' (Prioritize Inventory), backorder all of the
6017 -- WDD lines that could not be allocated. Remove those entries from the
6018 -- delivery IN OUT tables: p_trolin_delivery_ids and p_del_detail_id.
6019 -- UPDATE: No need to remove the backordered lines from the delivery tables.
6020 -- This is because shipping does not pass anything in those tables. They expect
6021 -- us to populate those tables with crossdocked WDD lines only.
6022 -- {{
6023 -- Test that for allocation method of Prioritize Inventory, if a line does not get
6024 -- allocated through inventory or crossdock, it should be backordered. }}
6025 IF (l_allocation_method = G_PRIORITIZE_INVENTORY) THEN
6026 -- Initialize the variables
6027 l_wdd_index := p_wsh_release_table.FIRST;
6028 l_index := 1;
6029 l_shipping_attr.DELETE;
6030 l_backordered_wdd_lines := 0;
6031 LOOP
6032 IF (p_wsh_release_table.COUNT = 0) THEN
6033 EXIT;
6034 END IF;
6035
6036 -- Backorder the WDD lines that could not be allocated
6037 -- Bug 5220216
6038 -- For non-reservable item, shipping still calls the pick
6039 -- release API. As a result for prioritize Inventory case
6040 -- this API gets called and if there was a non-reservable
6041 -- item it will get back ordered. Excluding those WDDs.
6042 IF (p_wsh_release_table(l_wdd_index).released_status IN ('R', 'B'))
6043 AND (l_item_params_tb(p_wsh_release_table(l_wdd_index).inventory_item_id).reservable_type <> 2)
6044 THEN
6045 l_shipping_attr(l_index).source_header_id := p_wsh_release_table(l_wdd_index).source_header_id;
6046 l_shipping_attr(l_index).source_line_id := p_wsh_release_table(l_wdd_index).source_line_id;
6047 l_shipping_attr(l_index).ship_from_org_id := p_wsh_release_table(l_wdd_index).organization_id;
6048 l_shipping_attr(l_index).released_status := p_wsh_release_table(l_wdd_index).released_status;
6049 l_shipping_attr(l_index).delivery_detail_id := p_wsh_release_table(l_wdd_index).delivery_detail_id;
6050 l_shipping_attr(l_index).action_flag := 'B';
6051 l_shipping_attr(l_index).cycle_count_quantity := p_wsh_release_table(l_wdd_index).requested_quantity;
6052 l_shipping_attr(l_index).cycle_count_quantity2 := p_wsh_release_table(l_wdd_index).requested_quantity2;
6053 l_shipping_attr(l_index).subinventory := p_wsh_release_table(l_wdd_index).from_sub;
6054 l_shipping_attr(l_index).locator_id := NULL;
6055
6056 -- Increment the index storing the backordered WDD records
6057 l_index := l_index + 1;
6058
6059 -- Store the backordered WDD line in the table so it can
6060 -- be removed from the delivery IN OUT tables.
6061 -- No need to do this anymore since Shipping does not pass in any values in the
6062 -- IN OUT delivery tables. Instead just set the released status of the backordered
6063 -- WDD line in the release table to 'B'. Shipping can make use of this information
6064 -- later on if they do not want to auto-create deliveries for backordered lines.
6065 --l_backordered_wdd_tbl(p_wsh_release_table(l_wdd_index).delivery_detail_id) := TRUE;
6066 l_backordered_wdd_lines := l_backordered_wdd_lines + 1;
6067 p_wsh_release_table(l_wdd_index).released_status := 'B';
6068 END IF;
6069
6070 EXIT WHEN l_wdd_index = p_wsh_release_table.LAST;
6071 l_wdd_index := p_wsh_release_table.NEXT(l_wdd_index);
6072 END LOOP;
6073
6074 -- Call the Shipping API to backorder the WDD lines
6075 IF (l_shipping_attr.COUNT > 0) THEN
6076 IF (l_debug = 1) THEN
6077 print_debug('5.4 - Call the Update_Shipping_Attributes API to backorder ' ||
6078 l_shipping_attr.COUNT || ' WDD records');
6079 END IF;
6080 WSH_INTERFACE.Update_Shipping_Attributes
6081 (p_source_code => 'INV',
6082 p_changed_attributes => l_shipping_attr,
6083 x_return_status => x_return_status
6084 );
6085 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
6086 IF (l_debug = 1) THEN
6087 print_debug('5.4 - Error returned from Update_Shipping_Attributes API: '
6088 || x_return_status);
6089 END IF;
6090 RAISE FND_API.G_EXC_ERROR;
6091 END IF;
6092 END IF;
6093
6094 -- Loop through table p_del_detail_id. If that WDD is backordered (value exists in
6095 -- l_backordered_wdd_tbl), then delete that entry from p_del_detail_id and the corresponding
6096 -- one in p_trolin_delivery_ids.
6097 -- UPDATE: No need to do the following logic anymore since Shipping does not populate the
6098 -- delivery tables prior to calling the crossdock/inventory pick release APIs.
6099 -- {{
6100 -- Backordered WDD lines should have their records removed from the shipping delivery
6101 -- tables so the auto-create deliveries process does not pick them up. }}
6102 /*l_index := p_del_detail_id.FIRST;
6103 l_next_index := p_del_detail_id.FIRST;
6104 LOOP
6105 l_index := l_next_index;
6106 l_next_index := p_del_detail_id.NEXT(l_next_index);
6107 -- Exit out of loop when l_index is null, meaning we have
6108 -- reached the last entry in the table.
6109 EXIT WHEN l_index IS NULL;
6110
6111 IF (l_backordered_wdd_tbl.EXISTS(p_del_detail_id(l_index))) THEN
6112 p_del_detail_id.DELETE(l_index);
6113 p_trolin_delivery_ids.DELETE(l_index);
6114 END IF;
6115 END LOOP;*/
6116 IF (l_debug = 1) THEN
6117 print_debug('5.4 - Finished backordering ' || l_backordered_wdd_lines || ' WDD lines');
6118 END IF;
6119 END IF; -- End of: IF (l_allocation_method = G_PRIORITIZE_INVENTORY) THEN
6120 l_progress := '610';
6121
6122 -- 5.5 - Bug 5194761: delete records from wms_xdock_pegging_gtmp
6123 DELETE wms_xdock_pegging_gtmp;
6124 IF (l_debug = 1) AND SQL%FOUND THEN
6125 print_debug('5.5 - Cleared the temp table wms_xdock_pegging_gtmp');
6126 END IF;
6127
6128 -- Standard call to commit
6129 IF fnd_api.To_Boolean(p_commit) THEN
6130 COMMIT;
6131 END IF;
6132 l_progress := '620';
6133
6134 -- If we have reached this point, the return status should be set to success.
6135 -- This variable is reused each time we call another API but we try to continue with the
6136 -- flow and raise an exception only when absolutely necessary. Since this is a planning
6137 -- and pegging API, if exceptions occur, we should just not peg anything instead of throwing
6138 -- errors. Addendum to this is for allocation method of 'Crossdock Only', if any of the
6139 -- lines could not be crossdocked, return a 'Warning' status. This is so Shipping can alert
6140 -- the user that some lines were not able to be allocated through crossdock. The other
6141 -- allocation methods are taken care of when backordering unallocated WDD lines.
6142 IF (l_allocation_method = G_CROSSDOCK_ONLY AND l_unable_to_crossdock) THEN
6143 x_return_status := WSH_UTIL_CORE.G_RET_STS_WARNING;
6144 ELSE
6145 x_return_status := fnd_api.g_ret_sts_success;
6146 END IF;
6147 l_progress := '630';
6148
6149 IF (l_debug = 1) THEN
6150 print_debug('***End of Planned_Cross_Dock***');
6151 END IF;
6152
6153 -- Stop the profiler
6154 -- dbms_profiler.stop_profiler;
6155
6156 EXCEPTION
6157 WHEN FND_API.G_EXC_ERROR THEN
6158 ROLLBACK TO Planned_Cross_Dock_sp;
6159 x_return_status := fnd_api.g_ret_sts_error;
6160 fnd_msg_pub.count_and_get(p_count => x_msg_count,
6161 p_data => x_msg_data);
6162 IF (l_debug = 1) THEN
6163 print_debug('Exiting Planned_Cross_Dock - Execution error: ' ||
6164 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
6165 END IF;
6166
6167 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
6168 ROLLBACK TO Planned_Cross_Dock_sp;
6169 x_return_status := fnd_api.g_ret_sts_unexp_error;
6170 fnd_msg_pub.count_and_get(p_count => x_msg_count,
6171 p_data => x_msg_data);
6172 IF (l_debug = 1) THEN
6173 print_debug('Exiting Planned_Cross_Dock - Unexpected error: ' ||
6174 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
6175 END IF;
6176
6177 WHEN OTHERS THEN
6178 ROLLBACK TO Planned_Cross_Dock_sp;
6179 x_return_status := fnd_api.g_ret_sts_unexp_error;
6180 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
6181 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
6182 END IF;
6183 fnd_msg_pub.count_and_get(p_count => x_msg_count,
6184 p_data => x_msg_data);
6185 IF (l_debug = 1) THEN
6186 print_debug('Exiting Planned_Cross_Dock - Others exception: ' ||
6187 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
6188 END IF;
6189
6190 END Planned_Cross_Dock;
6191 -- {{ }}
6192 -- {{******************** End Planned_Cross_Dock ********************}}
6193 -- {{ }}
6194
6195
6196 -- {{ }}
6197 -- {{******************** Procedure Opportunistic_Cross_Dock ********************}}
6198 PROCEDURE Opportunistic_Cross_Dock
6199 (p_organization_id IN NUMBER,
6200 p_move_order_line_id IN NUMBER,
6201 p_crossdock_criterion_id IN NUMBER,
6202 x_return_status OUT NOCOPY VARCHAR2,
6203 x_msg_count OUT NOCOPY NUMBER,
6204 x_msg_data OUT NOCOPY VARCHAR2)
6205 IS
6206 l_api_name CONSTANT VARCHAR2(30) := 'Opportunistic_Cross_Dock';
6207 l_progress VARCHAR2(10);
6208 l_debug NUMBER := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
6209
6210 -- This variable is used to indicate if the custom APIs were used.
6211 l_api_is_implemented BOOLEAN;
6212
6213 -- This variable stores the PJM org parameter to allow cross project allocation
6214 -- when matching supply to demand lines for crossdocking. Possible values are 'Y' or 'N'.
6215 l_allow_cross_proj_issues VARCHAR2(1);
6216
6217 -- This variable indicates if the org is PJM enabled or not. 1 = Yes, 2 = No
6218 l_project_ref_enabled NUMBER;
6219
6220 -- This boolean variable indicates if the org is a WMS org or not.
6221 l_wms_org_flag BOOLEAN;
6222
6223 -- These variable will store necessary info for the item being crossdocked
6224 -- from the MOL inputted.
6225 l_inventory_item_id NUMBER;
6226 l_primary_uom_code VARCHAR2(3);
6227 l_reservable_type NUMBER;
6228 l_lot_control_code NUMBER;
6229 l_lot_divisible_flag VARCHAR2(1);
6230
6231 -- Local variables for the input org and crossdock criteria.
6232 -- Needed so code from Planned Crossdock case can be reused.
6233 l_organization_id NUMBER;
6234 l_crossdock_criteria_id NUMBER;
6235
6236 -- Cursor to retrieve valid scheduled Sales Order demand lines
6237 CURSOR SO_scheduled_lines(p_project_id NUMBER, p_task_id NUMBER) IS
6238 SELECT
6239 inv_salesorder.get_salesorder_for_oeheader(wdd.source_header_id) AS header_id,
6240 wdd.source_line_id AS line_id,
6241 wdd.delivery_detail_id AS line_detail_id,
6242 wdd.requested_quantity AS quantity,
6243 wdd.requested_quantity_uom AS uom_code,
6244 wdd.requested_quantity2 AS secondary_quantity,
6245 wdd.requested_quantity_uom2 AS secondary_uom_code,
6246 wdd.project_id AS project_id,
6247 wdd.task_id AS task_id,
6248 NULL AS wip_supply_type
6249 FROM wsh_delivery_details wdd, oe_order_lines_all ool
6250 WHERE wdd.organization_id = l_organization_id
6251 AND wdd.inventory_item_id = l_inventory_item_id
6252 AND wdd.released_status = 'R'
6253 AND wdd.source_code = 'OE'
6254 AND wdd.requested_quantity > 0
6255 AND wdd.source_line_id = ool.line_id
6256 AND NVL(ool.source_document_type_id, -999) <> 10
6257 AND ool.booked_flag = 'Y'
6258 AND ool.open_flag = 'Y'
6259 AND NOT EXISTS (SELECT 'Drop Ship'
6260 FROM oe_drop_ship_sources odss
6261 WHERE odss.header_id = ool.header_id
6262 AND odss.line_id = ool.line_id)
6263 -- Only pick up WDD lines that match the project/task of the MOL if necessary
6264 AND (l_project_ref_enabled = 2 OR
6265 l_allow_cross_proj_issues = 'Y' OR
6266 (NVL(wdd.project_id, -999) = NVL(p_project_id, -999) AND
6267 NVL(wdd.task_id, -999) = NVL(p_task_id, -999)));
6268
6269
6270 -- Cursor to retrieve valid backordered Sales Order demand lines
6271 CURSOR SO_backordered_lines(p_project_id NUMBER, p_task_id NUMBER) IS
6272 SELECT
6273 inv_salesorder.get_salesorder_for_oeheader(wdd.source_header_id) AS header_id,
6274 wdd.source_line_id AS line_id,
6275 wdd.delivery_detail_id AS line_detail_id,
6276 wdd.requested_quantity AS quantity,
6277 wdd.requested_quantity_uom AS uom_code,
6278 wdd.requested_quantity2 AS secondary_quantity,
6279 wdd.requested_quantity_uom2 AS secondary_uom_code,
6280 wdd.project_id AS project_id,
6281 wdd.task_id AS task_id,
6282 NULL AS wip_supply_type
6283 FROM wsh_delivery_details wdd, oe_order_lines_all ool
6284 WHERE wdd.organization_id = l_organization_id
6285 AND wdd.inventory_item_id = l_inventory_item_id
6286 AND wdd.released_status = 'B'
6287 AND wdd.source_code = 'OE'
6288 AND wdd.requested_quantity > 0
6289 AND wdd.source_line_id = ool.line_id
6290 AND NVL(ool.source_document_type_id, -999) <> 10
6291 AND ool.booked_flag = 'Y'
6292 AND ool.open_flag = 'Y'
6293 AND NOT EXISTS (SELECT 'Drop Ship'
6294 FROM oe_drop_ship_sources odss
6295 WHERE odss.header_id = ool.header_id
6296 AND odss.line_id = ool.line_id)
6297 -- Only pick up WDD lines that match the project/task of the MOL if necessary
6298 AND (l_project_ref_enabled = 2 OR
6299 l_allow_cross_proj_issues = 'Y' OR
6300 (NVL(wdd.project_id, -999) = NVL(p_project_id, -999) AND
6301 NVL(wdd.task_id, -999) = NVL(p_task_id, -999)));
6302
6303
6304 -- Cursor to retrieve valid scheduled Internal Order demand lines
6305 CURSOR IO_scheduled_lines(p_project_id NUMBER, p_task_id NUMBER) IS
6306 SELECT
6307 inv_salesorder.get_salesorder_for_oeheader(wdd.source_header_id) AS header_id,
6308 wdd.source_line_id AS line_id,
6309 wdd.delivery_detail_id AS line_detail_id,
6310 wdd.requested_quantity AS quantity,
6311 wdd.requested_quantity_uom AS uom_code,
6312 wdd.requested_quantity2 AS secondary_quantity,
6313 wdd.requested_quantity_uom2 AS secondary_uom_code,
6314 wdd.project_id AS project_id,
6315 wdd.task_id AS task_id,
6316 NULL AS wip_supply_type
6317 FROM wsh_delivery_details wdd, oe_order_lines_all ool
6318 WHERE wdd.organization_id = l_organization_id
6319 AND wdd.inventory_item_id = l_inventory_item_id
6320 AND wdd.released_status = 'R'
6321 AND wdd.source_code = 'OE'
6322 AND wdd.requested_quantity > 0
6323 AND wdd.source_line_id = ool.line_id
6324 AND NVL(ool.source_document_type_id, -999) = 10
6325 AND ool.booked_flag = 'Y'
6326 AND ool.open_flag = 'Y'
6327 AND NOT EXISTS (SELECT 'Drop Ship'
6328 FROM oe_drop_ship_sources odss
6329 WHERE odss.header_id = ool.header_id
6330 AND odss.line_id = ool.line_id)
6331 -- Only pick up WDD lines that match the project/task of the MOL if necessary
6332 AND (l_project_ref_enabled = 2 OR
6333 l_allow_cross_proj_issues = 'Y' OR
6334 (NVL(wdd.project_id, -999) = NVL(p_project_id, -999) AND
6335 NVL(wdd.task_id, -999) = NVL(p_task_id, -999)));
6336
6337
6338 -- Cursor to retrieve valid backordered Internal Order demand lines
6339 CURSOR IO_backordered_lines(p_project_id NUMBER, p_task_id NUMBER) IS
6340 SELECT
6341 inv_salesorder.get_salesorder_for_oeheader(wdd.source_header_id) AS header_id,
6342 wdd.source_line_id AS line_id,
6343 wdd.delivery_detail_id AS line_detail_id,
6344 wdd.requested_quantity AS quantity,
6345 wdd.requested_quantity_uom AS uom_code,
6346 wdd.requested_quantity2 AS secondary_quantity,
6347 wdd.requested_quantity_uom2 AS secondary_uom_code,
6348 wdd.project_id AS project_id,
6349 wdd.task_id AS task_id,
6350 NULL AS wip_supply_type
6351 FROM wsh_delivery_details wdd, oe_order_lines_all ool
6352 WHERE wdd.organization_id = l_organization_id
6353 AND wdd.inventory_item_id = l_inventory_item_id
6354 AND wdd.released_status = 'B'
6355 AND wdd.source_code = 'OE'
6356 AND wdd.requested_quantity > 0
6357 AND wdd.source_line_id = ool.line_id
6358 AND NVL(ool.source_document_type_id, -999) = 10
6359 AND ool.booked_flag = 'Y'
6360 AND ool.open_flag = 'Y'
6361 AND NOT EXISTS (SELECT 'Drop Ship'
6362 FROM oe_drop_ship_sources odss
6363 WHERE odss.header_id = ool.header_id
6364 AND odss.line_id = ool.line_id)
6365 -- Only pick up WDD lines that match the project/task of the MOL if necessary
6366 AND (l_project_ref_enabled = 2 OR
6367 l_allow_cross_proj_issues = 'Y' OR
6368 (NVL(wdd.project_id, -999) = NVL(p_project_id, -999) AND
6369 NVL(wdd.task_id, -999) = NVL(p_task_id, -999)));
6370
6371
6372 -- Cursor to retrieve valid backordered WIP Component demand lines
6373 CURSOR wip_component_demand_lines(p_project_id NUMBER,
6374 p_task_id NUMBER,
6375 p_xdock_start_time DATE,
6376 p_xdock_end_time DATE) IS
6377 SELECT
6378 wmsv.wip_entity_id AS header_id,
6379 wmsv.operation_seq_num AS line_id,
6380 wmsv.repetitive_schedule_id AS line_detail_id,
6381 wmsv.date_required AS expected_time,
6382 wmsv.quantity_backordered AS quantity,
6383 wmsv.primary_uom_code AS uom_code,
6384 NULL AS secondary_quantity,
6385 NULL AS secondary_uom_code,
6386 wmsv.project_id AS project_id,
6387 wmsv.task_id AS task_id,
6388 wmsv.wip_supply_type AS wip_supply_type
6389 FROM wip_material_shortages_v wmsv
6390 WHERE wmsv.organization_id = l_organization_id
6391 AND wmsv.inventory_item_id = l_inventory_item_id
6392 AND wmsv.wip_entity_type in (1, 2, 5)
6393 AND wmsv.date_required IS NOT NULL
6394 -- Only pick up WIP demand lines that lie within the crossdock window
6395 -- OR have a date_required value in the past.
6396 AND (wmsv.date_required BETWEEN p_xdock_start_time AND p_xdock_end_time OR
6397 wmsv.date_required < SYSDATE)
6398 -- Only pick up WIP lines that match the project/task of the MOL if necessary
6399 AND (l_project_ref_enabled = 2 OR
6400 l_allow_cross_proj_issues = 'Y' OR
6401 (NVL(wmsv.project_id, -999) = NVL(p_project_id, -999) AND
6402 NVL(wmsv.task_id, -999) = NVL(p_task_id, -999)));
6403
6404
6405 -- Variables to retrieve the values from the demand lines cursors.
6406 -- We will bulk collect the records from the cursors into these PLSQL tables and
6407 -- use them to do a bulk insert into the xdock pegging global temp table.
6408 TYPE num_tab IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
6409 TYPE uom_tab IS TABLE OF VARCHAR2(3) INDEX BY BINARY_INTEGER;
6410 TYPE bool_tab IS TABLE OF BOOLEAN INDEX BY BINARY_INTEGER;
6411 l_header_id_tb num_tab;
6412 l_line_id_tb num_tab;
6413 l_line_detail_id_tb num_tab;
6414 l_quantity_tb num_tab;
6415 l_uom_code_tb uom_tab;
6416 l_secondary_quantity_tb num_tab;
6417 l_secondary_uom_code_tb uom_tab;
6418 l_project_id_tb num_tab;
6419 l_task_id_tb num_tab;
6420 l_wip_supply_type_tb num_tab;
6421
6422 -- Variables to store the expected time values for the demand line records retrieved.
6423 -- We will use the date tables to do a bulk insert into the xdock pegging global temp table.
6424 TYPE date_tab IS TABLE OF DATE INDEX BY BINARY_INTEGER;
6425 l_dock_start_time_tb date_tab;
6426 l_dock_mean_time_tb date_tab;
6427 l_dock_end_time_tb date_tab;
6428 l_expected_time_tb date_tab;
6429
6430 -- Cursor to retrieve, lock and validate the MOL inputted
6431 CURSOR get_move_order_line IS
6432 SELECT mtrl.*,
6433 msi.primary_uom_code AS primary_uom_code,
6434 NVL(msi.reservable_type, 1) AS reservable_type,
6435 NVL(msi.lot_control_code, 1) AS lot_control_code,
6436 NVL(msi.lot_divisible_flag, 'Y') AS lot_divisible_flag,
6437 wlpn.lpn_context AS lpn_context
6438 FROM mtl_txn_request_lines mtrl, mtl_system_items msi, wms_license_plate_numbers wlpn
6439 WHERE mtrl.line_id = p_move_order_line_id
6440 AND mtrl.organization_id = l_organization_id
6441 -- Modified the line below to use an IN instead of <>
6442 -- AND mtrl.line_status <> inv_globals.g_to_status_closed
6443 AND mtrl.line_status IN (inv_globals.g_to_status_preapproved,
6444 inv_globals.g_to_status_approved)
6445 AND mtrl.backorder_delivery_detail_id IS NULL
6446 AND mtrl.lpn_id IS NOT NULL
6447 AND mtrl.quantity > 0
6448 AND NVL(mtrl.quantity_delivered, 0) = 0
6449 AND NVL(mtrl.quantity_detailed, 0) = 0
6450 AND NVL(mtrl.inspection_status, 2) = 2
6451 AND NVL(mtrl.wms_process_flag, 1) = 1
6452 AND NVL(mtrl.reference, 'non-RMA') <> 'ORDER_LINE_ID'
6453 AND mtrl.inventory_item_id = msi.inventory_item_id
6454 AND mtrl.organization_id = msi.organization_id
6455 AND mtrl.lpn_id = wlpn.lpn_id
6456 AND wlpn.lpn_context IN (2, 3) -- WIP or RCV
6457 -- Added the following line so the index: WMS_LICENSE_PLATE_NUMBERS_N6
6458 -- can be used in case the SQL optimizer uses WLPN as the driving table.
6459 AND wlpn.organization_id = l_organization_id
6460 FOR UPDATE OF mtrl.line_id NOWAIT;
6461
6462 -- Variable to store info from the inputted MOL record
6463 l_mol_rec get_move_order_line%ROWTYPE;
6464 l_supply_type_id NUMBER;
6465 l_supply_header_id NUMBER;
6466 l_supply_line_id NUMBER;
6467 l_supply_line_detail_id NUMBER;
6468 l_supply_uom_code VARCHAR2(3);
6469 l_supply_expected_time DATE;
6470 l_mol_qty NUMBER;
6471 l_mol_header_id NUMBER;
6472 l_mol_line_id NUMBER;
6473 l_mol_prim_qty NUMBER;
6474 l_mol_qty2 NUMBER;
6475 l_mol_uom_code2 VARCHAR2(3);
6476 l_mol_lpn_id NUMBER;
6477
6478 -- Cursor to lock the set of MOL lines related to the input MOL (i.e. same org/item
6479 -- for RCV, same org/item/WIP job for WIP)
6480 CURSOR lock_mo_lines(p_lpn_context NUMBER,
6481 p_wip_entity_id NUMBER,
6482 p_operation_seq_num NUMBER,
6483 p_repetitive_schedule_id NUMBER) IS
6484 SELECT mtrl.line_id
6485 FROM mtl_txn_request_lines mtrl, mtl_txn_request_headers mtrh,
6486 wms_license_plate_numbers wlpn
6487 WHERE mtrl.header_id = mtrh.header_id
6488 AND mtrh.move_order_type = inv_globals.g_move_order_put_away
6489 AND mtrl.organization_id = l_organization_id
6490 AND mtrl.inventory_item_id = l_inventory_item_id
6491 -- Modified the line below to use an IN instead of <> so the
6492 -- index MTL_TXN_REQUEST_LINES_N10 on MTRL is more likely to be used.
6493 -- AND mtrl.line_status <> inv_globals.g_to_status_closed
6494 AND mtrl.line_status IN (inv_globals.g_to_status_preapproved,
6495 inv_globals.g_to_status_approved)
6496 AND mtrl.backorder_delivery_detail_id IS NULL
6497 AND mtrl.lpn_id IS NOT NULL
6498 AND mtrl.quantity > 0
6499 AND NVL(mtrl.quantity_delivered, 0) = 0
6500 AND NVL(mtrl.quantity_detailed, 0) = 0
6501 AND NVL(mtrl.inspection_status, 2) = 2
6502 AND NVL(mtrl.wms_process_flag, 1) = 1
6503 AND NVL(mtrl.reference, 'non-RMA') <> 'ORDER_LINE_ID'
6504 AND mtrl.lpn_id = wlpn.lpn_id
6505 AND wlpn.lpn_context = p_lpn_context
6506 -- Added the following line so the index: WMS_LICENSE_PLATE_NUMBERS_N6
6507 -- can be used in case the SQL optimizer uses WLPN as the driving table.
6508 AND wlpn.organization_id = l_organization_id
6509 AND (p_lpn_context = 3 OR -- RCV
6510 (p_lpn_context = 2 AND -- WIP
6511 mtrl.txn_source_id = p_wip_entity_id)
6512 -- The two lines below are not required since WIP putaway MOLs do not store
6513 -- the operation sequence num or the repetitive schedule ID.
6514 -- NVL(mtrl.txn_source_line_id, -999) = NVL(p_operation_seq_num, -999) AND
6515 -- NVL(mtrl.reference_id, -999) = NVL(p_repetitive_schedule_id, -999))
6516 )
6517 FOR UPDATE OF mtrl.line_id NOWAIT;
6518
6519 -- Table to store the results from the lock_mo_lines cursor
6520 TYPE locked_mo_lines_tb IS TABLE OF lock_mo_lines%ROWTYPE INDEX BY BINARY_INTEGER;
6521 l_locked_mo_lines_tb locked_mo_lines_tb;
6522
6523 -- Crossdock Criteria time interval values.
6524 -- The max precision for the DAY is 2 digits (i.e. 99 DAY is the largest possible value)
6525 -- and will be enforced in the crossdock criteria definition form.
6526 l_xdock_window_interval INTERVAL DAY(2) TO SECOND;
6527 l_buffer_interval INTERVAL DAY(2) TO SECOND;
6528 l_processing_interval INTERVAL DAY(2) TO SECOND;
6529
6530 -- Crossdock time window start and end times. Any valid deamnds within this
6531 -- time interval are valid for crossdocking.
6532 l_xdock_start_time DATE;
6533 l_xdock_end_time DATE;
6534
6535 -- Cursor to retrieve the existing high level non-crossdocked, non-WIP as demand reservations
6536 -- for the MO supply line. For these types of reservations, the detailed_quantity
6537 -- column should be NULL or 0.
6538 -- We will also lock the reservations records here. Using the SKIP LOCKED keyword,
6539 -- we can select only row records which are lockable without erroring out the entire query.
6540 CURSOR existing_rsvs_cursor(p_lpn_context NUMBER,
6541 p_wip_entity_id NUMBER) IS
6542 SELECT reservation_id, demand_source_type_id, demand_source_header_id,
6543 demand_source_line_id, reservation_quantity, reservation_uom_code,
6544 secondary_reservation_quantity, secondary_uom_code,
6545 primary_reservation_quantity, primary_uom_code
6546 FROM mtl_reservations
6547 WHERE organization_id = l_organization_id
6548 AND inventory_item_id = l_inventory_item_id
6549 AND ((p_lpn_context = 3 AND -- RCV supply
6550 supply_source_type_id = inv_reservation_global.g_source_type_rcv)
6551 OR
6552 (p_lpn_context = 2 AND -- WIP supply
6553 supply_source_type_id = inv_reservation_global.g_source_type_wip AND
6554 supply_source_header_id = p_wip_entity_id))
6555 AND demand_source_type_id <> inv_reservation_global.g_source_type_wip
6556 AND demand_source_line_detail IS NULL
6557 AND NVL(crossdock_flag, 'N') = 'N'
6558 AND primary_reservation_quantity - NVL(detailed_quantity, 0) > 0
6559 FOR UPDATE SKIP LOCKED;
6560
6561 -- Table to store the results from the existing reservations cursor
6562 TYPE existing_rsvs_tb IS TABLE OF existing_rsvs_cursor%ROWTYPE INDEX BY BINARY_INTEGER;
6563 l_existing_rsvs_tb existing_rsvs_tb;
6564
6565 -- Index used to loop through the existing high level non-inventory reservations
6566 l_rsv_index NUMBER;
6567
6568 -- Variables for existing reservations and the related demand line on it
6569 l_rsv_id NUMBER;
6570 l_rsv_qty NUMBER;
6571 l_rsv_uom_code VARCHAR2(3);
6572 l_rsv_qty2 NUMBER;
6573 l_rsv_uom_code2 VARCHAR2(3);
6574 l_rsv_prim_qty NUMBER;
6575 l_rsv_prim_uom_code VARCHAR2(3);
6576 l_demand_type_id NUMBER;
6577 l_demand_header_id NUMBER; -- OE order header ID
6578 l_demand_so_header_id NUMBER; -- Sales order header ID
6579 l_demand_line_id NUMBER;
6580
6581 -- Cursor to retrieve the valid WDD lines tied to an order line in an existing reservation.
6582 -- We will try to match for the project/task values on the supply line if necessary.
6583 CURSOR reserved_wdd_lines(p_project_id NUMBER, p_task_id NUMBER) IS
6584 SELECT wdd.delivery_detail_id, wdd.requested_quantity, wdd.requested_quantity_uom,
6585 wdd.requested_quantity2, wdd.requested_quantity_uom2,
6586 wdd.released_status, wdd.project_id, wdd.task_id
6587 FROM wsh_delivery_details wdd, oe_order_lines_all ool
6588 WHERE wdd.organization_id = l_organization_id
6589 AND wdd.inventory_item_id = l_inventory_item_id
6590 AND wdd.released_status IN ('R', 'B')
6591 AND wdd.source_code = 'OE'
6592 AND wdd.requested_quantity > 0
6593 AND wdd.source_header_id = l_demand_header_id
6594 AND wdd.source_line_id = l_demand_line_id
6595 AND wdd.source_line_id = ool.line_id
6596 AND ool.booked_flag = 'Y'
6597 AND ool.open_flag = 'Y'
6598 AND NOT EXISTS (SELECT 'Drop Ship'
6599 FROM oe_drop_ship_sources odss
6600 WHERE odss.header_id = ool.header_id
6601 AND odss.line_id = ool.line_id)
6602 -- Only pick up WDD lines that match the project/task of the MOL if necessary
6603 AND (l_project_ref_enabled = 2 OR
6604 l_allow_cross_proj_issues = 'Y' OR
6605 (NVL(wdd.project_id, -999) = NVL(p_project_id, -999) AND
6606 NVL(wdd.task_id, -999) = NVL(p_task_id, -999)))
6607 FOR UPDATE OF wdd.delivery_detail_id SKIP LOCKED;
6608
6609 -- Table to store the results from the reserved_wdd_lines cursor
6610 TYPE reserved_wdd_lines_tb IS TABLE OF reserved_wdd_lines%ROWTYPE INDEX BY BINARY_INTEGER;
6611 l_reserved_wdd_lines_tb reserved_wdd_lines_tb;
6612
6613 -- Index used to loop through the reserved WDD lines table
6614 l_wdd_index NUMBER;
6615
6616 -- Variables for the current demand line
6617 l_demand_line_detail_id NUMBER;
6618 l_demand_qty NUMBER;
6619 l_demand_uom_code VARCHAR2(3);
6620 l_demand_qty2 NUMBER;
6621 l_demand_uom_code2 VARCHAR2(3);
6622 l_demand_status VARCHAR2(1);
6623 l_demand_project_id NUMBER;
6624 l_demand_task_id NUMBER;
6625 l_dock_start_time DATE;
6626 l_dock_mean_time DATE;
6627 l_dock_end_time DATE;
6628 l_demand_expected_time DATE;
6629
6630 -- Variable used to store the current demand source code (as used by crossdock criteria)
6631 -- The supply source codes are different for Reservations and Crossdock Criteria.
6632 l_demand_src_code NUMBER;
6633
6634 -- Conversion rate when converting quantity values to different UOMs
6635 l_conversion_rate NUMBER;
6636 -- The standard Inventory precision is to 5 decimal places. Define this in a local constant
6637 -- in case this needs to be changed later on. Variable is used to round off converted values
6638 -- to this precision level.
6639 l_conversion_precision CONSTANT NUMBER := 5;
6640
6641 -- Variables to store the converted quantity values and the available to detail
6642 -- values. They will all be converted to the UOM on the MOL supply line, l_supply_uom_code.
6643 -- We also need the ATD qty in the primary UOM of the item.
6644 -- l_wdd_atr_txn_qty is used when the full quantity on the WDD line may not be available
6645 -- for crossdocking. This is not the case for existing reservations but is possible for
6646 -- normal crossdocking, i.e. other existing reservations tying up quantity on the WDD line.
6647 l_wdd_txn_qty NUMBER;
6648 l_wdd_atr_txn_qty NUMBER;
6649 l_rsv_txn_qty NUMBER;
6650 l_atd_qty NUMBER;
6651 l_atd_prim_qty NUMBER;
6652
6653 -- These values will store the available to detail quantity converted to the UOM of
6654 -- the WDD and RSV record respectively. They are used whenever those records need
6655 -- to be split. The secondary quantities are needed too when splitting a WDD or RSV record.
6656 -- For MOL records, the ATD quantity is always in that UOM. However, we still need to
6657 -- convert the ATD quantity to the secondary UOM on the MOL record if it exists.
6658 l_atd_wdd_qty NUMBER;
6659 l_atd_wdd_qty2 NUMBER;
6660 l_atd_rsv_qty NUMBER;
6661 l_atd_rsv_qty2 NUMBER;
6662 l_atd_mol_qty2 NUMBER;
6663
6664 -- Variables used to call the Shipping API to split a WDD line if a partial quantity
6665 -- is crossdocked on the WDD line.
6666 l_detail_id_tab WSH_UTIL_CORE.id_tab_type;
6667 l_action_prms WSH_GLBL_VAR_STRCT_GRP.dd_action_parameters_rec_type;
6668 l_action_out_rec WSH_GLBL_VAR_STRCT_GRP.dd_action_out_rec_type;
6669 l_split_wdd_rel_rec WSH_PR_CRITERIA.relRecTyp;
6670 l_split_wdd_id NUMBER;
6671 l_index NUMBER;
6672
6673 -- Variables used to call the Shipping API to update a WDD line when it is
6674 -- being crossdocked.
6675 l_detail_info_tab WSH_INTERFACE_EXT_GRP.Delivery_Details_Attr_Tbl_Type;
6676 l_in_rec WSH_INTERFACE_EXT_GRP.detailInRecType;
6677 l_out_rec WSH_INTERFACE_EXT_GRP.detailOutRecType;
6678
6679 -- Variable used to update a crossdocked WDD record
6680 l_xdocked_wdd_index NUMBER;
6681
6682 -- Dummy variables used when calling the private Crossdock_WDD procedure.
6683 -- These are variables used in the Planned Crossdocking case but not needed here.
6684 l_batch_id NUMBER;
6685 l_wsh_release_table WSH_PR_CRITERIA.relRecTabTyp;
6686 l_trolin_delivery_ids WSH_UTIL_CORE.Id_Tab_Type;
6687 l_del_detail_id WSH_PICK_LIST.DelDetTabTyp;
6688 l_dummy_wdd_index NUMBER;
6689 l_allocation_method VARCHAR2(1);
6690 l_split_wdd_index NUMBER;
6691 l_split_delivery_index NUMBER;
6692 TYPE orig_wdd_values_rec IS RECORD
6693 (requested_quantity NUMBER,
6694 requested_quantity2 NUMBER,
6695 released_status VARCHAR2(1),
6696 move_order_line_id NUMBER);
6697 l_orig_wdd_values_rec orig_wdd_values_rec;
6698 l_error_code VARCHAR2(3);
6699
6700 -- Variables to split and update reservations records
6701 l_original_rsv_rec inv_reservation_global.mtl_reservation_rec_type;
6702 l_to_rsv_rec inv_reservation_global.mtl_reservation_rec_type;
6703 l_original_serial_number inv_reservation_global.serial_number_tbl_type;
6704 l_to_serial_number inv_reservation_global.serial_number_tbl_type;
6705 l_split_rsv_id NUMBER;
6706
6707 -- Variables to store the available to reserve quantity for a demand or supply line
6708 -- both in the primary and demand/supply line UOM.
6709 l_demand_atr_prim_qty NUMBER;
6710 l_demand_atr_qty NUMBER;
6711 l_demand_available_qty NUMBER;
6712 l_supply_atr_prim_qty NUMBER;
6713 l_supply_atr_qty NUMBER;
6714 l_supply_available_qty NUMBER;
6715
6716 -- Cursor to retrieve eligible demand source types for a given crossdock criteria
6717 CURSOR demand_src_types_cursor IS
6718 SELECT source_code
6719 FROM wms_xdock_source_assignments
6720 WHERE criterion_id = l_crossdock_criteria_id
6721 AND source_type = G_SRC_TYPE_DEM
6722 ORDER BY priority;
6723
6724 -- Table to retrieve the values from the demand_src_types_cursor
6725 l_demand_src_types_tb num_tab;
6726
6727 -- Table to store the valid demand lines for crossdocking for the MOL supply line.
6728 -- The type is defined in the specs instead so the custom logic package can reference it.
6729 l_shopping_basket_tb shopping_basket_tb;
6730
6731 -- Variables used when calling custom logic to sort the supply lines in the
6732 -- shopping basket table.
6733 l_sorted_order_tb sorted_order_tb;
6734 l_shopping_basket_temp_tb shopping_basket_tb;
6735 l_indices_used_tb bool_tab;
6736
6737 -- Variables for the get_demand_lines cursor to indicate the relative priority of the demand
6738 -- source types to retrieve valid demand lines for. If we don't need to prioritize documents,
6739 -- a default value of 99 will be used. The cursor get_demand_lines will order by the priority
6740 -- value in ascending order so lower values have higher priority.
6741 l_so_sched_priority NUMBER;
6742 l_so_back_priority NUMBER;
6743 l_io_sched_priority NUMBER;
6744 l_io_back_priority NUMBER;
6745 l_wip_priority NUMBER;
6746
6747 -- Cursor to retrieve valid demand lines for crossdocking.
6748 -- For opportunistic crossdock, only crossdockable demand lines are inserted into
6749 -- the global temp table. Therefore we want to select every single record (full table scan)
6750 -- from wms_xdock_pegging_gtmp.
6751 CURSOR get_demand_lines(p_crossdock_goal NUMBER,
6752 p_so_sched_priority NUMBER,
6753 p_so_back_priority NUMBER,
6754 p_io_sched_priority NUMBER,
6755 p_io_back_priority NUMBER,
6756 p_wip_priority NUMBER) IS
6757 SELECT ROWID,
6758 inventory_item_id,
6759 xdock_source_code,
6760 source_type_id,
6761 source_header_id,
6762 source_line_id,
6763 source_line_detail_id,
6764 dock_start_time,
6765 dock_mean_time,
6766 dock_end_time,
6767 expected_time,
6768 quantity,
6769 reservable_quantity,
6770 uom_code,
6771 primary_quantity,
6772 secondary_quantity,
6773 secondary_uom_code,
6774 project_id,
6775 task_id,
6776 lpn_id,
6777 wip_supply_type
6778 FROM wms_xdock_pegging_gtmp
6779 WHERE inventory_item_id = l_inventory_item_id
6780 ORDER BY DECODE (xdock_source_code,
6781 G_OPP_DEM_SO_SCHED, p_so_sched_priority,
6782 G_OPP_DEM_SO_BKORD, p_so_back_priority,
6783 G_OPP_DEM_IO_SCHED, p_io_sched_priority,
6784 G_OPP_DEM_IO_BKORD, p_io_back_priority,
6785 G_OPP_DEM_WIP_BKORD, p_wip_priority,
6786 99),
6787 DECODE (p_crossdock_goal,
6788 G_MINIMIZE_WAIT, SYSDATE - expected_time,
6789 G_MAXIMIZE_XDOCK, expected_time - SYSDATE,
6790 G_CUSTOM_GOAL, NULL,
6791 NULL);
6792
6793 -- Index used to loop through the demand lines for crossdocking to the MOL supply line.
6794 l_demand_index NUMBER;
6795
6796 -- Cursor to lock the WDD demand record
6797 CURSOR lock_wdd_record(p_delivery_detail_id NUMBER) IS
6798 SELECT delivery_detail_id
6799 FROM wsh_delivery_details
6800 WHERE delivery_detail_id = p_delivery_detail_id
6801 FOR UPDATE NOWAIT;
6802
6803 -- Cursor to lock the WIP demand record.
6804 -- WIP backordered component demand MUST have a record in the table
6805 -- wip_requirement_operations. Thus, operation_seq_num should not be null.
6806 -- We could also lock the wip_entities record but that is probably not necessary,
6807 -- especially if the demand is a WIP Repetitive job. That might lock up the record
6808 -- unnecessarily for other repetitive jobs with the same wip_entity_id.
6809 CURSOR lock_wip_record(p_wip_entity_id NUMBER,
6810 p_operation_seq_num NUMBER,
6811 p_repetitive_schedule_id NUMBER) IS
6812 SELECT wip_entity_id
6813 FROM wip_requirement_operations
6814 WHERE inventory_item_id = l_inventory_item_id
6815 AND organization_id = l_organization_id
6816 AND wip_entity_id = p_wip_entity_id
6817 AND operation_seq_num = p_operation_seq_num
6818 AND NVL(repetitive_schedule_id, -999) = NVL(p_repetitive_schedule_id, -999)
6819 FOR UPDATE NOWAIT;
6820
6821 -- The following are variables used to call the create_reservation API
6822 l_quantity_reserved NUMBER;
6823 l_quantity_reserved2 NUMBER;
6824
6825 -- Variables used for WIP backordered component demand lines
6826 l_wip_entity_id NUMBER;
6827 l_operation_seq_num NUMBER;
6828 l_repetitive_schedule_id NUMBER;
6829 l_wip_supply_type NUMBER;
6830 l_wip_qty_allocated NUMBER;
6831
6832 -- Cursor used when satisfying existing reservations with WIP as a supply.
6833 -- Part of the reservation could already be fulfilled by other MOLs from the same
6834 -- WIP job that have been crossdocked. Since we do not split and update the WIP
6835 -- to SO/IO reservation when crossdocking, and if the crossdocked MOLs have not
6836 -- been delivered yet, the WIP reservation will not be updated. We need to take
6837 -- these crossdocked WIP MOLs into account when calculating the quantity left to
6838 -- satisfy on the reservation. Query for crossdocked WIP MOLs with the WIP job on
6839 -- the reservation as supply and Order Line on reservation as demand.
6840 CURSOR get_wip_xdock_qty(p_wip_entity_id NUMBER,
6841 p_operation_seq_num NUMBER,
6842 p_repetitive_schedule_id NUMBER,
6843 p_demand_source_header_id NUMBER,
6844 p_demand_source_line_id NUMBER) IS
6845 SELECT NVL(SUM(mtrl.primary_quantity), 0)
6846 FROM mtl_txn_request_lines mtrl, wsh_delivery_details wdd,
6847 wms_license_plate_numbers wlpn
6848 WHERE mtrl.organization_id = l_organization_id
6849 AND mtrl.inventory_item_id = l_inventory_item_id
6850 -- Modified the line below to use an IN instead of <> so the
6851 -- index MTL_TXN_REQUEST_LINES_N10 on MTRL is more likely to be used.
6852 -- AND mtrl.line_status <> inv_globals.g_to_status_closed
6853 AND mtrl.line_status IN (inv_globals.g_to_status_preapproved,
6854 inv_globals.g_to_status_approved)
6855 AND NVL(mtrl.quantity_delivered, 0) = 0
6856 AND mtrl.txn_source_id = p_wip_entity_id
6857 -- The two lines below are not required since WIP putaway MOLs do not store
6858 -- the operation sequence num or the repetitive schedule ID.
6859 -- AND NVL(mtrl.txn_source_line_id, -999) = NVL(p_operation_seq_num, -999)
6860 -- AND NVL(mtrl.reference_id, -999) = NVL(p_repetitive_schedule_id, -999)
6861 AND mtrl.lpn_id = wlpn.lpn_id
6862 AND wlpn.lpn_context = 2 -- WIP
6863 -- Added the following line so the index: WMS_LICENSE_PLATE_NUMBERS_N6
6864 -- can be used in case the SQL optimizer uses WLPN as the driving table.
6865 AND wlpn.organization_id = l_organization_id
6866 AND mtrl.crossdock_type = 1 -- Crossdocked to OE demand
6867 AND mtrl.backorder_delivery_detail_id = wdd.delivery_detail_id
6868 AND wdd.source_header_id = p_demand_source_header_id
6869 AND wdd.source_line_id = p_demand_source_line_id;
6870
6871 -- Variables to WIP crossdocked quantity values to adjust the reservation qty
6872 l_wip_xdock_prim_qty NUMBER;
6873 l_wip_xdock_qty NUMBER;
6874 l_wip_xdock_qty2 NUMBER;
6875
6876 -- Variable for WIP MOL supply lines to indicate what type of WIP job
6877 -- it is from, i.e. Discrete or Flow.
6878 l_wip_entity_type NUMBER;
6879
6880 -- For WIP Discrete Job MOLs, check to see if multiple reservations exist
6881 -- for the same WIP job as supply. If so, then do not crossdock the MOL.
6882 -- If one reservation exists, try to honor it if the demand is of type OE.
6883 -- Any quantity left can only be pegged to this same OE demand. We do not want
6884 -- to create multiple reservations for the same WIP job going to different demands.
6885 -- Use a distinct in case we have multiple reservations for the same WIP supply and
6886 -- demand. This could be possible if the reservations have a different requirement date
6887 -- so the reservations were not merged.
6888 CURSOR existing_wip_rsvs IS
6889 SELECT DISTINCT demand_source_type_id, demand_source_header_id, demand_source_line_id
6890 FROM mtl_reservations
6891 WHERE organization_id = l_organization_id
6892 AND inventory_item_id = l_inventory_item_id
6893 AND supply_source_type_id = inv_reservation_global.g_source_type_wip
6894 AND supply_source_header_id = l_supply_header_id;
6895
6896 -- Table to store the results from the existing WIP reservations cursor
6897 TYPE existing_wip_rsvs_tb IS TABLE OF existing_wip_rsvs%ROWTYPE INDEX BY BINARY_INTEGER;
6898 l_existing_wip_rsvs_tb existing_wip_rsvs_tb;
6899
6900 -- Variables to store the demand that a WIP MOL supply should be pegged against
6901 l_wip_demand_type_id NUMBER;
6902 l_wip_demand_header_id NUMBER; -- MTL Sales Order Header ID from Reservations
6903 l_wip_demand_line_id NUMBER;
6904
6905 BEGIN
6906 -- Start the profiler for Unit Testing to ensure complete code coverage
6907 --dbms_profiler.start_profiler('Opportunistic_Cross_Dock: ' || p_move_order_line_id);
6908
6909 IF (l_debug = 1) THEN
6910 print_debug('***Calling Opportunistic_Cross_Dock with the following parameters***');
6911 print_debug('Package Version: ==========> ' || g_pkg_version);
6912 print_debug('p_organization_id: ========> ' || p_organization_id);
6913 print_debug('p_move_order_line_id: =====> ' || p_move_order_line_id);
6914 print_debug('p_crossdock_criterion_id: => ' || p_crossdock_criterion_id);
6915 END IF;
6916
6917 -- Set the savepoint
6918 SAVEPOINT Opportunistic_Cross_Dock_sp;
6919 l_progress := '10';
6920
6921 -- Initialize message list to clear any existing messages
6922 fnd_msg_pub.initialize;
6923 l_progress := '20';
6924
6925 -- Initialize API return status to success
6926 x_return_status := fnd_api.g_ret_sts_success;
6927 l_progress := '30';
6928
6929 -- Initialize local versions of the following input parameters
6930 l_organization_id := p_organization_id;
6931 l_crossdock_criteria_id := p_crossdock_criterion_id;
6932
6933 -- Initialize the PLSQL tables used to retrieve the demand line cursor records
6934 l_header_id_tb.DELETE;
6935 l_line_id_tb.DELETE;
6936 l_line_detail_id_tb.DELETE;
6937 l_quantity_tb.DELETE;
6938 l_uom_code_tb.DELETE;
6939 l_secondary_quantity_tb.DELETE;
6940 l_secondary_uom_code_tb.DELETE;
6941 l_project_id_tb.DELETE;
6942 l_task_id_tb.DELETE;
6943 l_dock_start_time_tb.DELETE;
6944 l_dock_mean_time_tb.DELETE;
6945 l_dock_end_time_tb.DELETE;
6946 l_expected_time_tb.DELETE;
6947 l_wip_supply_type_tb.DELETE;
6948
6949 -- Initialize the detail info table used for updating
6950 -- crossdocked WDD records
6951 l_detail_info_tab.DELETE;
6952
6953 -- Initialize the global Item UOM conversion table.
6954 g_item_uom_conversion_tb.DELETE;
6955 l_progress := '40';
6956
6957 -- Query for and cache the org record.
6958 IF (NOT INV_CACHE.set_org_rec(l_organization_id)) THEN
6959 IF (l_debug = 1) THEN
6960 print_debug('Error caching the org record');
6961 END IF;
6962 RAISE fnd_api.g_exc_unexpected_error;
6963 END IF;
6964 -- Set the PJM enabled flag.
6965 l_project_ref_enabled := INV_CACHE.org_rec.project_reference_enabled;
6966 l_progress := '50';
6967
6968 -- Check if the organization is a WMS organization
6969 l_wms_org_flag := wms_install.check_install
6970 (x_return_status => x_return_status,
6971 x_msg_count => x_msg_count,
6972 x_msg_data => x_msg_data,
6973 p_organization_id => l_organization_id);
6974 IF (x_return_status <> fnd_api.g_ret_sts_success) THEN
6975 IF (l_debug = 1) THEN
6976 print_debug('Call to wms_install.check_install failed: ' || x_msg_data);
6977 END IF;
6978 RAISE FND_API.G_EXC_UNEXPECTED_ERROR;
6979 END IF;
6980 l_progress := '60';
6981
6982 -- Retrieve the org parameter for allowing cross project allocation for crossdocking.
6983 -- For now, just hardcode this to 'N'. The reason is even if we create a peg with
6984 -- differing project/task combinations, execution needs to be able to handle this.
6985 -- A project/task transfer needs to be done so until that code is present, we should not
6986 -- create cross project pegs. The following is the SQL for retrieving this value.
6987 /*IF (l_project_ref_enabled = 1) THEN
6988 -- PJM org so see if cross project allocation is allowed
6989 BEGIN
6990 SELECT NVL(allow_cross_proj_issues, 'N')
6991 INTO l_allow_cross_proj_issues
6992 FROM pjm_org_parameters
6993 WHERE organization_id = l_organization_id;
6994 EXCEPTION
6995 WHEN OTHERS THEN
6996 l_allow_cross_proj_issues := 'N';
6997 END;
6998 ELSE
6999 -- Non-PJM org so cross project allocation is allowed since there are no projects or tasks
7000 l_allow_cross_proj_issues := 'Y';
7001 END IF;*/
7002 l_allow_cross_proj_issues := 'N';
7003 l_progress := '70';
7004
7005 -- Query for and cache the crossdock criteria record for the value entered.
7006 -- A value must exist.
7007 -- {{
7008 -- API should error out if invalid crossdock criteria is passed. }}
7009 IF (NOT set_crossdock_criteria(l_crossdock_criteria_id)) THEN
7010 IF (l_debug = 1) THEN
7011 print_debug('Error caching the crossdock criteria record: ' ||
7012 l_crossdock_criteria_id);
7013 END IF;
7014 RAISE fnd_api.g_exc_unexpected_error;
7015 END IF;
7016 -- Validate that the crossdock criterion is of type 'Opportunistic'
7017 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).criterion_type <> G_CRT_TYPE_OPP) THEN
7018 IF (l_debug = 1) THEN
7019 print_debug('Invalid crossdock criterion type: ' ||
7020 g_crossdock_criteria_tb(l_crossdock_criteria_id).criterion_type);
7021 END IF;
7022 RAISE fnd_api.g_exc_unexpected_error;
7023 END IF;
7024 l_progress := '80';
7025 -- End of validations and initializations
7026
7027
7028 -- Section 1: Supply line validations and initializations
7029 -- 1.1 - Validate that the supply line is eligible for crossdocking.
7030 -- 1.2 - Lock the set of MOLs related to the inputted supply line.
7031 -- 1.3 - Calculate the crossdock window given the crossdock criteria time parameters.
7032
7033 -- 1.1 - Validate that the supply line is eligible for crossdocking.
7034 -- Retrieve, lock, and validate the MOL record.
7035 -- {{
7036 -- Invalid MOL supply lines should not be crossdocked. Test for MOLs that are
7037 -- already crossdocked, have partial quantity detailed or delivered already, loose non-LPN
7038 -- material, part of an RMA return, requires inspection and not inspected yet,
7039 -- or MOL has already been locked by some other process. }}
7040 BEGIN
7041 OPEN get_move_order_line;
7042 FETCH get_move_order_line INTO l_mol_rec;
7043 -- If the MOL record is not found, do not error out. Skip to the end
7044 -- and do not crossdock the MOL.
7045 IF (get_move_order_line%NOTFOUND) THEN
7046 IF (l_debug = 1) THEN
7047 print_debug('1.1 - MOL inputted is not valid for crossdocking');
7048 END IF;
7049 CLOSE get_move_order_line;
7050 GOTO end_crossdock;
7051 END IF;
7052 CLOSE get_move_order_line;
7053 EXCEPTION
7054 WHEN OTHERS THEN
7055 IF (l_debug = 1) THEN
7056 print_debug('1.1 - Could not retrieve the MOL record');
7057 END IF;
7058 -- If an exception occurs, do not error out.
7059 -- Skip to the end and do not crossdock the MOL.
7060 GOTO end_crossdock;
7061 END;
7062 IF (l_debug = 1) THEN
7063 print_debug('1.1 - Successfully retrieved the MOL record');
7064 print_debug('1.1 - Item ID: ==> ' || l_mol_rec.inventory_item_id);
7065 print_debug('1.1 - Quantity: => ' || l_mol_rec.quantity || ' ' || l_mol_rec.uom_code);
7066 END IF;
7067 l_progress := '90';
7068
7069 -- Store relevant values needed from the MOL record
7070 -- {{
7071 -- Crossdock WIP and RCV MOL supply lines. }}
7072 IF (l_mol_rec.lpn_context = 3) THEN
7073 -- RCV MOL
7074 l_supply_type_id := 27;
7075 l_supply_header_id := l_mol_rec.header_id;
7076 l_supply_line_id := l_mol_rec.line_id;
7077 l_supply_line_detail_id := NULL;
7078 ELSE
7079 -- WIP MOL
7080 l_supply_type_id := 5;
7081 l_supply_header_id := l_mol_rec.txn_source_id; -- WIP entity ID
7082 l_supply_line_id := l_mol_rec.txn_source_line_id; -- WIP oper seq num
7083 l_supply_line_detail_id := l_mol_rec.reference_id; -- WIP repetitive sched ID
7084 -- Actually the value above refers to the WIP LPN Completion header ID.
7085 -- For WIP job completions that are available for crossdocking (as a supply),
7086 -- only Discrete and Flow/WOL entity types will create a putaway MOL.
7087 -- I believe the only info about the WIP job that is populated on the MOL is
7088 -- the WIP entity ID, along with the LPN Completion header ID.
7089 -- For WIP MOLs, the supply line ID and supply line detail ID are not used currently
7090 -- in either the Availability check, or the create reservations call.
7091 -- It should be safe for now to leave these values as is.
7092
7093 -- Get the WIP entity type for the WIP supply
7094 BEGIN
7095 SELECT entity_type
7096 INTO l_wip_entity_type
7097 FROM wip_entities
7098 WHERE wip_entity_id = l_supply_header_id
7099 AND organization_id = l_organization_id;
7100 EXCEPTION
7101 WHEN OTHERS THEN
7102 IF (l_debug = 1) THEN
7103 print_debug('1.1 - Error retrieving WIP entity type for WIP entity: ' ||
7104 l_supply_header_id);
7105 END IF;
7106 -- If an exception occurs, just skip to the end and do not crossdock
7107 -- the MOL supply line.
7108 GOTO end_crossdock;
7109 END;
7110 END IF;
7111 IF (l_debug = 1) THEN
7112 print_debug('1.1 - Supply type: ========> ' || l_supply_type_id);
7113 print_debug('1.1 - Supply header ID: ===> ' || l_supply_header_id);
7114 print_debug('1.1 - Supply line ID: =====> ' || l_supply_line_id);
7115 print_debug('1.1 - Supply line detail: => ' || l_supply_line_detail_id);
7116 print_debug('1.1 - WIP entity type: ====> ' || l_wip_entity_type);
7117 END IF;
7118 l_progress := '95';
7119
7120 -- Check that for WIP MOL supply lines, the WIP entity type
7121 -- must be 1 (Discrete) or 4 (Flow). Other WIP entity types are
7122 -- not supported for crossdocking in R12.
7123 IF (l_wip_entity_type IS NOT NULL AND l_wip_entity_type NOT IN (1, 4)) THEN
7124 IF (l_debug = 1) THEN
7125 print_debug('1.1 - Invalid WIP entity type for crossdocking!');
7126 END IF;
7127 GOTO end_crossdock;
7128 END IF;
7129 l_progress := '97';
7130
7131 -- Store necessary info from the MOL record
7132 l_supply_uom_code := l_mol_rec.uom_code;
7133 l_supply_expected_time := SYSDATE;
7134 l_mol_header_id := l_mol_rec.header_id;
7135 l_mol_line_id := l_mol_rec.line_id;
7136 l_mol_qty := l_mol_rec.quantity;
7137 l_mol_prim_qty := l_mol_rec.primary_quantity;
7138 l_mol_qty2 := l_mol_rec.secondary_quantity;
7139 l_mol_uom_code2 := l_mol_rec.secondary_uom_code;
7140 l_mol_lpn_id := l_mol_rec.lpn_id;
7141 l_inventory_item_id := l_mol_rec.inventory_item_id;
7142 l_primary_uom_code := l_mol_rec.primary_uom_code;
7143 l_reservable_type := l_mol_rec.reservable_type;
7144 l_lot_control_code := l_mol_rec.lot_control_code;
7145 l_lot_divisible_flag := l_mol_rec.lot_divisible_flag;
7146 l_progress := '100';
7147
7148 -- For WIP supply MOL of type Flow or Work Order Less Completion,
7149 -- check to see if a specific OE demand has been associated to it.
7150 -- If so, we only want to attempt crossdocking to this demand.
7151 IF (l_wip_entity_type = 4) THEN
7152 -- Retrieve the OE demand info the WIP Flow job was completed for
7153 BEGIN
7154 SELECT DECODE(ool.source_document_type_id, 10, 8, 2),
7155 wlc.demand_source_header_id, wlc.demand_source_line
7156 INTO l_wip_demand_type_id, l_wip_demand_header_id, l_wip_demand_line_id
7157 FROM wip_lpn_completions wlc, oe_order_lines_all ool
7158 WHERE wlc.header_id = l_mol_rec.reference_id
7159 -- MOL reference_id is link to header_id in WIP LPN Flow Completions table
7160 AND wlc.wip_entity_id = l_supply_header_id
7161 AND wlc.lpn_id = l_mol_lpn_id
7162 AND wlc.inventory_item_id = l_inventory_item_id
7163 AND wlc.organization_id = l_organization_id
7164 AND wlc.demand_source_line = ool.line_id (+);
7165 EXCEPTION
7166 WHEN OTHERS THEN
7167 IF (l_debug = 1) THEN
7168 print_debug('1.1 - Exception retrieving demand that WIP job was completed for');
7169 END IF;
7170 GOTO end_crossdock;
7171 END;
7172
7173 -- See if WIP flow job was completed for a specific OE demand
7174 IF (l_wip_demand_header_id IS NOT NULL) THEN
7175 IF (l_debug = 1) THEN
7176 print_debug('1.1 - OE demand WIP job was completed for:');
7177 print_debug('1.1 - Demand Source Type: => ' || l_wip_demand_type_id);
7178 print_debug('1.1 - Demand Header ID: ===> ' || l_wip_demand_header_id);
7179 print_debug('1.1 - Demand Line ID: =====> ' || l_wip_demand_line_id);
7180 END IF;
7181 ELSE
7182 -- Null out the WIP demand type ID since it was defaulted to 2 in this case
7183 l_wip_demand_type_id := NULL;
7184 IF (l_debug = 1) THEN
7185 print_debug('1.1 - WIP job was not completed for a specific OE demand');
7186 END IF;
7187 END IF;
7188 END IF;
7189 l_progress := '105';
7190
7191 -- For WIP supply MOL of type Discrete, check that multiple distinct reservations
7192 -- against this WIP job do not exist. If so, do not crossdock this.
7193 -- Also if a single distinct reservation does exist, only crossdock peg against
7194 -- this specific demand if it is of type OE.
7195 IF (l_wip_entity_type = 1) THEN
7196 -- See how many reservations exist for the WIP Discrete job
7197 BEGIN
7198 OPEN existing_wip_rsvs;
7199 FETCH existing_wip_rsvs BULK COLLECT INTO l_existing_wip_rsvs_tb;
7200 CLOSE existing_wip_rsvs;
7201 EXCEPTION
7202 WHEN OTHERS THEN
7203 IF (l_debug = 1) THEN
7204 print_debug('1.1 - Exception retrieving the existing WIP reservations');
7205 END IF;
7206 GOTO end_crossdock;
7207 END;
7208 IF (l_debug = 1) THEN
7209 print_debug('1.1 - # of distinct existing reservations for WIP Discrete job: ' ||
7210 l_existing_wip_rsvs_tb.COUNT);
7211 END IF;
7212
7213 -- Do not crossdock if multiple reservations exist
7214 IF (l_existing_wip_rsvs_tb.COUNT > 1) THEN
7215 IF (l_debug = 1) THEN
7216 print_debug('1.1 - Multiple distinct reservations exist for WIP Discrete job');
7217 print_debug('1.1 - Do not crossdock WIP supply line');
7218 END IF;
7219 GOTO end_crossdock;
7220 END IF;
7221
7222 -- If a single distinct reservation exists for the WIP Discrete job as supply,
7223 -- retrieve the demand tied to it.
7224 IF (l_existing_wip_rsvs_tb.COUNT = 1) THEN
7225 -- Retrieve the demand info on the reservation
7226 l_rsv_index := l_existing_wip_rsvs_tb.FIRST;
7227 l_wip_demand_type_id := l_existing_wip_rsvs_tb(l_rsv_index).demand_source_type_id;
7228 l_wip_demand_header_id := l_existing_wip_rsvs_tb(l_rsv_index).demand_source_header_id;
7229 l_wip_demand_line_id := l_existing_wip_rsvs_tb(l_rsv_index).demand_source_line_id;
7230
7231 -- If the demand that the WIP Discrete job is tied to is NOT of type OE,
7232 -- skip all processing and do not crossdock.
7233 IF (l_wip_demand_type_id NOT IN (2, 8)) THEN
7234 IF (l_debug = 1) THEN
7235 print_debug('1.1 - WIP Discrete job is reserved to a non-OE demand');
7236 print_debug('1.1 - Do not crossdock WIP supply line');
7237 END IF;
7238 GOTO end_crossdock;
7239 END IF;
7240
7241 IF (l_debug = 1) THEN
7242 print_debug('1.1 - OE demand WIP job is reserved against:');
7243 print_debug('1.1 - Demand Source Type: => ' || l_wip_demand_type_id);
7244 print_debug('1.1 - Demand Header ID: ===> ' || l_wip_demand_header_id);
7245 print_debug('1.1 - Demand Line ID: =====> ' || l_wip_demand_line_id);
7246 END IF;
7247 END IF;
7248
7249 -- No existing reservations tied to the WIP job
7250 IF (l_existing_wip_rsvs_tb.COUNT = 0) THEN
7251 IF (l_debug = 1) THEN
7252 print_debug('1.1 - No demand is reserved against the WIP job');
7253 END IF;
7254 END IF;
7255
7256 END IF; -- END IF matches: IF (l_wip_entity_type = 1) THEN
7257 l_progress := '107';
7258
7259 -- Make sure the item is reservable.
7260 -- {{
7261 -- Non-reservable items should not be crossdocked. }}
7262 IF (l_reservable_type = 2) THEN
7263 IF (l_debug = 1) THEN
7264 print_debug('1.1 - Do not crossdock non-reservable items');
7265 END IF;
7266 GOTO end_crossdock;
7267 END IF;
7268 l_progress := '110';
7269
7270 -- Make sure the item is lot divisible if the item is lot controlled.
7271 -- {{
7272 -- Lot Indivisible items should not be crossdocked. }}
7273 IF (l_lot_control_code = 2 AND l_lot_divisible_flag = 'N') THEN
7274 IF (l_debug = 1) THEN
7275 print_debug('1.1 - Do not crossdock lot indivisible items');
7276 END IF;
7277 GOTO end_crossdock;
7278 END IF;
7279 l_progress := '120';
7280
7281 -- 1.2 - Lock the set of MOLs related to the inputted supply line.
7282 -- {{
7283 -- Test for errors while locking the set of supply MOLs related to the input MOL. }}
7284 BEGIN
7285 OPEN lock_mo_lines(p_lpn_context => l_mol_rec.lpn_context,
7286 p_wip_entity_id => l_mol_rec.txn_source_id,
7287 p_operation_seq_num => l_mol_rec.txn_source_line_id,
7288 p_repetitive_schedule_id => l_mol_rec.reference_id);
7289 FETCH lock_mo_lines BULK COLLECT INTO l_locked_mo_lines_tb;
7290 -- If no valid MO lines are found, do not error out.
7291 -- Skip to the end and do not crossdock the MOL.
7292 IF (l_locked_mo_lines_tb.COUNT = 0) THEN
7293 IF (l_debug = 1) THEN
7294 print_debug('1.2 - No valid Move Order supply lines found');
7295 END IF;
7296 CLOSE lock_mo_lines;
7297 GOTO end_crossdock;
7298 END IF;
7299 CLOSE lock_mo_lines;
7300 EXCEPTION
7301 WHEN OTHERS THEN
7302 IF (l_debug = 1) THEN
7303 print_debug('1.2 - Could not lock the Move Order supply lines');
7304 END IF;
7305 -- If we cannot lock the Move Order lines, do not error out.
7306 -- Skip to the end and do not crossdock the MOL.
7307 GOTO end_crossdock;
7308 END;
7309 IF (l_debug = 1) THEN
7310 print_debug('1.2 - Successfully locked the set of Move Order lines');
7311 END IF;
7312 l_progress := '130';
7313
7314 -- 1.3 - Calculate the crossdock window given the crossdock criteria time parameters.
7315
7316 -- Get the time interval values for the crossdock criteria.
7317 -- Time intervals will be defined using the function NUMTODSINTERVAL
7318 -- Crossdock Window Time Interval
7319 l_xdock_window_interval := NUMTODSINTERVAL
7320 (g_crossdock_criteria_tb(l_crossdock_criteria_id).window_interval,
7321 g_crossdock_criteria_tb(l_crossdock_criteria_id).window_uom);
7322 IF (l_debug = 1) THEN
7323 print_debug('1.3 - Crossdock Window: ' ||
7324 g_crossdock_criteria_tb(l_crossdock_criteria_id).window_interval || ' ' ||
7325 g_crossdock_criteria_tb(l_crossdock_criteria_id).window_uom);
7326 END IF;
7327 -- Buffer Time Interval
7328 -- The buffer time interval and UOM should either both be NULL or not NULL.
7329 l_buffer_interval := NUMTODSINTERVAL
7330 (NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_interval, 0),
7331 NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_uom, 'HOUR'));
7332 IF (l_debug = 1) THEN
7333 print_debug('1.3 - Buffer Time: ' ||
7334 g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_interval || ' ' ||
7335 g_crossdock_criteria_tb(l_crossdock_criteria_id).buffer_uom);
7336 END IF;
7337 -- Order Processing Time Interval
7338 -- The order processing time interval and UOM should either both be NULL or not NULL.
7339 l_processing_interval := NUMTODSINTERVAL
7340 (NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_interval, 0),
7341 NVL(g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_uom, 'HOUR'));
7342 IF (l_debug = 1) THEN
7343 print_debug('1.3 - Order Processing Time: ' ||
7344 g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_interval || ' ' ||
7345 g_crossdock_criteria_tb(l_crossdock_criteria_id).processing_uom);
7346 END IF;
7347
7348 -- Calculate the crossdock window start and end times
7349 l_xdock_start_time := SYSDATE + l_processing_interval + l_buffer_interval;
7350 l_xdock_end_time := SYSDATE + l_processing_interval + l_buffer_interval +
7351 l_xdock_window_interval;
7352 IF (l_debug = 1) THEN
7353 print_debug('1.3 - Crossdock start time: => ' ||
7354 TO_CHAR(l_xdock_start_time, 'DD-MON-YYYY HH24:MI:SS'));
7355 print_debug('1.3 - Crossdock end time: ===> ' ||
7356 TO_CHAR(l_xdock_end_time, 'DD-MON-YYYY HH24:MI:SS'));
7357 END IF;
7358 l_progress := '140';
7359
7360 -- Section 2: Crossdocking existing high level reservations
7361 -- For the inputted Move Order supply line, query to see if any existing high level
7362 -- reservations exist. If they do, we should try to detail those first.
7363 -- 2.1 - Query for and lock existing high level reservations for the MO supply line.
7364 -- - If a reservation cannot be locked, do not pick up the record for crossdocking.
7365 -- - Check that the UOM on the MOL supply and reservation match if UOM integrity is Yes.
7366 -- - For WIP MOL supply with existing reservations, calculate the WIP crossdocked qty.
7367 -- Get the total quantity for crossdocked MOLs from the same WIP job to the same demand.
7368 -- 2.2 - Query for and lock the available WDD demand line(s) with a released status of
7369 -- 'R' or 'B' tied to the order line on the reservation.
7370 -- - If cross project allocation is not allowed and the org is PJM enabled, make sure
7371 -- the project and task values on the MO supply line matches the demand.
7372 -- 2.3 - For each valid WDD demand, check that it is valid for crossdocking.
7373 -- - Demand source type must be allowed on the crossdock criteria.
7374 -- - Demand expected ship time must lie within the crossdock time window.
7375 -- 2.4 - Crossdock detail the reservation and update the demand and supply line records.
7376 -- 2.5 - If quantity still remains on the MOL to be crossdocked, see how much reservable
7377 -- quantity on the supply is actually available for crossdocking.
7378
7379 -- 2.1 - Query for and lock existing high level reservations for the MO supply line.
7380 -- - If a reservation cannot be locked, do not pick up the record for crossdocking.
7381 -- - Check that the UOM on the MOL supply and reservation match if UOM integrity is Yes.
7382 -- {{
7383 -- Test for MO supply lines with existing high level reservations.
7384 -- The possible demand source types for these reservations are:
7385 -- Sales Order (scheduled)
7386 -- Sales Order (backordered)
7387 -- Internal Order (scheduled)
7388 -- Internal Order (backordered) }}
7389 -- {{
7390 -- Test where an existing reservation is already locked. This record should not be
7391 -- picked up for crossdocking. }}
7392 -- {{
7393 -- Test for both OE and WIP MO supply lines with existing reservations. }}
7394 IF (l_debug = 1) THEN
7395 print_debug('2.1 - Query for existing high level reservations for the MO supply line');
7396 END IF;
7397 -- Initialize the table we are fetching records into.
7398 l_existing_rsvs_tb.DELETE;
7399 BEGIN
7400 OPEN existing_rsvs_cursor(p_lpn_context => l_mol_rec.lpn_context,
7401 p_wip_entity_id => l_mol_rec.txn_source_id);
7402 FETCH existing_rsvs_cursor BULK COLLECT INTO l_existing_rsvs_tb;
7403 CLOSE existing_rsvs_cursor;
7404 EXCEPTION
7405 WHEN OTHERS THEN
7406 IF (l_debug = 1) THEN
7407 print_debug('2.1 - Exception retrieving the existing reservations');
7408 END IF;
7409 GOTO after_existing_rsvs;
7410 --RAISE fnd_api.g_exc_unexpected_error;
7411 END;
7412 l_progress := '150';
7413
7414 -- Loop through the existing reservations and try to crossdock them
7415 l_rsv_index := l_existing_rsvs_tb.FIRST;
7416 LOOP
7417 -- If no existing reservations were found, exit out of loop.
7418 IF (l_existing_rsvs_tb.COUNT = 0) THEN
7419 IF (l_debug = 1) THEN
7420 print_debug('2.1 - No existing reservations to crossdock');
7421 END IF;
7422 EXIT;
7423 END IF;
7424
7425 -- Retrieve necessary parameters for the demand order line from the current reservation
7426 l_rsv_id := l_existing_rsvs_tb(l_rsv_index).reservation_id;
7427 l_rsv_qty := l_existing_rsvs_tb(l_rsv_index).reservation_quantity;
7428 l_rsv_uom_code := l_existing_rsvs_tb(l_rsv_index).reservation_uom_code;
7429 l_rsv_qty2 := l_existing_rsvs_tb(l_rsv_index).secondary_reservation_quantity;
7430 l_rsv_uom_code2 := l_existing_rsvs_tb(l_rsv_index).secondary_uom_code;
7431 l_rsv_prim_qty := l_existing_rsvs_tb(l_rsv_index).primary_reservation_quantity;
7432 l_rsv_prim_uom_code := l_existing_rsvs_tb(l_rsv_index).primary_uom_code;
7433 l_demand_type_id := l_existing_rsvs_tb(l_rsv_index).demand_source_type_id;
7434 l_demand_so_header_id := l_existing_rsvs_tb(l_rsv_index).demand_source_header_id;
7435 l_demand_line_id := l_existing_rsvs_tb(l_rsv_index).demand_source_line_id;
7436
7437 -- Get the demand OE header ID from the Sales Order header ID
7438 inv_salesorder.get_oeheader_for_salesorder
7439 (p_salesorder_id => l_demand_so_header_id,
7440 x_oe_header_id => l_demand_header_id,
7441 x_return_status => x_return_status);
7442
7443 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
7444 IF (l_debug = 1) THEN
7445 print_debug('2.1 - Error returned from get_oeheader_for_salesorder API: '
7446 || x_return_status);
7447 END IF;
7448 GOTO next_reservation;
7449 END IF;
7450
7451 IF (l_debug = 1) THEN
7452 print_debug('2.1 - Reservation ID: ========> ' || l_rsv_id);
7453 print_debug('2.1 - Reservation Quantity: ==> ' || l_rsv_qty || ' ' ||
7454 l_rsv_uom_code);
7455 print_debug('2.1 - Reservation Quantity2: => ' || l_rsv_qty2 || ' ' ||
7456 l_rsv_uom_code2);
7457 print_debug('2.1 - Reservation Prim Qty: ==> ' || l_rsv_prim_qty || ' ' ||
7458 l_rsv_prim_uom_code);
7459 print_debug('2.1 - Demand source type ID: => ' || l_demand_type_id);
7460 print_debug('2.1 - Demand SO header ID: ===> ' || l_demand_so_header_id);
7461 print_debug('2.1 - Demand header ID: ======> ' || l_demand_header_id);
7462 print_debug('2.1 - Demand line ID: ========> ' || l_demand_line_id);
7463 END IF;
7464 l_progress := '160';
7465
7466 -- Make sure the primary UOM code on the reservation matches the one for the item.
7467 -- This error condition should not come about but if it does, just skip this
7468 -- reservation and go to the next one.
7469 IF (l_primary_uom_code <> l_rsv_prim_uom_code) THEN
7470 IF (l_debug = 1) THEN
7471 print_debug('2.1 - Item and reservation primary UOM codes do not match!');
7472 END IF;
7473 GOTO next_reservation;
7474 END IF;
7475
7476 -- Check that the UOM on the MOL supply and reservation match if UOM integrity is Yes.
7477 -- {{
7478 -- Test for a crossdock criteria where UOM Integrity is Yes and the existing reservation
7479 -- has a different UOM from the MOL supply lines. }}
7480 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).uom_integrity_flag = 1 AND
7481 l_rsv_uom_code <> l_supply_uom_code) THEN
7482 IF (l_debug = 1) THEN
7483 print_debug('2.1 - RSV and MOL UOM codes do not match and UOM Integrity is Yes!');
7484 END IF;
7485 GOTO next_reservation;
7486 END IF;
7487 l_progress := '170';
7488
7489 -- - For WIP MOL supply with existing reservations, calculate the WIP crossdocked qty.
7490 -- Get the total quantity for crossdocked MOLs from the same WIP job to the same demand.
7491 -- {{
7492 -- Test for WIP MOL supply line where another MOL from the same WIP job is already
7493 -- satisfying part of an existing reservation. That quantity should be decremented
7494 -- from the reservation when deciding on how much quantity to detail. }}
7495 IF (l_supply_type_id = 5) THEN
7496 -- Retrieve the Primary qty for other WIP MOLs for the same WIP job that have
7497 -- already been pegged to this existing reservation.
7498 IF (l_debug = 1) THEN
7499 print_debug('2.1 - Retrieve the WIP crossdocked qty');
7500 END IF;
7501 BEGIN
7502 OPEN get_wip_xdock_qty(p_wip_entity_id => l_mol_rec.txn_source_id,
7503 p_operation_seq_num => l_mol_rec.txn_source_line_id,
7504 p_repetitive_schedule_id => l_mol_rec.reference_id,
7505 p_demand_source_header_id => l_demand_header_id,
7506 p_demand_source_line_id => l_demand_line_id);
7507 FETCH get_wip_xdock_qty INTO l_wip_xdock_prim_qty;
7508 IF (get_wip_xdock_qty%NOTFOUND) THEN
7509 l_wip_xdock_prim_qty := 0;
7510 END IF;
7511 CLOSE get_wip_xdock_qty;
7512 EXCEPTION
7513 WHEN OTHERS THEN
7514 IF (l_debug = 1) THEN
7515 print_debug('2.1 - Exception retrieving the WIP crossdocked qty');
7516 END IF;
7517 GOTO after_existing_rsvs;
7518 END;
7519 IF (l_debug = 1) THEN
7520 print_debug('2.1 - WIP crossdocked qty: ' || l_wip_xdock_prim_qty || ' '
7521 || l_primary_uom_code);
7522 END IF;
7523
7524 -- Decrement the reservation quantity to be crossdocked if part of it
7525 -- is already satisfied by existing crossdocked WIP MOLs.
7526 IF (l_wip_xdock_prim_qty <> 0) THEN
7527 -- Decrement the RSV qty
7528 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
7529 l_primary_uom_code, l_rsv_uom_code);
7530 IF (l_conversion_rate < 0) THEN
7531 IF (l_debug = 1) THEN
7532 print_debug('2.1 - Error while obtaining UOM conversion rate for RSV qty');
7533 END IF;
7534 GOTO next_reservation;
7535 END IF;
7536 -- Round the converted quantity to the standard precision
7537 l_wip_xdock_qty := ROUND(l_conversion_rate * l_wip_xdock_prim_qty, l_conversion_precision);
7538 l_rsv_qty := l_rsv_qty - l_wip_xdock_qty;
7539 IF (l_debug = 1) THEN
7540 print_debug('2.1 - Adjusted RSV Qty: ======> ' || l_rsv_qty || ' ' ||
7541 l_rsv_uom_code);
7542 END IF;
7543
7544 -- If the reservation has no quantity left on it to be satisfied,
7545 -- skip to the next available reservation.
7546 IF (l_rsv_qty = 0) THEN
7547 GOTO next_reservation;
7548 END IF;
7549
7550 -- Decrement the RSV qty2
7551 IF (l_rsv_uom_code2 IS NOT NULL) THEN
7552 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
7553 l_primary_uom_code, l_rsv_uom_code2);
7554 IF (l_conversion_rate < 0) THEN
7555 IF (l_debug = 1) THEN
7556 print_debug('2.1 - Error while obtaining UOM conversion rate for RSV qty2');
7557 END IF;
7558 GOTO next_reservation;
7559 END IF;
7560 -- Round the converted quantity to the standard precision
7561 l_wip_xdock_qty2 := ROUND(l_conversion_rate * l_wip_xdock_prim_qty, l_conversion_precision);
7562 l_rsv_qty2 := l_rsv_qty2 - l_wip_xdock_qty2;
7563 IF (l_debug = 1) THEN
7564 print_debug('2.1 - Adjusted RSV Qty2: =====> ' || l_rsv_qty2 || ' ' ||
7565 l_rsv_uom_code2);
7566 END IF;
7567 END IF;
7568
7569 -- Decrement the RSV primary qty
7570 l_rsv_prim_qty := l_rsv_prim_qty - l_wip_xdock_prim_qty;
7571 IF (l_debug = 1) THEN
7572 print_debug('2.1 - Adjusted RSV Prim Qty: => ' || l_rsv_prim_qty || ' ' ||
7573 l_rsv_prim_uom_code);
7574 END IF;
7575 END IF; -- End IF matches: IF (l_wip_xdock_prim_qty <> 0) THEN
7576 END IF; -- End Calculating WIP crossdocked qty
7577 l_progress := '175';
7578
7579 -- 2.2 - Query for and lock the available WDD demand line(s) with a released status of
7580 -- 'R' or 'B' tied to the order line on the reservation.
7581 -- - If cross project allocation is not allowed and the org is PJM enabled, make sure
7582 -- the project and task values on the MO supply line matches the demand.
7583
7584 -- Initialize the table we are fetching records into.
7585 l_reserved_wdd_lines_tb.DELETE;
7586 BEGIN
7587 OPEN reserved_wdd_lines(l_mol_rec.project_id, l_mol_rec.task_id);
7588 FETCH reserved_wdd_lines BULK COLLECT INTO l_reserved_wdd_lines_tb;
7589 CLOSE reserved_wdd_lines;
7590 EXCEPTION
7591 WHEN OTHERS THEN
7592 IF (l_debug = 1) THEN
7593 print_debug('2.2 - Exception retrieving the reserved WDD demand lines');
7594 END IF;
7595 GOTO next_reservation;
7596 --RAISE fnd_api.g_exc_unexpected_error;
7597 END;
7598 l_progress := '180';
7599
7600 -- Loop through the available WDD lines and try to crossdock the valid ones
7601 l_wdd_index := l_reserved_wdd_lines_tb.FIRST;
7602 LOOP
7603 -- Define a savepoint so if an exception occurs while updating database records such
7604 -- as WDD, RSV, or MOL, we need to rollback the changes and goto the next reserved
7605 -- WDD demand line to crossdock (if one exists).
7606 SAVEPOINT Reserved_WDD_sp;
7607
7608 -- Initialize the variable below used for updating crossdocked WDD records,
7609 -- in case we need to rollback the changes to local PLSQL data structures.
7610 l_xdocked_wdd_index := NULL;
7611
7612 -- If no valid reserved WDD lines were found, exit out of loop.
7613 -- This should not happen if the reservation was allowed to be created.
7614 IF (l_reserved_wdd_lines_tb.COUNT = 0) THEN
7615 IF (l_debug = 1) THEN
7616 print_debug('2.2 - No valid reserved WDD lines to crossdock');
7617 END IF;
7618 EXIT;
7619 END IF;
7620
7621 -- Retrieve necessary parameters for the demand order line from the current reservation
7622 l_demand_line_detail_id := l_reserved_wdd_lines_tb(l_wdd_index).delivery_detail_id;
7623 l_demand_qty := l_reserved_wdd_lines_tb(l_wdd_index).requested_quantity;
7624 l_demand_uom_code := l_reserved_wdd_lines_tb(l_wdd_index).requested_quantity_uom;
7625 l_demand_qty2 := l_reserved_wdd_lines_tb(l_wdd_index).requested_quantity2;
7626 l_demand_uom_code2 := l_reserved_wdd_lines_tb(l_wdd_index).requested_quantity_uom2;
7627 l_demand_status := l_reserved_wdd_lines_tb(l_wdd_index).released_status;
7628 l_demand_project_id := l_reserved_wdd_lines_tb(l_wdd_index).project_id;
7629 l_demand_task_id := l_reserved_wdd_lines_tb(l_wdd_index).task_id;
7630 -- Set the WIP variables to NULL since the demand line is an OE WDD demand
7631 l_wip_entity_id := NULL;
7632 l_operation_seq_num := NULL;
7633 l_repetitive_schedule_id := NULL;
7634 l_wip_supply_type := NULL;
7635
7636 IF (l_debug = 1) THEN
7637 print_debug('2.2 - Current reserved WDD line to check for crossdock:');
7638 print_debug('2.2 - Demand line detail ID: ==> ' || l_demand_line_detail_id);
7639 print_debug('2.2 - Demand line qty: ========> ' || l_demand_qty || ' ' ||
7640 l_demand_uom_code);
7641 print_debug('2.2 - Demand line qty2: =======> ' || l_demand_qty2 || ' ' ||
7642 l_demand_uom_code2);
7643 print_debug('2.2 - Demand Released Status: => ' || l_demand_status);
7644 print_debug('2.2 - Demand Project ID: ======> ' || l_demand_project_id);
7645 print_debug('2.2 - Demand Task ID: =========> ' || l_demand_task_id);
7646 END IF;
7647
7648 -- 2.3 - For each valid WDD demand, check that it is valid for crossdocking.
7649 -- - Demand source type must be allowed on the crossdock criteria.
7650 -- - Demand expected ship time must lie within the crossdock time window.
7651 IF (l_debug = 1) THEN
7652 print_debug('2.3 - Check if the current reserved WDD line is valid for crossdocking');
7653 END IF;
7654
7655 -- Set the appropriate Opportunistic Crossdock demand source code. This uses a different
7656 -- set of lookup values compared to the reservations demand source codes.
7657 IF (l_demand_type_id = 2 AND l_demand_status = 'R') THEN
7658 -- Sales Order (Scheduled)
7659 l_demand_src_code := G_OPP_DEM_SO_SCHED;
7660 ELSIF (l_demand_type_id = 2 AND l_demand_status = 'B') THEN
7661 -- Sales Order (Backordered)
7662 l_demand_src_code := G_OPP_DEM_SO_BKORD;
7663 ELSIF (l_demand_type_id = 8 AND l_demand_status = 'R') THEN
7664 -- Internal Order (Scheduled)
7665 l_demand_src_code := G_OPP_DEM_IO_SCHED;
7666 ELSIF (l_demand_type_id = 8 AND l_demand_status = 'B') THEN
7667 -- Internal Order (Backordered)
7668 l_demand_src_code := G_OPP_DEM_IO_BKORD;
7669 ELSE
7670 -- Invalid demand for crossdocking.
7671 -- {{
7672 -- For prior existing reservations that are not supported for crossdocking (WIP),
7673 -- make sure we do not try to crossdock them. }}
7674 GOTO next_reserved_wdd;
7675 END IF;
7676 IF (l_debug = 1) THEN
7677 print_debug('2.3 - Crossdock Demand Source Code: => ' || l_demand_src_code);
7678 END IF;
7679 l_progress := '190';
7680
7681 -- Demand source type must be allowed on the crossdock criteria.
7682 -- Check if the demand line tied to the reservation is valid for crossdocking
7683 -- based on the valid demand types allowed for the crossdock criteria.
7684 -- {{
7685 -- Test for existing reservations for valid demand types to crossdock which are
7686 -- not allowed on the crossdock criteria. Processing should stop and the next
7687 -- reserved WDD demand should be considered for crossdocking. }}
7688 IF (NOT WMS_XDOCK_UTILS_PVT.Is_Eligible_Demand_Source
7689 (p_criterion_id => l_crossdock_criteria_id,
7690 p_source_code => l_demand_src_code)) THEN
7691 -- Demand line on reservation is not valid source for crossdocking
7692 IF (l_debug = 1) THEN
7693 print_debug('2.3 - WDD Demand line on reservation is not a valid source');
7694 END IF;
7695 GOTO next_reserved_wdd;
7696 END IF;
7697 l_progress := '200';
7698
7699 -- Demand expected ship time must lie within the crossdock time window.
7700 -- Check if the demand line tied to the reservation is valid for crossdocking
7701 -- based on the crossdock window for the crossdock criteria.
7702 IF (l_debug = 1) THEN
7703 print_debug('2.3 - Determine the expected ship time for the demand line');
7704 END IF;
7705 Get_Expected_Time
7706 (p_source_type_id => l_demand_type_id,
7707 p_source_header_id => l_demand_so_header_id,
7708 p_source_line_id => l_demand_line_id,
7709 p_source_line_detail_id => l_demand_line_detail_id,
7710 p_supply_or_demand => G_SRC_TYPE_DEM,
7711 p_crossdock_criterion_id => l_crossdock_criteria_id,
7712 x_return_status => x_return_status,
7713 x_msg_count => x_msg_count,
7714 x_msg_data => x_msg_data,
7715 x_dock_start_time => l_dock_start_time,
7716 x_dock_mean_time => l_dock_mean_time,
7717 x_dock_end_time => l_dock_end_time,
7718 x_expected_time => l_demand_expected_time);
7719
7720 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
7721 IF (l_debug = 1) THEN
7722 print_debug('2.3 - Success returned from Get_Expected_Time API');
7723 END IF;
7724 ELSE
7725 IF (l_debug = 1) THEN
7726 print_debug('2.3 - Failure returned from Get_Expected_Time API');
7727 END IF;
7728 GOTO next_reserved_wdd;
7729 --RAISE fnd_api.g_exc_error;
7730 END IF;
7731
7732 -- Do not crossdock the demand line on the reservation if an expected ship
7733 -- time cannot be determined.
7734 -- {{
7735 -- If an expected ship time for the demand line on an existing reservation
7736 -- cannot be determined, skip processing and move on to the next reserved WDD
7737 -- demand. }}
7738 IF (l_demand_expected_time IS NULL) THEN
7739 IF (l_debug = 1) THEN
7740 print_debug('2.3 - Unable to crossdock reservation since demand expected time is NULL');
7741 END IF;
7742 GOTO next_reserved_wdd;
7743 END IF;
7744 IF (l_debug = 1) THEN
7745 print_debug('2.3 - Demand expected time: => ' ||
7746 TO_CHAR(l_demand_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
7747 END IF;
7748 l_progress := '210';
7749
7750 -- See if the WDD demand line lies within the crossdock time window.
7751 -- If a dock appointment for the demand does not exist and the crossdock criteria
7752 -- allows rescheduling of the demand for anytime on the expected ship date, set the
7753 -- appropriate logic to determine if the demand is valid.
7754 -- Demands with an expected ship time in the past are considered as ready to ship out
7755 -- immediately. Thus they are all valid for Opportunistic Crossdocking.
7756 -- {{
7757 -- Test for a demand line on an existing reservation that does not have a dock appointment
7758 -- and demand reschedule is allowed. }}
7759 -- {{
7760 -- Test for a demand line on an existing reservation lying within the crossdock window. }}
7761 -- {{
7762 -- Test for a demand line on an existing reservation not lying within the crossdock
7763 -- window. In this case, we cannot crossdock the existing reservation so just move
7764 -- on to the next reserved WDD. }}
7765 IF ((l_dock_start_time IS NULL AND
7766 g_crossdock_criteria_tb(l_crossdock_criteria_id).allow_demand_reschedule_flag = 1 AND
7767 l_demand_expected_time BETWEEN TRUNC(l_xdock_start_time) AND
7768 TO_DATE(TO_CHAR(TRUNC(l_xdock_end_time), 'DD-MON-YYYY') ||
7769 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
7770 OR (l_demand_expected_time < SYSDATE)
7771 OR (l_demand_expected_time BETWEEN l_xdock_start_time AND l_xdock_end_time)) THEN
7772 -- Demand is valid for crossdocking based on crossdock time window
7773 IF (l_debug = 1) THEN
7774 print_debug('2.3 - Demand line is within the crossdock window');
7775 END IF;
7776 ELSE
7777 -- Demand is not valid for crossdocking so skip to the next
7778 -- reserved WDD demand to crossdock
7779 IF (l_debug = 1) THEN
7780 print_debug('2.3 - Demand line is not within the crossdock window');
7781 END IF;
7782 GOTO next_reserved_wdd;
7783 END IF;
7784 l_progress := '220';
7785
7786 -- 2.4 - Crossdock detail the reservation and update the demand and supply line records.
7787 IF (l_debug = 1) THEN
7788 print_debug('2.4 - Crossdock detail the relevant records: RSV, WDD, MOL');
7789 END IF;
7790
7791 -- Convert the WDD qty to the UOM on the supply line.
7792 -- Retrieve the conversion rate for the item/from UOM/to UOM combination.
7793 -- {{
7794 -- Test that the WDD quantity is converted properly to the UOM on the supply line. }}
7795 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
7796 l_demand_uom_code, l_supply_uom_code);
7797 IF (l_conversion_rate < 0) THEN
7798 IF (l_debug = 1) THEN
7799 print_debug('2.4 - Error while obtaining UOM conversion rate for WDD qty');
7800 END IF;
7801 -- Rollback any db changes that might have occurred (currently none).
7802 ROLLBACK TO Reserved_WDD_sp;
7803 -- Process the next existing reserved WDD.
7804 GOTO next_reserved_wdd;
7805 END IF;
7806 -- Round the converted quantity to the standard precision
7807 l_wdd_txn_qty := ROUND(l_conversion_rate * l_demand_qty, l_conversion_precision);
7808 IF (l_debug = 1) THEN
7809 print_debug('2.4 - WDD qty: =====> ' || l_demand_qty || ' ' || l_demand_uom_code);
7810 print_debug('2.4 - WDD txn qty: => ' || l_wdd_txn_qty || ' ' || l_supply_uom_code);
7811 END IF;
7812 l_progress := '230';
7813
7814 -- Convert the RSV qty to the UOM on the supply line.
7815 -- Retrieve the conversion rate for the item/from UOM/to UOM combination.
7816 -- {{
7817 -- Test that the RSV quantity is converted properly to the UOM on the supply line. }}
7818 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
7819 l_rsv_uom_code, l_supply_uom_code);
7820 IF (l_conversion_rate < 0) THEN
7821 IF (l_debug = 1) THEN
7822 print_debug('2.4 - Error while obtaining UOM conversion rate for RSV qty');
7823 END IF;
7824 -- Rollback any db changes that might have occurred (currently none).
7825 ROLLBACK TO Reserved_WDD_sp;
7826 -- Process the next existing reserved WDD.
7827 GOTO next_reserved_wdd;
7828 END IF;
7829 -- Round the converted quantity to the standard precision
7830 l_rsv_txn_qty := ROUND(l_conversion_rate * l_rsv_qty, l_conversion_precision);
7831 IF (l_debug = 1) THEN
7832 print_debug('2.4 - RSV qty: =====> ' || l_rsv_qty || ' ' || l_rsv_uom_code);
7833 print_debug('2.4 - RSV txn qty: => ' || l_rsv_txn_qty || ' ' || l_supply_uom_code);
7834 END IF;
7835 l_progress := '240';
7836
7837 -- Calculate the Available to Detail quantity.
7838 -- {{
7839 -- Test that the available to detail quantity is calculated properly,
7840 -- i.e. is lower than WDD, RSV, and MOL qty, and is an integer value if
7841 -- UOM integrity = 'Y'. }}
7842 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).uom_integrity_flag = 1) THEN
7843 -- UOM Integrity is 'Yes'
7844 l_atd_qty := LEAST(FLOOR(l_wdd_txn_qty), FLOOR(l_rsv_txn_qty), FLOOR(l_mol_qty));
7845 ELSE
7846 -- UOM Integrity is 'No'
7847 l_atd_qty := LEAST(l_wdd_txn_qty, l_rsv_txn_qty, l_mol_qty);
7848 END IF;
7849 IF (l_debug = 1) THEN
7850 print_debug('2.4 - Available to detail qty: ' || l_atd_qty || ' ' ||
7851 l_supply_uom_code);
7852 END IF;
7853 -- If the ATD qty is 0, then goto the next reserved WDD to crossdock.
7854 -- This is possible if the UOM integrity flag is 'Y' and the resultant quantities
7855 -- were floored to 0.
7856 -- {{
7857 -- Test for ATD qty = 0. This can come about if UOM integrity is Yes and the
7858 -- demand, reservation or supply line gets floored to 0. }}
7859 IF (l_atd_qty = 0) THEN
7860 IF (l_debug = 1) THEN
7861 print_debug('2.4 - No available qty to detail for this WDD/RSV/MOL combination');
7862 END IF;
7863 -- Rollback any db changes that might have occurred (currently none).
7864 ROLLBACK TO Reserved_WDD_sp;
7865 -- Process the next existing reserved WDD.
7866 GOTO next_reserved_wdd;
7867 END IF;
7868 l_progress := '250';
7869
7870 -- Convert l_atd_qty to the primary UOM
7871 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
7872 l_supply_uom_code, l_primary_uom_code);
7873 IF (l_conversion_rate < 0) THEN
7874 IF (l_debug = 1) THEN
7875 print_debug('2.4 - Error while obtaining primary UOM conversion rate for ATD qty');
7876 END IF;
7877 -- Rollback any db changes that might have occurred (currently none).
7878 ROLLBACK TO Reserved_WDD_sp;
7879 -- Process the next existing reserved WDD.
7880 GOTO next_reserved_wdd;
7881 END IF;
7882 -- Round the converted quantity to the standard precision
7883 l_atd_prim_qty := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
7884 IF (l_debug = 1) THEN
7885 print_debug('2.4 - ATD qty in primary UOM: => ' || l_atd_prim_qty || ' ' ||
7886 l_primary_uom_code);
7887 END IF;
7888 l_progress := '260';
7889
7890 -- Crossdock the WDD record, splitting it if necessary.
7891 IF (l_debug = 1) THEN
7892 print_debug('2.4 - Call the Crossdock_WDD API to crossdock/split the WDD');
7893 END IF;
7894 Crossdock_WDD
7895 (p_log_prefix => '2.4 - ',
7896 p_crossdock_type => G_CRT_TYPE_OPP,
7897 p_batch_id => l_batch_id,
7898 p_wsh_release_table => l_wsh_release_table,
7899 p_trolin_delivery_ids => l_trolin_delivery_ids,
7900 p_del_detail_id => l_del_detail_id,
7901 l_wdd_index => l_dummy_wdd_index,
7902 l_debug => l_debug,
7903 l_inventory_item_id => l_inventory_item_id,
7904 l_wdd_txn_qty => l_wdd_txn_qty,
7905 l_atd_qty => l_atd_qty,
7906 l_atd_wdd_qty => l_atd_wdd_qty,
7907 l_atd_wdd_qty2 => l_atd_wdd_qty2,
7908 l_supply_uom_code => l_supply_uom_code,
7909 l_demand_uom_code => l_demand_uom_code,
7910 l_demand_uom_code2 => l_demand_uom_code2,
7911 l_conversion_rate => l_conversion_rate,
7912 l_conversion_precision => l_conversion_precision,
7913 l_demand_line_detail_id => l_demand_line_detail_id,
7914 l_index => l_index,
7915 l_detail_id_tab => l_detail_id_tab,
7916 l_action_prms => l_action_prms,
7917 l_action_out_rec => l_action_out_rec,
7918 l_split_wdd_id => l_split_wdd_id,
7919 l_detail_info_tab => l_detail_info_tab,
7920 l_in_rec => l_in_rec,
7921 l_out_rec => l_out_rec,
7922 l_mol_line_id => l_mol_line_id,
7923 l_split_wdd_index => l_split_wdd_index,
7924 l_split_delivery_index => l_split_delivery_index,
7925 l_split_wdd_rel_rec => l_split_wdd_rel_rec,
7926 l_allocation_method => l_allocation_method,
7927 l_demand_qty => l_demand_qty,
7928 l_demand_qty2 => l_demand_qty2,
7929 l_demand_atr_qty => l_demand_atr_qty,
7930 l_xdocked_wdd_index => l_xdocked_wdd_index,
7931 l_supply_type_id => l_supply_type_id,
7932 x_return_status => x_return_status,
7933 x_msg_count => x_msg_count,
7934 x_msg_data => x_msg_data,
7935 x_error_code => l_error_code
7936 );
7937
7938 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
7939 IF (l_debug = 1) THEN
7940 print_debug('2.4 - Error returned from Crossdock_WDD API: '
7941 || x_return_status);
7942 END IF;
7943 --RAISE fnd_api.g_exc_error;
7944 -- If an exception occurs while modifying a database record, rollback the changes
7945 -- and just go to the next WDD record or reservation to crossdock.
7946 ROLLBACK TO Reserved_WDD_sp;
7947 -- We need to also rollback changes done to local PLSQL data structures
7948 IF (l_xdocked_wdd_index IS NOT NULL) THEN
7949 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
7950 END IF;
7951 -- Process the next existing reserved WDD.
7952 GOTO next_reserved_wdd;
7953 ELSE
7954 IF (l_debug = 1) THEN
7955 print_debug('2.4 - Successfully crossdocked/split the WDD record');
7956 END IF;
7957 END IF;
7958 l_progress := '270';
7959
7960
7961 -- Crossdock the RSV record, splitting it if necessary.
7962 -- Do not modify the reservation if supply is of type WIP.
7963 IF (l_debug = 1) THEN
7964 print_debug('2.4 - Call the Crossdock_RSV API to crossdock/split the RSV');
7965 END IF;
7966 Crossdock_RSV
7967 (p_log_prefix => '2.4 - ',
7968 p_crossdock_type => G_CRT_TYPE_OPP,
7969 l_debug => l_debug,
7970 l_inventory_item_id => l_inventory_item_id,
7971 l_rsv_txn_qty => l_rsv_txn_qty,
7972 l_atd_qty => l_atd_qty,
7973 l_atd_rsv_qty => l_atd_rsv_qty,
7974 l_atd_rsv_qty2 => l_atd_rsv_qty2,
7975 l_atd_prim_qty => l_atd_prim_qty,
7976 l_supply_uom_code => l_supply_uom_code,
7977 l_rsv_uom_code => l_rsv_uom_code,
7978 l_rsv_uom_code2 => l_rsv_uom_code2,
7979 l_primary_uom_code => l_primary_uom_code,
7980 l_conversion_rate => l_conversion_rate,
7981 l_conversion_precision => l_conversion_precision,
7982 l_original_rsv_rec => l_original_rsv_rec,
7983 l_rsv_id => l_rsv_id,
7984 l_to_rsv_rec => l_to_rsv_rec,
7985 l_split_wdd_id => l_split_wdd_id,
7986 l_crossdock_criteria_id => l_crossdock_criteria_id,
7987 l_demand_expected_time => l_demand_expected_time,
7988 l_supply_expected_time => l_supply_expected_time,
7989 l_original_serial_number => l_original_serial_number,
7990 l_split_rsv_id => l_split_rsv_id,
7991 l_rsv_qty => l_rsv_qty,
7992 l_rsv_qty2 => l_rsv_qty2,
7993 l_to_serial_number => l_to_serial_number,
7994 l_supply_type_id => l_supply_type_id,
7995 x_return_status => x_return_status,
7996 x_msg_count => x_msg_count,
7997 x_msg_data => x_msg_data,
7998 x_error_code => l_error_code
7999 );
8000
8001 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
8002 IF (l_debug = 1) THEN
8003 print_debug('2.4 - Error returned from Crossdock_RSV API: '
8004 || x_return_status);
8005 END IF;
8006 --RAISE fnd_api.g_exc_error;
8007 -- If an exception occurs while modifying a database record, rollback the changes
8008 -- and just go to the next WDD record or reservation to crossdock.
8009 ROLLBACK TO Reserved_WDD_sp;
8010 -- We need to also rollback changes done to local PLSQL data structures
8011 IF (l_xdocked_wdd_index IS NOT NULL) THEN
8012 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
8013 END IF;
8014 -- Process the next existing reserved WDD.
8015 GOTO next_reserved_wdd;
8016 ELSE
8017 IF (l_debug = 1) THEN
8018 print_debug('2.4 - Successfully crossdocked/split the RSV record');
8019 END IF;
8020 END IF;
8021 l_progress := '280';
8022
8023
8024 -- Crossdock the MOL record, splitting it if necessary
8025 IF (l_debug = 1) THEN
8026 print_debug('2.4 - Call the Crossdock_MOL API to crossdock/split the MOL');
8027 END IF;
8028 Crossdock_MOL
8029 (p_log_prefix => '2.4 - ',
8030 p_crossdock_type => G_CRT_TYPE_OPP,
8031 l_debug => l_debug,
8032 l_inventory_item_id => l_inventory_item_id,
8033 l_mol_qty => l_mol_qty,
8034 l_mol_qty2 => l_mol_qty2,
8035 l_atd_qty => l_atd_qty,
8036 l_atd_mol_qty2 => l_atd_mol_qty2,
8037 l_supply_uom_code => l_supply_uom_code,
8038 l_mol_uom_code2 => l_mol_uom_code2,
8039 l_conversion_rate => l_conversion_rate,
8040 l_conversion_precision => l_conversion_precision,
8041 l_mol_prim_qty => l_mol_prim_qty,
8042 l_atd_prim_qty => l_atd_prim_qty,
8043 l_split_wdd_id => l_split_wdd_id,
8044 l_mol_header_id => l_mol_header_id,
8045 l_mol_line_id => l_mol_line_id,
8046 l_supply_atr_qty => l_supply_atr_qty,
8047 l_demand_type_id => l_demand_type_id,
8048 l_wip_entity_id => l_wip_entity_id,
8049 l_operation_seq_num => l_operation_seq_num,
8050 l_repetitive_schedule_id => l_repetitive_schedule_id,
8051 l_wip_supply_type => l_wip_supply_type,
8052 l_xdocked_wdd_index => l_xdocked_wdd_index,
8053 l_detail_info_tab => l_detail_info_tab,
8054 l_wdd_index => l_dummy_wdd_index,
8055 l_split_wdd_index => l_split_wdd_index,
8056 p_wsh_release_table => l_wsh_release_table,
8057 l_supply_type_id => l_supply_type_id,
8058 x_return_status => x_return_status,
8059 x_msg_count => x_msg_count,
8060 x_msg_data => x_msg_data,
8061 x_error_code => l_error_code,
8062 l_criterion_type => G_CRT_TYPE_OPP
8063 );
8064
8065 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
8066 IF (l_debug = 1) THEN
8067 print_debug('2.4 - Error returned from Crossdock_MOL API: '
8068 || x_return_status);
8069 END IF;
8070 --RAISE fnd_api.g_exc_error;
8071 -- If an exception occurs while modifying a database record, rollback the changes
8072 -- and just go to the next WDD record or reservation to crossdock.
8073 ROLLBACK TO Reserved_WDD_sp;
8074 -- We need to also rollback changes done to local PLSQL data structures
8075 IF (l_xdocked_wdd_index IS NOT NULL) THEN
8076 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
8077 END IF;
8078 -- Process the next existing reserved WDD.
8079 GOTO next_reserved_wdd;
8080 ELSE
8081 IF (l_debug = 1) THEN
8082 print_debug('2.4 - Successfully crossdocked/split the MOL record');
8083 END IF;
8084 END IF;
8085 l_progress := '290';
8086
8087
8088 -- Exit out of loop if the MOL supply has been fully crossdocked or the
8089 -- reservation has been fully consumed.
8090 IF (l_mol_qty = 0 OR l_rsv_qty = 0) THEN
8091 EXIT;
8092 END IF;
8093
8094 <<next_reserved_wdd>>
8095 EXIT WHEN l_wdd_index = l_reserved_wdd_lines_tb.LAST;
8096 l_wdd_index := l_reserved_wdd_lines_tb.NEXT(l_wdd_index);
8097 END LOOP; -- End looping through WDD lines in l_existing_rsvs_tb
8098
8099 -- Exit out of existing reservations loop if the MOL supply has been fully crossdocked.
8100 -- There is no need to consider anymore existing reservations.
8101 IF (l_mol_qty = 0) THEN
8102 EXIT;
8103 END IF;
8104
8105 <<next_reservation>>
8106 EXIT WHEN l_rsv_index = l_existing_rsvs_tb.LAST;
8107 l_rsv_index := l_existing_rsvs_tb.NEXT(l_rsv_index);
8108 END LOOP; -- End looping through existing reservations
8109 l_progress := '300';
8110
8111 <<after_existing_rsvs>>
8112 IF (l_debug = 1) THEN
8113 print_debug('2.5 - Finished processing existing reservations');
8114 print_debug('2.5 - Quantity left on MOL: ' || l_mol_qty || ' ' || l_supply_uom_code);
8115 END IF;
8116
8117 -- 2.5 - If quantity still remains on the MOL to be crossdocked, see how much reservable
8118 -- quantity on the supply is actually available for crossdocking.
8119 -- {{
8120 -- Test for a supply MOL being fully crossdocked by existing reservations.
8121 -- Further crossdock processing should not occur. }}
8122 IF (l_mol_qty = 0) THEN
8123 GOTO end_crossdock;
8124 END IF;
8125
8126 IF (l_debug = 1) THEN
8127 print_debug('2.5 - Calculate the ATR qty on the MOL supply line for crossdocking');
8128 END IF;
8129 -- {{
8130 -- Test getting the available to reserve quantity for the MOL supply for
8131 -- type RCV as well as WIP. }}
8132 IF (l_supply_type_id = 27) THEN
8133 -- RCV MOL
8134 INV_RESERVATION_AVAIL_PVT.Available_supply_to_reserve
8135 (p_api_version_number => 1.0,
8136 p_init_msg_lst => fnd_api.g_false,
8137 x_return_status => x_return_status,
8138 x_msg_count => x_msg_count,
8139 x_msg_data => x_msg_data,
8140 p_organization_id => l_organization_id,
8141 p_item_id => l_inventory_item_id,
8142 p_supply_source_type_id => l_supply_type_id,
8143 p_supply_source_header_id => l_supply_header_id,
8144 p_supply_source_line_id => l_supply_line_id,
8145 p_supply_source_line_detail => l_supply_line_detail_id,
8146 p_project_id => l_mol_rec.project_id,
8147 p_task_id => l_mol_rec.task_id,
8148 x_qty_available_to_reserve => l_supply_atr_prim_qty,
8149 x_qty_available => l_supply_available_qty);
8150 ELSIF (l_wip_entity_type = 1) THEN
8151 -- WIP Discrete Job MOL
8152 INV_RESERVATION_AVAIL_PVT.Available_supply_to_reserve
8153 (p_api_version_number => 1.0,
8154 p_init_msg_lst => fnd_api.g_false,
8155 x_return_status => x_return_status,
8156 x_msg_count => x_msg_count,
8157 x_msg_data => x_msg_data,
8158 p_organization_id => l_organization_id,
8159 p_item_id => l_inventory_item_id,
8160 p_supply_source_type_id => l_supply_type_id,
8161 p_supply_source_header_id => l_supply_header_id,
8162 p_supply_source_line_id => l_supply_line_id,
8163 p_supply_source_line_detail => l_supply_line_detail_id,
8164 p_project_id => l_mol_rec.project_id,
8165 p_task_id => l_mol_rec.task_id,
8166 x_qty_available_to_reserve => l_supply_atr_prim_qty,
8167 x_qty_available => l_supply_available_qty);
8168 ELSE -- l_wip_entity_type = 4
8169 -- WIP Flow Job MOL
8170 -- The full quantity on the MOL is available for crossdocking since
8171 -- you cannot create reservations against WIP Flow jobs as supply in R12.
8172 l_supply_atr_prim_qty := l_mol_prim_qty;
8173 END IF;
8174
8175 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
8176 IF (l_debug = 1) THEN
8177 print_debug('2.5 - Error returned from available_supply_to_reserve API: '
8178 || x_return_status);
8179 END IF;
8180 GOTO end_crossdock;
8181 --RAISE fnd_api.g_exc_error;
8182 END IF;
8183
8184 -- The ATR qty returned is for all of receiving. Since we are working on a specific
8185 -- MOL supply line, we need to use a LEAST to get the min qty value.
8186 -- If the MOL is for WIP, the ATR qty is for all of the lines for the same WIP job.
8187 l_supply_atr_prim_qty := LEAST(l_mol_prim_qty, l_supply_atr_prim_qty);
8188
8189 IF (l_debug = 1) THEN
8190 print_debug('2.5 - Available qty to reserve (primary) for supply: ' ||
8191 l_supply_atr_prim_qty || ' ' || l_primary_uom_code);
8192 END IF;
8193 l_progress := '360';
8194
8195 -- Check how much quantity is available to be crossdocked.
8196 -- {{
8197 -- Test for case where the MOL supply, after considering existing reservations, does not
8198 -- have any reservable quantity. This line cannot be crossdocked and we should end
8199 -- crossdocking logic. }}
8200 IF (l_supply_atr_prim_qty <= 0) THEN
8201 GOTO end_crossdock;
8202 ELSE
8203 -- Convert the ATR primary quantity to the UOM on the MOL supply line
8204 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
8205 l_primary_uom_code, l_supply_uom_code);
8206 IF (l_conversion_rate < 0) THEN
8207 IF (l_debug = 1) THEN
8208 print_debug('2.5 - Error while obtaining Primary UOM conversion rate for WDD');
8209 END IF;
8210 GOTO end_crossdock;
8211 END IF;
8212 -- Round the converted quantity to the standard precision
8213 l_supply_atr_qty := ROUND(l_conversion_rate * l_supply_atr_prim_qty, l_conversion_precision);
8214 IF (l_debug = 1) THEN
8215 print_debug('2.5 - Available qty to reserve for supply: ' || l_supply_atr_qty ||
8216 ' ' || l_supply_uom_code);
8217 END IF;
8218 l_progress := '370';
8219
8220 -- Instead of splitting the MOL record here with the ATR quantity, just keep track
8221 -- of that qty and use it later on when determining the available to detail qty.
8222 -- In this way, we can minimize the amount of MOL splitting, doing it only when
8223 -- absolutely necessary.
8224 END IF;
8225
8226 -- Section 3: Build the set of available demand lines for the MOL supply
8227 -- 3.1 - For each available demand source type for the crossdock criteria,
8228 -- retrieve the available demand lines.
8229 -- 3.2 - For each demand line retrieved, determine the expected ship time.
8230 -- If the demand line does not lie within the crossdock window, remove it
8231 -- from the local PLSQL tables prior to insertion into the global temp table.
8232 -- 3.3 - Insert the available crossdockable demand lines into the global temp table.
8233 -- 3.4 - Retrieve all of the demand lines inserted into the global temp table and
8234 -- store it in the shopping basket table. If prioritize documents, order this
8235 -- by the source type.
8236 -- 3.5 - Sort the demand lines in the shopping basket table based on the crossdocking
8237 -- goals.
8238
8239 -- 3.1 - For each available demand source type for the crossdock criteria,
8240 -- retrieve the available demand lines.
8241 -- {{
8242 -- Test for different demand source types for opportunistic crossdocking. Make sure
8243 -- only the valid ones are retrieved, i.e. SO, IO (both scheduled and backordered) and
8244 -- WIP backordered component demands. }}
8245 IF (l_debug = 1) THEN
8246 print_debug('3.1 - Query and cache the available demand source types for crossdocking');
8247 END IF;
8248 BEGIN
8249 OPEN demand_src_types_cursor;
8250 FETCH demand_src_types_cursor BULK COLLECT INTO l_demand_src_types_tb;
8251 CLOSE demand_src_types_cursor;
8252 EXCEPTION
8253 WHEN OTHERS THEN
8254 IF (l_debug = 1) THEN
8255 print_debug('3.1 - Exception retrieving the eligible demand source types');
8256 END IF;
8257 GOTO end_crossdock;
8258 END;
8259 IF (l_debug = 1) THEN
8260 print_debug('3.1 - Successfully retrieved ' || l_demand_src_types_tb.COUNT ||
8261 ' eligible demand source types');
8262 END IF;
8263
8264 -- Set a savepoint in case an error occurs while inserting demand line records
8265 -- into the global temp table.
8266 SAVEPOINT Demand_Lines_sp;
8267
8268 FOR i IN 1 .. l_demand_src_types_tb.COUNT LOOP
8269 -- Store the current demand source code
8270 l_demand_src_code := l_demand_src_types_tb(i);
8271
8272 -- Retrieve the available demand lines for the current demand source type,
8273 -- item,org, project and task.
8274 IF (l_debug = 1) THEN
8275 IF (l_demand_src_code = G_OPP_DEM_SO_SCHED) THEN
8276 print_debug('3.1 - Demand source type to retrieve: Scheduled Sales Order');
8277 ELSIF (l_demand_src_code = G_OPP_DEM_SO_BKORD) THEN
8278 print_debug('3.1 - Demand source type to retrieve: Backordered Sales Order');
8279 ELSIF (l_demand_src_code = G_OPP_DEM_IO_SCHED) THEN
8280 print_debug('3.1 - Demand source type to retrieve: Scheduled Internal Order');
8281 ELSIF (l_demand_src_code = G_OPP_DEM_IO_BKORD) THEN
8282 print_debug('3.1 - Demand source type to retrieve: Backordered Internal Order');
8283 ELSIF (l_demand_src_code = G_OPP_DEM_WIP_BKORD) THEN
8284 print_debug('3.1 - Demand source type to retrieve: Backordered WIP Component');
8285 ELSE
8286 print_debug('3.1 - Demand source type to retrieve: INVALID DEMAND!');
8287 END IF;
8288 END IF;
8289
8290 -- Initialize the tables we are BULK fetching into
8291 l_header_id_tb.DELETE;
8292 l_line_id_tb.DELETE;
8293 l_line_detail_id_tb.DELETE;
8294 l_dock_start_time_tb.DELETE;
8295 l_dock_mean_time_tb.DELETE;
8296 l_dock_end_time_tb.DELETE;
8297 l_expected_time_tb.DELETE;
8298 l_quantity_tb.DELETE;
8299 l_uom_code_tb.DELETE;
8300 l_secondary_quantity_tb.DELETE;
8301 l_secondary_uom_code_tb.DELETE;
8302 l_project_id_tb.DELETE;
8303 l_task_id_tb.DELETE;
8304 l_wip_supply_type_tb.DELETE;
8305
8306 -- Bulk collect the demand line cursors into the PLSQL tables based on
8307 -- the current crossdock demand source type.
8308 -- {{
8309 -- Make sure that if cross project/task allocation is not allowed, only valid demand
8310 -- lines that match the project/task on the supply are retrieved. }}
8311 IF (l_demand_src_code = G_OPP_DEM_SO_SCHED) THEN
8312 -- Sales Order (Scheduled)
8313 BEGIN
8314 OPEN SO_scheduled_lines(l_mol_rec.project_id, l_mol_rec.task_id);
8315 FETCH SO_scheduled_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
8316 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb,
8317 l_secondary_quantity_tb, l_secondary_uom_code_tb, l_project_id_tb, l_task_id_tb,
8318 l_wip_supply_type_tb;
8319 CLOSE SO_scheduled_lines;
8320 EXCEPTION
8321 WHEN OTHERS THEN
8322 IF (l_debug = 1) THEN
8323 print_debug('3.1 - Could not retrieve the Scheduled SO demand lines');
8324 END IF;
8325 -- If we cannot retrieve the available demand lines, do not error out.
8326 -- Rollback any db changes that might have occurred (currently none).
8327 ROLLBACK TO Demand_Lines_sp;
8328 GOTO end_crossdock;
8329 END;
8330 l_demand_type_id := 2;
8331 ELSIF (l_demand_src_code = G_OPP_DEM_SO_BKORD) THEN
8332 -- Sales Order (Backordered)
8333 BEGIN
8334 OPEN SO_backordered_lines(l_mol_rec.project_id, l_mol_rec.task_id);
8335 FETCH SO_backordered_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
8336 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb,
8337 l_secondary_quantity_tb, l_secondary_uom_code_tb, l_project_id_tb, l_task_id_tb,
8338 l_wip_supply_type_tb;
8339 CLOSE SO_backordered_lines;
8340 EXCEPTION
8341 WHEN OTHERS THEN
8342 IF (l_debug = 1) THEN
8343 print_debug('3.1 - Could not retrieve the Backordered SO demand lines');
8344 END IF;
8345 -- If we cannot retrieve the available demand lines, do not error out.
8346 -- Rollback any db changes that might have occurred (currently none).
8347 ROLLBACK TO Demand_Lines_sp;
8348 GOTO end_crossdock;
8349 END;
8350 l_demand_type_id := 2;
8351 ELSIF (l_demand_src_code = G_OPP_DEM_IO_SCHED) THEN
8352 -- Internal Order (Scheduled)
8353 BEGIN
8354 OPEN IO_scheduled_lines(l_mol_rec.project_id, l_mol_rec.task_id);
8355 FETCH IO_scheduled_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
8356 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb,
8357 l_secondary_quantity_tb, l_secondary_uom_code_tb, l_project_id_tb, l_task_id_tb,
8358 l_wip_supply_type_tb;
8359 CLOSE IO_scheduled_lines;
8360 EXCEPTION
8361 WHEN OTHERS THEN
8362 IF (l_debug = 1) THEN
8363 print_debug('3.1 - Could not retrieve the Scheduled IO demand lines');
8364 END IF;
8365 -- If we cannot retrieve the available demand lines, do not error out.
8366 -- Rollback any db changes that might have occurred (currently none).
8367 ROLLBACK TO Demand_Lines_sp;
8368 GOTO end_crossdock;
8369 END;
8370 l_demand_type_id := 8;
8371 ELSIF (l_demand_src_code = G_OPP_DEM_IO_BKORD) THEN
8372 -- Internal Order (Backordered)
8373 BEGIN
8374 OPEN IO_backordered_lines(l_mol_rec.project_id, l_mol_rec.task_id);
8375 FETCH IO_backordered_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
8376 l_line_detail_id_tb, l_quantity_tb, l_uom_code_tb,
8377 l_secondary_quantity_tb, l_secondary_uom_code_tb, l_project_id_tb, l_task_id_tb,
8378 l_wip_supply_type_tb;
8379 CLOSE IO_backordered_lines;
8380 EXCEPTION
8381 WHEN OTHERS THEN
8382 IF (l_debug = 1) THEN
8383 print_debug('3.1 - Could not retrieve the Backordered IO demand lines');
8384 END IF;
8385 -- If we cannot retrieve the available demand lines, do not error out.
8386 -- Rollback any db changes that might have occurred (currently none).
8387 ROLLBACK TO Demand_Lines_sp;
8388 GOTO end_crossdock;
8389 END;
8390 l_demand_type_id := 8;
8391 ELSIF (l_demand_src_code = G_OPP_DEM_WIP_BKORD) THEN
8392 -- WIP backordered component
8393 BEGIN
8394 OPEN wip_component_demand_lines(l_mol_rec.project_id, l_mol_rec.task_id,
8395 l_xdock_start_time, l_xdock_end_time);
8396 FETCH wip_component_demand_lines BULK COLLECT INTO l_header_id_tb, l_line_id_tb,
8397 l_line_detail_id_tb, l_expected_time_tb, l_quantity_tb, l_uom_code_tb,
8398 l_secondary_quantity_tb, l_secondary_uom_code_tb, l_project_id_tb, l_task_id_tb,
8399 l_wip_supply_type_tb;
8400 CLOSE wip_component_demand_lines;
8401 EXCEPTION
8402 WHEN OTHERS THEN
8403 IF (l_debug = 1) THEN
8404 print_debug('3.1 - Could not retrieve the WIP component demand lines');
8405 END IF;
8406 -- If we cannot retrieve the available demand lines, do not error out.
8407 -- Rollback any db changes that might have occurred (currently none).
8408 ROLLBACK TO Demand_Lines_sp;
8409 GOTO end_crossdock;
8410 END;
8411 l_demand_type_id := 5;
8412 ELSE
8413 -- Invalid demand type for crossdocking
8414 -- Rollback any db changes that might have occurred (currently none).
8415 ROLLBACK TO Demand_Lines_sp;
8416 GOTO end_crossdock;
8417 END IF; -- End retrieving demand lines for different demand source types
8418 IF (l_debug = 1) THEN
8419 IF (l_demand_src_code = G_OPP_DEM_SO_SCHED) THEN
8420 print_debug('3.1 - Successfully retrieved ' || l_header_id_tb.COUNT ||
8421 ' available line(s) for Scheduled Sales Order');
8422 ELSIF (l_demand_src_code = G_OPP_DEM_SO_BKORD) THEN
8423 print_debug('3.1 - Successfully retrieved ' || l_header_id_tb.COUNT ||
8424 ' available line(s) for Backordered Sales Order');
8425 ELSIF (l_demand_src_code = G_OPP_DEM_IO_SCHED) THEN
8426 print_debug('3.1 - Successfully retrieved ' || l_header_id_tb.COUNT ||
8427 ' available line(s) for Scheduled Internal Order');
8428 ELSIF (l_demand_src_code = G_OPP_DEM_IO_BKORD) THEN
8429 print_debug('3.1 - Successfully retrieved ' || l_header_id_tb.COUNT ||
8430 ' available line(s) for Backordered Internal Order');
8431 ELSIF (l_demand_src_code = G_OPP_DEM_WIP_BKORD) THEN
8432 print_debug('3.1 - Successfully retrieved ' || l_header_id_tb.COUNT ||
8433 ' available line(s) for Backordered WIP Component');
8434 END IF;
8435 END IF;
8436 l_progress := '380';
8437
8438 -- 3.2 - For each demand line retrieved, determine the expected ship time.
8439 -- If the demand line does not lie within the crossdock window, remove it
8440 -- from the local PLSQL tables prior to insertion into the global temp table.
8441 -- {{
8442 -- Make sure that demand lines with an expected time that lies outside of the crossdock
8443 -- window are removed from the PLSQL tables and not inserted into the global temp table. }}
8444 IF (l_debug = 1) THEN
8445 print_debug('3.2 - For each demand line retrieved, calculate the expected ship time');
8446 END IF;
8447 FOR j IN 1 .. l_header_id_tb.COUNT LOOP
8448 -- Call the Get_Expected_Time API for OE demand. WIP demand will already
8449 -- have the date_required value retrieved.
8450 IF (l_demand_type_id <> 5) THEN
8451 Get_Expected_Time
8452 (p_source_type_id => l_demand_type_id,
8453 p_source_header_id => l_header_id_tb(j),
8454 p_source_line_id => l_line_id_tb(j),
8455 p_source_line_detail_id => l_line_detail_id_tb(j),
8456 p_supply_or_demand => G_SRC_TYPE_DEM,
8457 p_crossdock_criterion_id => l_crossdock_criteria_id,
8458 x_return_status => x_return_status,
8459 x_msg_count => x_msg_count,
8460 x_msg_data => x_msg_data,
8461 x_dock_start_time => l_dock_start_time_tb(j),
8462 x_dock_mean_time => l_dock_mean_time_tb(j),
8463 x_dock_end_time => l_dock_end_time_tb(j),
8464 x_expected_time => l_expected_time_tb(j));
8465
8466 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
8467 IF (l_debug = 1) THEN
8468 print_debug('3.2 - Success returned from Get_Expected_Time API');
8469 END IF;
8470 ELSE
8471 IF (l_debug = 1) THEN
8472 print_debug('3.2 - Failure returned from Get_Expected_Time API');
8473 END IF;
8474 -- Rollback any db changes that might have occurred (currently none).
8475 ROLLBACK TO Demand_Lines_sp;
8476 GOTO end_crossdock;
8477 END IF;
8478 ELSE
8479 -- WIP demand line. Use the value retrieved in the l_expected_time_tb
8480 -- and populate the same value for the dock appointment tables.
8481 l_dock_start_time_tb(j) := l_expected_time_tb(j);
8482 l_dock_mean_time_tb(j) := l_expected_time_tb(j);
8483 l_dock_end_time_tb(j) := l_expected_time_tb(j);
8484 END IF;
8485
8486 -- Check if the current demand line lies within the crossdock window.
8487 -- Remove any demand lines that are not crossdockable from the PLSQL tables.
8488 -- Do this only for non-WIP demand types. WIP demand lines retrieved will already
8489 -- be checked to lie within the crossdock window. This logic is done within the
8490 -- wip_component_demand_lines cursor.
8491 -- Demand lines with an expected ship time in the past are always eligible for
8492 -- opportunistic crossdocking.
8493 IF (l_demand_type_id <> 5) THEN
8494 IF (l_expected_time_tb(j) IS NOT NULL AND
8495 ((l_dock_start_time_tb(j) IS NULL AND
8496 g_crossdock_criteria_tb(l_crossdock_criteria_id).allow_demand_reschedule_flag = 1 AND
8497 l_expected_time_tb(j) BETWEEN TRUNC(l_xdock_start_time) AND
8498 TO_DATE(TO_CHAR(TRUNC(l_xdock_end_time), 'DD-MON-YYYY') ||
8499 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS'))
8500 OR (l_expected_time_tb(j) < SYSDATE)
8501 OR (l_expected_time_tb(j) BETWEEN l_xdock_start_time AND l_xdock_end_time))) THEN
8502 -- Demand is within the crossdock window
8503 IF (l_debug = 1) THEN
8504 print_debug('3.2 - Current demand line is valid for crossdocking');
8505 END IF;
8506 ELSE
8507 -- Demand is not valid for crossdocking based on crossdock time window
8508 -- so remove this line from the local tables prior to insertion.
8509 IF (l_debug = 1) THEN
8510 print_debug('3.2 - Current demand line is invalid for crossdocking so remove it');
8511 END IF;
8512 l_header_id_tb.DELETE(j);
8513 l_line_id_tb.DELETE(j);
8514 l_line_detail_id_tb.DELETE(j);
8515 l_quantity_tb.DELETE(j);
8516 l_uom_code_tb.DELETE(j);
8517 l_secondary_quantity_tb.DELETE(j);
8518 l_secondary_uom_code_tb.DELETE(j);
8519 l_project_id_tb.DELETE(j);
8520 l_task_id_tb.DELETE(j);
8521 l_dock_start_time_tb.DELETE(j);
8522 l_dock_mean_time_tb.DELETE(j);
8523 l_dock_end_time_tb.DELETE(j);
8524 l_expected_time_tb.DELETE(j);
8525 l_wip_supply_type_tb.DELETE(j);
8526 END IF;
8527 END IF;
8528
8529 -- If we do not allow partial WIP crossdock, check if the demand is already tied
8530 -- to a WIP supply. If yes, then only WIP supply lines are valid for crossdocking.
8531 -- Similarly, if the supply is a WIP supply, check that the demand is not already tied
8532 -- to non-WIP and non-Inventory supplies.
8533 -- Do this check only for non-WIP demand lines since those are the ones that will have
8534 -- reservations created for the crossdock. Only do this check if the demand line has not
8535 -- already been removed above for not lying within the crossdock window.
8536 IF (l_header_id_tb.EXISTS(j) AND l_demand_type_id <> 5) THEN
8537 IF (WMS_XDOCK_CUSTOM_APIS_PUB.g_allow_partial_wip_xdock = 'N') THEN
8538 IF ((l_supply_type_id <> 5 AND WMS_XDOCK_PEGGING_PUB.is_demand_tied_to_wip
8539 (p_organization_id => l_organization_id,
8540 p_inventory_item_id => l_inventory_item_id,
8541 p_demand_type_id => l_demand_type_id,
8542 p_demand_header_id => l_header_id_tb(j),
8543 p_demand_line_id => l_line_id_tb(j)) = 'Y') OR
8544 (l_supply_type_id = 5 AND WMS_XDOCK_PEGGING_PUB.is_demand_tied_to_non_wip
8545 (p_organization_id => l_organization_id,
8546 p_inventory_item_id => l_inventory_item_id,
8547 p_demand_type_id => l_demand_type_id,
8548 p_demand_header_id => l_header_id_tb(j),
8549 p_demand_line_id => l_line_id_tb(j)) = 'Y')) THEN
8550 IF (l_debug = 1) THEN
8551 print_debug('3.2 - Demand cannot be crossdocked, partial WIP xdock is not allowed');
8552 END IF;
8553 l_header_id_tb.DELETE(j);
8554 l_line_id_tb.DELETE(j);
8555 l_line_detail_id_tb.DELETE(j);
8556 l_quantity_tb.DELETE(j);
8557 l_uom_code_tb.DELETE(j);
8558 l_secondary_quantity_tb.DELETE(j);
8559 l_secondary_uom_code_tb.DELETE(j);
8560 l_project_id_tb.DELETE(j);
8561 l_task_id_tb.DELETE(j);
8562 l_dock_start_time_tb.DELETE(j);
8563 l_dock_mean_time_tb.DELETE(j);
8564 l_dock_end_time_tb.DELETE(j);
8565 l_expected_time_tb.DELETE(j);
8566 l_wip_supply_type_tb.DELETE(j);
8567 END IF;
8568 END IF;
8569 END IF;
8570
8571 -- If the supply MOL is WIP, then there could be a specific OE demand that we
8572 -- can ONLY crossdock to. If that is the case, do not insert any other demand lines
8573 -- into the xdock pegging temp table. Only do this check if the demand line has not
8574 -- already been removed above for not lying within the crossdock window or being part
8575 -- of a partial WIP xdock.
8576 IF (l_header_id_tb.EXISTS(j) AND
8577 l_wip_entity_type IS NOT NULL AND l_wip_demand_header_id IS NOT NULL) THEN
8578 IF (l_demand_type_id <> l_wip_demand_type_id OR
8579 l_header_id_tb(j) <> l_wip_demand_header_id OR
8580 l_line_id_tb(j) <> l_wip_demand_line_id) THEN
8581 -- Demand is not valid for crossdocking due to WIP specified OE demand restriction.
8582 -- So remove this line from the local tables prior to insertion.
8583 IF (l_debug = 1) THEN
8584 print_debug('3.2 - Current demand line does not match WIP OE demand so remove it');
8585 END IF;
8586 l_header_id_tb.DELETE(j);
8587 l_line_id_tb.DELETE(j);
8588 l_line_detail_id_tb.DELETE(j);
8589 l_quantity_tb.DELETE(j);
8590 l_uom_code_tb.DELETE(j);
8591 l_secondary_quantity_tb.DELETE(j);
8592 l_secondary_uom_code_tb.DELETE(j);
8593 l_project_id_tb.DELETE(j);
8594 l_task_id_tb.DELETE(j);
8595 l_dock_start_time_tb.DELETE(j);
8596 l_dock_mean_time_tb.DELETE(j);
8597 l_dock_end_time_tb.DELETE(j);
8598 l_expected_time_tb.DELETE(j);
8599 l_wip_supply_type_tb.DELETE(j);
8600 END IF;
8601 END IF;
8602
8603 END LOOP; -- End looping through demand lines retrieved
8604 IF (l_debug = 1) THEN
8605 print_debug('3.2 - Finished calculating expected time for all demand lines');
8606 END IF;
8607 l_progress := '390';
8608
8609 -- 3.3 - Insert the available crossdockable demand lines into the global temp table.
8610 -- {{
8611 -- Make sure the valid crossdockable demand lines are properly inserted into the
8612 -- global temp table. }}
8613 IF (l_debug = 1) THEN
8614 print_debug('3.3 - Insert ' || l_header_id_tb.COUNT ||
8615 ' crossdockable demand lines into the global temp table');
8616 END IF;
8617 BEGIN
8618 FORALL k IN INDICES OF l_header_id_tb
8619 INSERT INTO wms_xdock_pegging_gtmp
8620 (inventory_item_id,
8621 xdock_source_code,
8622 source_type_id,
8623 source_header_id,
8624 source_line_id,
8625 source_line_detail_id,
8626 dock_start_time,
8627 dock_mean_time,
8628 dock_end_time,
8629 expected_time,
8630 quantity,
8631 uom_code,
8632 secondary_quantity,
8633 secondary_uom_code,
8634 project_id,
8635 task_id,
8636 wip_supply_type
8637 )
8638 VALUES
8639 (l_inventory_item_id,
8640 l_demand_src_code,
8641 l_demand_type_id,
8642 l_header_id_tb(k),
8643 l_line_id_tb(k),
8644 l_line_detail_id_tb(k),
8645 l_dock_start_time_tb(k),
8646 l_dock_mean_time_tb(k),
8647 l_dock_end_time_tb(k),
8648 l_expected_time_tb(k),
8649 l_quantity_tb(k),
8650 l_uom_code_tb(k),
8651 l_secondary_quantity_tb(k),
8652 l_secondary_uom_code_tb(k),
8653 l_project_id_tb(k),
8654 l_task_id_tb(k),
8655 l_wip_supply_type_tb(k)
8656 );
8657 EXCEPTION
8658 WHEN OTHERS THEN
8659 IF (l_debug = 1) THEN
8660 print_debug('3.3 - Error inserting available demand lines into temp table');
8661 END IF;
8662 -- If an exception occurs while inserting demand line records,
8663 -- rollback the changes and stop crossdock processing.
8664 ROLLBACK TO Demand_Lines_sp;
8665 GOTO end_crossdock;
8666 END;
8667 IF (l_debug = 1) THEN
8668 print_debug('3.3 - Successfully inserted ' || l_header_id_tb.COUNT ||
8669 ' crossdockable demand lines into temp table');
8670 END IF;
8671 l_progress := '400';
8672
8673 -- Clear the PLSQL tables used once the data is inserted into the global temp table
8674 IF (l_header_id_tb.COUNT > 0) THEN
8675 l_header_id_tb.DELETE;
8676 l_line_id_tb.DELETE;
8677 l_line_detail_id_tb.DELETE;
8678 l_dock_start_time_tb.DELETE;
8679 l_dock_mean_time_tb.DELETE;
8680 l_dock_end_time_tb.DELETE;
8681 l_expected_time_tb.DELETE;
8682 l_quantity_tb.DELETE;
8683 l_uom_code_tb.DELETE;
8684 l_secondary_quantity_tb.DELETE;
8685 l_secondary_uom_code_tb.DELETE;
8686 l_project_id_tb.DELETE;
8687 l_task_id_tb.DELETE;
8688 l_wip_supply_type_tb.DELETE;
8689 END IF;
8690 l_progress := '410';
8691
8692 END LOOP; -- End looping through eligible demand source types
8693
8694 -- 3.4 - Retrieve all of the demand lines inserted into the global temp table and
8695 -- store it in the shopping basket table. If prioritize documents, order this
8696 -- by the source type.
8697 -- {{
8698 -- Make sure the demand lines retrieved are sorted in order of document priority if
8699 -- necessary. }}
8700 IF (l_debug = 1) THEN
8701 print_debug('3.4 - Retrieve all of the demand lines that are valid for crossdocking');
8702 END IF;
8703
8704 -- Iniitialize the shopping basket table which will store the valid supply lines
8705 -- for crossdocking to the current demand line.
8706 l_shopping_basket_tb.DELETE;
8707
8708 -- Initialize the demand document priority variables
8709 l_so_sched_priority := 99;
8710 l_so_back_priority := 99;
8711 l_io_sched_priority := 99;
8712 l_io_back_priority := 99;
8713 l_wip_priority := 99;
8714
8715 -- Get the valid demand source types to retrieve.
8716 -- The demand source types are cached in the order of the document priority already.
8717 -- Just use the same index value for the document priority variable.
8718 -- Do this only if we need to prioritize documents for the crossdock criteria
8719 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).prioritize_documents_flag = 1) THEN
8720 FOR i IN 1 .. l_demand_src_types_tb.COUNT LOOP
8721 IF (l_demand_src_types_tb(i) = G_OPP_DEM_SO_SCHED) THEN
8722 l_so_sched_priority := i;
8723 ELSIF (l_demand_src_types_tb(i) = G_OPP_DEM_SO_BKORD) THEN
8724 l_so_back_priority := i;
8725 ELSIF (l_demand_src_types_tb(i) = G_OPP_DEM_IO_SCHED) THEN
8726 l_io_sched_priority := i;
8727 ELSIF (l_demand_src_types_tb(i) = G_OPP_DEM_IO_BKORD) THEN
8728 l_io_back_priority := i;
8729 ELSIF (l_demand_src_types_tb(i) = G_OPP_DEM_WIP_BKORD) THEN
8730 l_wip_priority := i;
8731 END IF;
8732 END LOOP;
8733 END IF;
8734
8735 -- Now get the valid demand lines for crossdocking and store it in the
8736 -- shopping basket table. All of the demand lines stored in the global temp table
8737 -- should already match the project/task of the supply (if necessary). They should
8738 -- also lie within the crossdock window. We are just sorting them basically here.
8739 -- {{
8740 -- Make sure the demand lines are retrieved properly into the shopping basket table.
8741 -- Do this both with and without enforcing document priority. Also use various
8742 -- available demand types. }}
8743 BEGIN
8744 OPEN get_demand_lines
8745 (p_crossdock_goal => g_crossdock_criteria_tb(l_crossdock_criteria_id).crossdock_goal,
8746 p_so_sched_priority => l_so_sched_priority,
8747 p_so_back_priority => l_so_back_priority,
8748 p_io_sched_priority => l_io_sched_priority,
8749 p_io_back_priority => l_io_back_priority,
8750 p_wip_priority => l_wip_priority);
8751 FETCH get_demand_lines BULK COLLECT INTO l_shopping_basket_tb;
8752 CLOSE get_demand_lines;
8753 EXCEPTION
8754 WHEN OTHERS THEN
8755 IF (l_debug = 1) THEN
8756 print_debug('3.4 - Could not retrieve the valid demand lines for available demand types');
8757 END IF;
8758 -- If we cannot retrieve the valid demand lines, do not error out.
8759 -- Stop crossdock processing and exit out of the API.
8760 GOTO end_crossdock;
8761 END;
8762 IF (l_debug = 1) THEN
8763 print_debug('3.4 - Successfully populated the shopping basket table with ' ||
8764 l_shopping_basket_tb.COUNT || ' crossdockable demand lines');
8765 END IF;
8766 l_progress := '420';
8767
8768 -- 3.5 - Sort the demand lines in the shopping basket table based on the crossdocking
8769 -- goals.
8770 -- For crossdock goals of Minimize Wait and Maximize Crossdock, the demand lines in the
8771 -- shopping basket have already been sorted.
8772 -- {{
8773 -- Test out the custom crossdock goal method of sorting the shopping basket lines.
8774 -- The not implemented stub version should just pass back the inputted shopping basket
8775 -- table without sorting them. }}
8776 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).crossdock_goal = G_CUSTOM_GOAL) THEN
8777 -- For each record in the shopping basket table, call the available to reserve API
8778 -- to determine how much quantity from each demand line is available for crossdocking.
8779 -- We need to do this since the custom logic might decide which demand lines to consume
8780 -- based on the reservable quantity (e.g. Best Fit SPQ type of logic).
8781 IF (l_debug = 1) THEN
8782 print_debug('3.5 - Use custom logic to sort the demand lines');
8783 END IF;
8784
8785 FOR i IN 1 .. l_shopping_basket_tb.COUNT LOOP
8786
8787 -- Call the Available_demand_to_reserve API for OE demand.
8788 -- The quantity_backordered on the WIP demand is the same as
8789 -- the ATR qty so it is fully reserveable.
8790 IF (l_shopping_basket_tb(i).source_type_id <> 5) THEN
8791 IF (l_debug = 1) THEN
8792 print_debug('3.5 - Call the Available_demand_to_reserve API');
8793 END IF;
8794 INV_RESERVATION_AVAIL_PVT.Available_demand_to_reserve
8795 (p_api_version_number => 1.0,
8796 p_init_msg_lst => fnd_api.g_false,
8797 x_return_status => x_return_status,
8798 x_msg_count => x_msg_count,
8799 x_msg_data => x_msg_data,
8800 p_primary_uom_code => l_primary_uom_code,
8801 p_demand_source_type_id => l_shopping_basket_tb(i).source_type_id,
8802 p_demand_source_header_id => l_shopping_basket_tb(i).source_header_id,
8803 p_demand_source_line_id => l_shopping_basket_tb(i).source_line_id,
8804 p_demand_source_line_detail => l_shopping_basket_tb(i).source_line_detail_id,
8805 p_project_id => l_shopping_basket_tb(i).project_id,
8806 p_task_id => l_shopping_basket_tb(i).task_id,
8807 x_qty_available_to_reserve => l_demand_atr_prim_qty,
8808 x_qty_available => l_demand_available_qty);
8809
8810 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
8811 IF (l_debug = 1) THEN
8812 print_debug('3.5 - Error returned from available_demand_to_reserve API: '
8813 || x_return_status);
8814 END IF;
8815 -- Instead of erroring out and stopping crossdock processing,
8816 -- just delete the demand line from the shopping basket table. Shopping basket
8817 -- table can therefore be a sparsely populated table after running custom logic.
8818 l_shopping_basket_tb.DELETE(i);
8819 GOTO next_custom_demand;
8820 END IF;
8821 ELSE
8822 -- WIP backordered component demand lines always store quantity in the primary UOM
8823 l_demand_atr_prim_qty := l_shopping_basket_tb(i).quantity;
8824 END IF;
8825
8826 -- Convert the ATR primary quantity to the UOM on the demand line
8827 l_demand_uom_code := l_shopping_basket_tb(i).uom_code;
8828 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
8829 l_primary_uom_code, l_demand_uom_code);
8830 IF (l_conversion_rate < 0) THEN
8831 IF (l_debug = 1) THEN
8832 print_debug('3.5 - Error while obtaining Primary UOM conversion rate for demand line');
8833 END IF;
8834 -- Instead of erroring out and stopping crossdock processing,
8835 -- just delete the demand line from the shopping basket table. Shopping basket
8836 -- table can therefore be a sparsely populated table after running custom logic.
8837 l_shopping_basket_tb.DELETE(i);
8838 GOTO next_custom_demand;
8839 END IF;
8840 -- Round the converted quantity to the standard precision
8841 l_demand_atr_qty := ROUND(l_conversion_rate * l_demand_atr_prim_qty, l_conversion_precision);
8842 IF (l_debug = 1) THEN
8843 print_debug('3.5 - Demand line ATR qty: ' || l_demand_atr_qty || ' ' ||
8844 l_demand_uom_code);
8845 END IF;
8846
8847 -- Set the reservable_quantity field to be equal to the ATR quanitty for the
8848 -- current demand line record in the shopping basket.
8849 l_shopping_basket_tb(i).reservable_quantity := l_demand_atr_qty;
8850
8851 <<next_custom_demand>>
8852 NULL; -- Need an executable statment for the branching label above
8853 END LOOP; -- End retrieving ATR quantity for all demand lines in shopping basket table
8854 -- At this stage, the shopping basket table will have the ATR quantity stamped on all of
8855 -- the records. The table can be sparse so the custom logic to sort the shopping basket
8856 -- must keep this in mind. This will be documented in the custom logic API.
8857 l_progress := '430';
8858
8859 -- Call the Custom logic to sort the shopping basket table.
8860 -- If the API is not implemented, the lines will not be sorted at all.
8861 -- {{
8862 -- Test that invalid custom logic to sort demand lines is caught. No sorting
8863 -- should be done if this is the case. }}
8864 IF (l_debug = 1) THEN
8865 print_debug('3.5 - Call the Sort_Demand_Lines API');
8866 END IF;
8867 WMS_XDOCK_CUSTOM_APIS_PUB.Sort_Demand_Lines
8868 (p_move_order_line_id => p_move_order_line_id,
8869 p_prioritize_documents => g_crossdock_criteria_tb(l_crossdock_criteria_id).prioritize_documents_flag,
8870 p_shopping_basket_tb => l_shopping_basket_tb,
8871 x_return_status => x_return_status,
8872 x_msg_count => x_msg_count,
8873 x_msg_data => x_msg_data,
8874 x_api_is_implemented => l_api_is_implemented,
8875 x_sorted_order_tb => l_sorted_order_tb);
8876
8877 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
8878 IF (l_debug = 1) THEN
8879 print_debug('3.5 - Success returned from Sort_Demand_Lines API');
8880 END IF;
8881 ELSE
8882 IF (l_debug = 1) THEN
8883 print_debug('3.5 - Failure returned from Sort_Demand_Lines API');
8884 END IF;
8885 -- In case of exception, do not error out. Just use whatever order the
8886 -- demand lines are in when the shopping basket table was created.
8887 l_sorted_order_tb.DELETE;
8888 END IF;
8889 l_progress := '440';
8890
8891 IF (NOT l_api_is_implemented) THEN
8892 IF (l_debug = 1) THEN
8893 print_debug('3.5 - Custom API is NOT implemented even though Custom Goal is selected!');
8894 END IF;
8895 ELSE
8896 IF (l_debug = 1) THEN
8897 print_debug('3.5 - Custom API is implemented so custom sorting logic is used');
8898 END IF;
8899 END IF;
8900
8901 -- Validate that the output l_sorted_order_tb is not larger in size than
8902 -- the shopping basket table and that values exist in l_sorted_order_tb.
8903 IF (l_debug = 1) THEN
8904 print_debug('3.5 - Rebuild the shopping basket table based on the sorting order returned');
8905 END IF;
8906 IF (l_sorted_order_tb.COUNT > l_shopping_basket_tb.COUNT OR
8907 l_sorted_order_tb.COUNT = 0) THEN
8908 -- Invalid condition from the custom logic API.
8909 -- Do not sort the shopping basket table and just use the current order
8910 -- the lines are in.
8911 IF (l_debug = 1) THEN
8912 print_debug('3.5 - Invalid output from Sort_Demand_Lines API');
8913 print_debug('3.5 - Do not sort the demand lines in the shopping basket');
8914 END IF;
8915 ELSE
8916 -- Sort and rebuild the shopping basket table
8917 l_index := l_sorted_order_tb.FIRST;
8918 -- Initialize the indices used table and the temp shopping basket table
8919 l_indices_used_tb.DELETE;
8920 l_shopping_basket_temp_tb.DELETE;
8921 LOOP
8922 -- Make sure the current entry has not already been used.
8923 -- Also make sure the index refered to in l_sorted_order_tb is a valid one
8924 -- in the shopping basket table.
8925 IF (l_indices_used_tb.EXISTS(l_sorted_order_tb(l_index)) OR
8926 NOT l_shopping_basket_tb.EXISTS(l_sorted_order_tb(l_index))) THEN
8927 IF (l_debug = 1) THEN
8928 print_debug('3.5 - Sorted order table is invalid so do not sort the demand lines');
8929 END IF;
8930 -- Clear the temp shopping basket table
8931 l_shopping_basket_temp_tb.DELETE;
8932 -- Exit out of the loop. No sorting will be done.
8933 GOTO invalid_sorting;
8934 END IF;
8935
8936 -- Mark the current pointer index to the shopping basket table as used
8937 l_indices_used_tb(l_sorted_order_tb(l_index)) := TRUE;
8938
8939 -- Add this entry to the temp shopping basket table.
8940 l_shopping_basket_temp_tb(l_shopping_basket_temp_tb.COUNT + 1) :=
8941 l_shopping_basket_tb(l_sorted_order_tb(l_index));
8942
8943 EXIT WHEN l_index = l_sorted_order_tb.LAST;
8944 l_index := l_sorted_order_tb.NEXT(l_index);
8945 END LOOP;
8946
8947 -- Set the shopping basket table to point to the new sorted one
8948 l_shopping_basket_tb := l_shopping_basket_temp_tb;
8949 l_shopping_basket_temp_tb.DELETE;
8950 IF (l_debug = 1) THEN
8951 print_debug('3.5 - Finished sorting and rebuilding the shopping basket table');
8952 END IF;
8953
8954 -- In case of an invalid sorted order table, jump to this label below and
8955 -- do not sort the shopping basket at all.
8956 <<invalid_sorting>>
8957 NULL; -- Need an executable statement for the above label to work
8958 END IF;
8959 l_progress := '450';
8960
8961 END IF; -- End of crossdocking goal = CUSTOM
8962
8963 -- Section 4: Consume the valid demand lines for crossdocking to the MOL supply
8964 -- 4.1 - Lock the demand line record.
8965 -- 4.2 - Call the available to reserve API to see how much quantity from the demand
8966 -- is valid for crossdocking.
8967 -- 4.3 - Crossdock the demand and supply line records.
8968 -- 4.4 - Create a crossdocked reservation tying the demand to the supply line.
8969
8970 -- Check if there are valid demand lines found for crossdocking.
8971 IF (l_shopping_basket_tb.COUNT = 0) THEN
8972 IF (l_debug = 1) THEN
8973 print_debug('4.1 - No valid demand lines for crossdocking were found');
8974 END IF;
8975 GOTO end_crossdock;
8976 END IF;
8977
8978 -- Initialize the shopping basket demand lines index. This should not be a NULL value.
8979 l_demand_index := NVL(l_shopping_basket_tb.FIRST, 1);
8980
8981 -- Loop through the valid demand lines to crossdock the MOL supply
8982 LOOP
8983 -- Define a savepoint so if an exception occurs while updating database records such as
8984 -- WDD, RSV, or MOL, we need to rollback the changes and stop crossdock processing.
8985 -- Put this inside the demand lines loop so if one demand line is crossdocked successfully
8986 -- but another one errors out, we can still crossdock the first one.
8987 SAVEPOINT Crossdock_Demand_sp;
8988
8989 -- Initialize the variable below used for updating crossdocked WDD records,
8990 -- in case we need to rollback the changes to local PLSQL data structures.
8991 l_xdocked_wdd_index := NULL;
8992
8993 -- Retrieve needed values from the current demand line
8994 l_demand_type_id := l_shopping_basket_tb(l_demand_index).source_type_id;
8995 -- Since the demand type could be WIP or OE, use the same variable to store the
8996 -- header ID. For OE demand lines, this will always refer to the MTL sales order
8997 -- header and not the OE header ID. Currently there is no need to retrieve the
8998 -- OE header ID.
8999 l_demand_header_id := l_shopping_basket_tb(l_demand_index).source_header_id;
9000 l_demand_line_id := l_shopping_basket_tb(l_demand_index).source_line_id;
9001 l_demand_line_detail_id := l_shopping_basket_tb(l_demand_index).source_line_detail_id;
9002 l_demand_qty := l_shopping_basket_tb(l_demand_index).quantity;
9003 l_demand_uom_code := l_shopping_basket_tb(l_demand_index).uom_code;
9004 l_demand_qty2 := l_shopping_basket_tb(l_demand_index).secondary_quantity;
9005 l_demand_uom_code2 := l_shopping_basket_tb(l_demand_index).secondary_uom_code;
9006 l_demand_project_id := l_shopping_basket_tb(l_demand_index).project_id;
9007 l_demand_task_id := l_shopping_basket_tb(l_demand_index).task_id;
9008 l_demand_expected_time := l_shopping_basket_tb(l_demand_index).expected_time;
9009 -- Set the WIP related fields if the demand line is a WIP backordered component demand
9010 IF (l_demand_type_id = 5) THEN
9011 l_wip_entity_id := l_demand_header_id;
9012 l_operation_seq_num := l_demand_line_id;
9013 l_repetitive_schedule_id := l_demand_line_detail_id;
9014 l_wip_supply_type := l_shopping_basket_tb(l_demand_index).wip_supply_type;
9015 ELSE
9016 l_wip_entity_id := NULL;
9017 l_operation_seq_num := NULL;
9018 l_repetitive_schedule_id := NULL;
9019 l_wip_supply_type := NULL;
9020 END IF;
9021
9022 IF (l_debug = 1) THEN
9023 print_debug('4.1 - Current demand line to consider for crossdocking');
9024 print_debug('4.1 - Demand Source Type ID: => ' || l_demand_type_id);
9025 print_debug('4.1 - Demand Header ID: ======> ' || l_demand_header_id);
9026 print_debug('4.1 - Demand Line ID: ========> ' || l_demand_line_id);
9027 print_debug('4.1 - Demand Line Detail ID: => ' || l_demand_line_detail_id);
9028 print_debug('4.1 - Demand Qty: ============> ' || l_demand_qty || ' ' || l_demand_uom_code);
9029 print_debug('4.1 - Secondary Demand Qty: ==> ' || l_demand_qty2 || ' ' || l_demand_uom_code2);
9030 print_debug('4.1 - Demand Project ID: =====> ' || l_demand_project_id);
9031 print_debug('4.1 - Demand Task ID: ========> ' || l_demand_task_id);
9032 print_debug('4.1 - Demand Expected Time: ==> ' ||
9033 TO_CHAR(l_demand_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
9034 print_debug('4.1 - WIP Supply Type: =======> ' || l_wip_supply_type);
9035 END IF;
9036
9037 -- For WIP Discrete Job MOLs, we only want to crossdock to the same
9038 -- OE demand at the Sales Order Line level (Not the WDD level).
9039 -- If the WIP Discrete job was completed for a specific Sales Order demand,
9040 -- then only the WDD records associated with that demand will be populated
9041 -- in the xdock temp table and the shopping basket table. The condition below
9042 -- will thus always be met.
9043
9044 -- If the Discrete job was NOT completed for a particular Sales Order,
9045 -- we will set the l_wip_demand variables to point the OE demand that the WIP
9046 -- MOL was first crossdocked to. Thus afterwards, we will only crossdock to
9047 -- OE WDD demand lines that match the previously crossdocked OE demand.
9048 -- WIP demand will not need to do this check since we do not create reservations
9049 -- for those types of crossdock.
9050 IF (l_wip_entity_type = 1 AND l_wip_demand_header_id IS NOT NULL
9051 AND l_demand_type_id <> 5) THEN
9052 -- Make sure the current OE demand matches the one we are allowed to crossdock to.
9053 IF (l_demand_type_id <> l_wip_demand_type_id OR
9054 l_demand_header_id <> l_wip_demand_header_id OR
9055 l_demand_line_id <> l_wip_demand_line_id) THEN
9056 IF (l_debug = 1) THEN
9057 print_debug('4.1 - Invalid OE demand to crossdock to for WIP Discrete supply');
9058 END IF;
9059 GOTO next_demand;
9060 END IF;
9061 END IF;
9062
9063 -- 4.1 - Lock the demand line record.
9064 -- {{
9065 -- If a demand line cannot be locked, make sure we skip it and do not error out.
9066 -- Just move on to the next available demand. }}
9067 IF (l_demand_type_id IN (2, 8)) THEN
9068 -- OE WDD demand line
9069 BEGIN
9070 OPEN lock_wdd_record(l_demand_line_detail_id);
9071 CLOSE lock_wdd_record;
9072 EXCEPTION
9073 WHEN OTHERS THEN
9074 IF (l_debug = 1) THEN
9075 print_debug('4.1 - Could not lock the WDD demand line record');
9076 END IF;
9077 -- If we cannot lock the supply line, do not error out. Just go to the
9078 -- next available demand and try to crossdock that.
9079 -- Rollback any db changes that might have occurred (currently none).
9080 ROLLBACK TO Crossdock_Demand_sp;
9081 GOTO next_demand;
9082 END;
9083 ELSIF (l_demand_type_id = 5) THEN
9084 -- WIP Backordered Component Demand
9085 BEGIN
9086 OPEN lock_wip_record(l_demand_header_id, l_demand_line_id, l_demand_line_detail_id);
9087 CLOSE lock_wip_record;
9088 EXCEPTION
9089 WHEN OTHERS THEN
9090 IF (l_debug = 1) THEN
9091 print_debug('4.1 - Could not lock the WIP demand line record');
9092 END IF;
9093 -- If we cannot lock the demand line, do not error out. Just go to the
9094 -- next available demand and try to crossdock that.
9095 -- Rollback any db changes that might have occurred (currently none).
9096 ROLLBACK TO Crossdock_Demand_sp;
9097 GOTO next_demand;
9098 END;
9099 ELSE
9100 -- Invalid demand for crossdocking. Should not reach this condition.
9101 -- Rollback any db changes that might have occurred (currently none).
9102 ROLLBACK TO Crossdock_Demand_sp;
9103 GOTO next_demand;
9104 END IF; -- End locking demand line from different source types
9105
9106 IF (l_debug = 1) THEN
9107 print_debug('4.1 - Successfully locked the demand line record');
9108 END IF;
9109 l_progress := '460';
9110
9111 -- 4.2 - Call the available to reserve API to see how much quantity from the demand
9112 -- is valid for crossdocking.
9113 -- The quantity_backordered on the WIP demand is the same as
9114 -- the ATR qty so it is fully reserveable.
9115 IF (l_demand_type_id <> 5) THEN
9116 IF (l_debug = 1) THEN
9117 print_debug('4.2 - Call the Available_demand_to_reserve API');
9118 END IF;
9119 INV_RESERVATION_AVAIL_PVT.Available_demand_to_reserve
9120 (p_api_version_number => 1.0,
9121 p_init_msg_lst => fnd_api.g_false,
9122 x_return_status => x_return_status,
9123 x_msg_count => x_msg_count,
9124 x_msg_data => x_msg_data,
9125 p_primary_uom_code => l_primary_uom_code,
9126 p_demand_source_type_id => l_demand_type_id,
9127 p_demand_source_header_id => l_demand_header_id,
9128 p_demand_source_line_id => l_demand_line_id,
9129 p_demand_source_line_detail => l_demand_line_detail_id,
9130 p_project_id => l_demand_project_id,
9131 p_task_id => l_demand_task_id,
9132 x_qty_available_to_reserve => l_demand_atr_prim_qty,
9133 x_qty_available => l_demand_available_qty);
9134
9135 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
9136 IF (l_debug = 1) THEN
9137 print_debug('4.2 - Error returned from available_demand_to_reserve API: '
9138 || x_return_status);
9139 END IF;
9140 -- Rollback any db changes that might have occurred (currently none).
9141 ROLLBACK TO Crossdock_Demand_sp;
9142 GOTO next_demand;
9143 END IF;
9144 ELSE
9145 -- WIP backordered component demand lines always store quantity in the primary UOM
9146 l_demand_atr_prim_qty := l_demand_qty;
9147 END IF;
9148
9149 -- Convert the ATR primary quantity to the UOM on the demand line
9150 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
9151 l_primary_uom_code, l_demand_uom_code);
9152 IF (l_conversion_rate < 0) THEN
9153 IF (l_debug = 1) THEN
9154 print_debug('4.2 - Error while obtaining Primary UOM conversion rate for demand line');
9155 END IF;
9156 -- Rollback any db changes that might have occurred (currently none).
9157 ROLLBACK TO Crossdock_Demand_sp;
9158 GOTO next_demand;
9159 END IF;
9160 -- Round the converted quantity to the standard precision
9161 l_demand_atr_qty := ROUND(l_conversion_rate * l_demand_atr_prim_qty, l_conversion_precision);
9162
9163 -- Set the reservable quantity field for the current demand line
9164 -- in the shopping basket table.
9165 l_shopping_basket_tb(l_demand_index).reservable_quantity := l_demand_atr_qty;
9166
9167 IF (l_debug = 1) THEN
9168 print_debug('4.2 - Demand line ATR qty: ' || l_demand_atr_qty || ' ' ||
9169 l_demand_uom_code);
9170 END IF;
9171 -- If the current demand line has no reservable quantity,
9172 -- skip it and go to the next available demand line.
9173 -- {{
9174 -- Test for an available demand line for crossdocking that has no available quantity
9175 -- to reserve. This line is already satisfied by another existing reservation. }}
9176 IF (l_demand_atr_qty <= 0) THEN
9177 IF (l_debug = 1) THEN
9178 print_debug('4.2 - Demand ATR qty <= 0 so skip to next available demand');
9179 END IF;
9180 -- Rollback any db changes that might have occurred (currently none).
9181 ROLLBACK TO Crossdock_Demand_sp;
9182 GOTO next_demand;
9183 END IF;
9184 l_progress := '470';
9185
9186 -- 4.3 - Crossdock the demand and supply line records.
9187 IF (l_debug = 1) THEN
9188 print_debug('4.3 - Crossdock the demand and supply line records');
9189 END IF;
9190
9191 -- Convert the WDD ATR qty to the UOM on the MOL supply line. This value should not be zero
9192 -- if we have reached this point. Also convert the WDD qty to the UOM on the supply line.
9193 -- Since they use the same conversion rate, we just need to retrieve that value once.
9194 -- This is required so we know if the WDD line needs to be split or not. That would depend
9195 -- on the WDD qty, not the WDD ATR qty.
9196 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
9197 l_demand_uom_code, l_supply_uom_code);
9198 IF (l_conversion_rate < 0) THEN
9199 IF (l_debug = 1) THEN
9200 print_debug('4.3 - Error while obtaining UOM conversion rate for WDD/WIP qty');
9201 END IF;
9202 -- Rollback any db changes that might have occurred (currently none).
9203 ROLLBACK TO Crossdock_Demand_sp;
9204 GOTO next_demand;
9205 END IF;
9206 -- Round the converted quantity to the standard precision
9207 l_wdd_atr_txn_qty := ROUND(l_conversion_rate * l_demand_atr_qty, l_conversion_precision);
9208 l_wdd_txn_qty := ROUND(l_conversion_rate * l_demand_qty, l_conversion_precision);
9209 IF (l_debug = 1) THEN
9210 print_debug('4.3 - WDD/WIP ATR txn qty: => ' || l_wdd_atr_txn_qty || ' ' || l_supply_uom_code);
9211 print_debug('4.3 - WDD/WIP txn qty: =====> ' || l_wdd_txn_qty || ' ' || l_supply_uom_code);
9212 END IF;
9213 l_progress := '480';
9214
9215 -- Calculate the Available to Detail quantity.
9216 -- {{
9217 -- Test that the available to detail quantity is calculated properly,
9218 -- i.e. is lower than WDD/WIP ATR qty and supply line qty, and is an integer value if
9219 -- UOM integrity = 'Y'. }}
9220 IF (g_crossdock_criteria_tb(l_crossdock_criteria_id).uom_integrity_flag = 1) THEN
9221 -- UOM Integrity is 'Yes'
9222 l_atd_qty := LEAST(FLOOR(l_wdd_atr_txn_qty), FLOOR(l_supply_atr_qty));
9223 ELSE
9224 -- UOM Integrity is 'No'
9225 l_atd_qty := LEAST(l_wdd_atr_txn_qty, l_supply_atr_qty);
9226 END IF;
9227 IF (l_debug = 1) THEN
9228 print_debug('4.3 - Available to detail qty: ' || l_atd_qty || ' ' ||
9229 l_supply_uom_code);
9230 END IF;
9231 -- If the ATD qty is 0, then goto the next available demand line to crossdock.
9232 -- This is possible if the UOM integrity flag is 'Y' and the resultant quantities
9233 -- were floored to 0.
9234 -- {{
9235 -- Test for ATD qty = 0. This can come about if UOM integrity is Yes and the
9236 -- demand line with available to reserve qty gets floored to 0. }}
9237 IF (l_atd_qty = 0) THEN
9238 IF (l_debug = 1) THEN
9239 print_debug('4.3 - ATD qty = 0 so skip to the next available demand');
9240 END IF;
9241 -- Rollback any db changes that might have occurred (currently none).
9242 ROLLBACK TO Crossdock_Demand_sp;
9243 GOTO next_demand;
9244 END IF;
9245 l_progress := '490';
9246
9247 -- Convert l_atd_qty to the primary UOM
9248 l_conversion_rate := get_conversion_rate(l_inventory_item_id,
9249 l_supply_uom_code, l_primary_uom_code);
9250 IF (l_conversion_rate < 0) THEN
9251 IF (l_debug = 1) THEN
9252 print_debug('4.3 - Error while obtaining primary UOM conversion rate for ATD qty');
9253 END IF;
9254 -- Rollback any db changes that might have occurred (currently none).
9255 ROLLBACK TO Crossdock_Demand_sp;
9256 GOTO next_demand;
9257 END IF;
9258 -- Convert l_atd_qty to the primary UOM
9259 -- Bug 5608611: Use quantity from demand document where possible
9260 IF (l_atd_qty = l_wdd_atr_txn_qty AND l_demand_uom_code = l_primary_uom_code) THEN
9261 l_atd_prim_qty := l_demand_atr_qty;
9262 ELSE
9263 -- Round the converted quantity to the standard precision
9264 l_atd_prim_qty := ROUND(l_conversion_rate * l_atd_qty, l_conversion_precision);
9265 END IF;
9266 IF (l_debug = 1) THEN
9267 print_debug('4.3 - ATD qty in primary UOM: => ' || l_atd_prim_qty || ' ' ||
9268 l_primary_uom_code);
9269 END IF;
9270 l_progress := '500';
9271
9272 -- Crossdock the WDD/WIP demand record
9273 IF (l_demand_type_id <> 5) THEN
9274 -- Crossdock the WDD record, splitting it if necessary.
9275 IF (l_debug = 1) THEN
9276 print_debug('4.3 - Call the Crossdock_WDD API to crossdock/split the WDD');
9277 END IF;
9278 Crossdock_WDD
9279 (p_log_prefix => '4.3 - ',
9280 p_crossdock_type => G_CRT_TYPE_OPP,
9281 p_batch_id => l_batch_id,
9282 p_wsh_release_table => l_wsh_release_table,
9283 p_trolin_delivery_ids => l_trolin_delivery_ids,
9284 p_del_detail_id => l_del_detail_id,
9285 l_wdd_index => l_dummy_wdd_index,
9286 l_debug => l_debug,
9287 l_inventory_item_id => l_inventory_item_id,
9288 l_wdd_txn_qty => l_wdd_txn_qty,
9289 l_atd_qty => l_atd_qty,
9290 l_atd_wdd_qty => l_atd_wdd_qty,
9291 l_atd_wdd_qty2 => l_atd_wdd_qty2,
9292 l_supply_uom_code => l_supply_uom_code,
9293 l_demand_uom_code => l_demand_uom_code,
9294 l_demand_uom_code2 => l_demand_uom_code2,
9295 l_conversion_rate => l_conversion_rate,
9296 l_conversion_precision => l_conversion_precision,
9297 l_demand_line_detail_id => l_demand_line_detail_id,
9298 l_index => l_index,
9299 l_detail_id_tab => l_detail_id_tab,
9300 l_action_prms => l_action_prms,
9301 l_action_out_rec => l_action_out_rec,
9302 l_split_wdd_id => l_split_wdd_id,
9303 l_detail_info_tab => l_detail_info_tab,
9304 l_in_rec => l_in_rec,
9305 l_out_rec => l_out_rec,
9306 l_mol_line_id => l_mol_line_id,
9307 l_split_wdd_index => l_split_wdd_index,
9308 l_split_delivery_index => l_split_delivery_index,
9309 l_split_wdd_rel_rec => l_split_wdd_rel_rec,
9310 l_allocation_method => l_allocation_method,
9311 l_demand_qty => l_demand_qty,
9312 l_demand_qty2 => l_demand_qty2,
9313 l_demand_atr_qty => l_demand_atr_qty,
9314 l_xdocked_wdd_index => l_xdocked_wdd_index,
9315 l_supply_type_id => l_supply_type_id,
9316 x_return_status => x_return_status,
9317 x_msg_count => x_msg_count,
9318 x_msg_data => x_msg_data,
9319 x_error_code => l_error_code
9320 );
9321
9322 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
9323 IF (l_debug = 1) THEN
9324 print_debug('4.3 - Error returned from Crossdock_WDD API: '
9325 || x_return_status);
9326 END IF;
9327 --RAISE fnd_api.g_exc_error;
9328 -- If an exception occurs while modifying a database record, rollback the changes
9329 -- and just go to the next available demand to crossdock
9330 ROLLBACK TO Crossdock_Demand_sp;
9331 -- We need to also rollback changes done to local PLSQL data structures
9332 IF (l_xdocked_wdd_index IS NOT NULL) THEN
9333 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
9334 END IF;
9335 GOTO next_demand;
9336 ELSE
9337 IF (l_debug = 1) THEN
9338 print_debug('4.3 - Successfully crossdocked/split the WDD record');
9339 END IF;
9340 END IF;
9341 l_progress := '510';
9342
9343 ELSE
9344 -- Crossdock the WIP demand record.
9345 -- {{
9346 -- Verify that the WIP API properly allocates the crossdocked material when
9347 -- the demand is WIP. }}
9348 IF (l_debug = 1) THEN
9349 print_debug('4.3 - Call wip_picking_pub.allocate_material to crossdock the WIP demand');
9350 END IF;
9351 wip_picking_pub.allocate_material
9352 (p_wip_entity_id => l_wip_entity_id,
9353 p_operation_seq_num => l_operation_seq_num,
9354 p_inventory_item_id => l_inventory_item_id,
9355 p_repetitive_schedule_id => l_repetitive_schedule_id,
9356 p_primary_quantity => l_atd_prim_qty,
9357 x_quantity_allocated => l_wip_qty_allocated,
9358 x_return_status => x_return_status,
9359 x_msg_data => x_msg_data
9360 );
9361
9362 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS OR l_wip_qty_allocated = 0) THEN
9363 IF (l_debug = 1) THEN
9364 print_debug('4.3 - Error returned from wip_picking_pub.allocate_material API: '
9365 || x_return_status);
9366 END IF;
9367 --RAISE fnd_api.g_exc_error;
9368 -- If an exception occurs while modifying a database record, rollback the changes
9369 -- and just go to the next available demand to crossdock
9370 ROLLBACK TO Crossdock_Demand_sp;
9371 GOTO next_demand;
9372 ELSE
9373 IF (l_debug = 1) THEN
9374 print_debug('4.3 - Successfully crossdocked the WIP demand');
9375 END IF;
9376 END IF;
9377 l_progress := '515';
9378 END IF;
9379
9380
9381 -- Crossdock the MOL supply line, splitting it if necessary
9382 IF (l_debug = 1) THEN
9383 print_debug('4.3 - Call the Crossdock_MOL API to crossdock/split the MOL');
9384 END IF;
9385 Crossdock_MOL
9386 (p_log_prefix => '4.3 - ',
9387 p_crossdock_type => G_CRT_TYPE_OPP,
9388 l_debug => l_debug,
9389 l_inventory_item_id => l_inventory_item_id,
9390 l_mol_qty => l_mol_qty,
9391 l_mol_qty2 => l_mol_qty2,
9392 l_atd_qty => l_atd_qty,
9393 l_atd_mol_qty2 => l_atd_mol_qty2,
9394 l_supply_uom_code => l_supply_uom_code,
9395 l_mol_uom_code2 => l_mol_uom_code2,
9396 l_conversion_rate => l_conversion_rate,
9397 l_conversion_precision => l_conversion_precision,
9398 l_mol_prim_qty => l_mol_prim_qty,
9399 l_atd_prim_qty => l_atd_prim_qty,
9400 l_split_wdd_id => l_split_wdd_id,
9401 l_mol_header_id => l_mol_header_id,
9402 l_mol_line_id => l_mol_line_id,
9403 l_supply_atr_qty => l_supply_atr_qty,
9404 l_demand_type_id => l_demand_type_id,
9405 l_wip_entity_id => l_wip_entity_id,
9406 l_operation_seq_num => l_operation_seq_num,
9407 l_repetitive_schedule_id => l_repetitive_schedule_id,
9408 l_wip_supply_type => l_wip_supply_type,
9409 l_xdocked_wdd_index => l_xdocked_wdd_index,
9410 l_detail_info_tab => l_detail_info_tab,
9411 l_wdd_index => l_dummy_wdd_index,
9412 l_split_wdd_index => l_split_wdd_index,
9413 p_wsh_release_table => l_wsh_release_table,
9414 l_supply_type_id => l_supply_type_id,
9415 x_return_status => x_return_status,
9416 x_msg_count => x_msg_count,
9417 x_msg_data => x_msg_data,
9418 x_error_code => l_error_code,
9419 l_criterion_type => G_CRT_TYPE_OPP
9420 );
9421
9422 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
9423 IF (l_debug = 1) THEN
9424 print_debug('4.3 - Error returned from Crossdock_MOL API: '
9425 || x_return_status);
9426 END IF;
9427 --RAISE fnd_api.g_exc_error;
9428 -- If an exception occurs while modifying a database record, rollback the changes
9429 -- and just go to the next WDD record or supply to crossdock.
9430 ROLLBACK TO Crossdock_Demand_sp;
9431 -- We need to also rollback changes done to local PLSQL data structures
9432 IF (l_xdocked_wdd_index IS NOT NULL) THEN
9433 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
9434 END IF;
9435 GOTO next_demand;
9436 ELSE
9437 IF (l_debug = 1) THEN
9438 print_debug('4.3 - Successfully crossdocked/split the MOL record');
9439 END IF;
9440 END IF;
9441 l_progress := '520';
9442
9443 -- 4.4 - Create a crossdocked reservation tying the demand to the supply line.
9444 -- Calculate the supply expected time
9445 IF (l_debug = 1) THEN
9446 print_debug('4.4 - Create a crossdock reservation peg to tie the demand to the supply');
9447 END IF;
9448
9449 -- Call the Create_RSV API to create a crossdock reservation.
9450 -- Do this only for OE demand, not WIP.
9451 -- For WIP supply, create a reservation only if the WIP entity type is 'Discrete'.
9452 -- Flow WIP LPN completions should not create reservations here. They are created
9453 -- immediately upon flow schedule completion against onhand Inventory.
9454 IF (l_demand_type_id <> 5 AND
9455 (l_wip_entity_type IS NULL OR l_wip_entity_type = 1)) THEN
9456 IF (l_debug = 1) THEN
9457 print_debug('4.4 - Call the Create_RSV API to create a crossdock reservation');
9458 END IF;
9459 Create_RSV
9460 (p_log_prefix => '4.4 - ',
9461 p_crossdock_type => G_CRT_TYPE_OPP,
9462 l_debug => l_debug,
9463 l_organization_id => l_organization_id,
9464 l_inventory_item_id => l_inventory_item_id,
9465 l_demand_type_id => l_demand_type_id,
9466 l_demand_so_header_id => l_demand_header_id, -- Use this value here for Opportunistic
9467 l_demand_line_id => l_demand_line_id,
9468 l_split_wdd_id => l_split_wdd_id,
9469 l_primary_uom_code => l_primary_uom_code,
9470 l_demand_uom_code2 => l_demand_uom_code2,
9471 l_supply_uom_code => l_supply_uom_code,
9472 l_atd_qty => l_atd_qty,
9473 l_atd_prim_qty => l_atd_prim_qty,
9474 l_atd_wdd_qty2 => l_atd_wdd_qty2,
9475 l_supply_type_id => l_supply_type_id,
9476 l_supply_header_id => l_supply_header_id,
9477 l_supply_line_id => l_supply_line_id,
9478 l_supply_line_detail_id => l_supply_line_detail_id,
9479 l_crossdock_criteria_id => l_crossdock_criteria_id,
9480 l_supply_expected_time => l_supply_expected_time,
9481 l_demand_expected_time => l_demand_expected_time,
9482 l_demand_project_id => l_demand_project_id,
9483 l_demand_task_id => l_demand_task_id,
9484 l_original_rsv_rec => l_original_rsv_rec,
9485 l_original_serial_number => l_original_serial_number,
9486 l_to_serial_number => l_to_serial_number,
9487 l_quantity_reserved => l_quantity_reserved,
9488 l_quantity_reserved2 => l_quantity_reserved2,
9489 l_rsv_id => l_rsv_id,
9490 x_return_status => x_return_status,
9491 x_msg_count => x_msg_count,
9492 x_msg_data => x_msg_data
9493 );
9494
9495 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
9496 IF (l_debug = 1) THEN
9497 print_debug('4.4 - Error returned from create_reservation API: '
9498 || x_return_status);
9499 END IF;
9500 --RAISE fnd_api.g_exc_error;
9501 -- If an exception occurs while modifying a database record, rollback the changes
9502 -- and just go to the next WDD record to crossdock.
9503 ROLLBACK TO Crossdock_Demand_sp;
9504 -- We need to also rollback changes done to local PLSQL data structures
9505 IF (l_xdocked_wdd_index IS NOT NULL) THEN
9506 l_detail_info_tab.DELETE(l_xdocked_wdd_index);
9507 END IF;
9508 GOTO next_demand;
9509 ELSE
9510 IF (l_debug = 1) THEN
9511 print_debug('4.4 - Successfully created a crossdock RSV record');
9512 END IF;
9513 END IF;
9514 END IF;
9515 l_progress := '530';
9516
9517 -- If the supply is a WIP discrete job, we only want to create reservation pegs
9518 -- tying the WIP job to the same OE Sales Order Line demand. The user can manually
9519 -- create multiple ones for the same WIP job to different OE demand from
9520 -- the reservations form, but from the crossdock pegging logic, we want to restrict this.
9521 -- The reason is due to WIP not having the logic to know which reservation to consume
9522 -- when the WIP job LPN is being putaway. If we have reached this point, a crossdock
9523 -- peg has already been created. Set the l_wip_demand variables so we will only
9524 -- crossdock to that OE demand. (You can have multiple WDD records for the same SO line).
9525 IF (l_wip_entity_type = 1 AND l_wip_demand_header_id IS NULL) THEN
9526 IF (l_demand_type_id <> 5) THEN
9527 -- OE demand that was just crossdocked for WIP Discrete supply.
9528 -- We want to restrict future crossdock pegs to only go against this same demand.
9529 l_wip_demand_type_id := l_demand_type_id;
9530 l_wip_demand_header_id := l_demand_header_id;
9531 l_wip_demand_line_id := l_demand_line_id;
9532 IF (l_debug = 1) THEN
9533 print_debug('4.4 - Supply is a WIP Discrete job and a crossdock has occurred');
9534 print_debug('4.4 - Unique OE demand we are ONLY allowed to peg to');
9535 print_debug('4.4 - Demand Type ID: ===> ' || l_wip_demand_type_id);
9536 print_debug('4.4 - Demand Header ID: => ' || l_wip_demand_header_id);
9537 print_debug('4.4 - Demand Line ID: ===> ' || l_wip_demand_line_id);
9538 END IF;
9539 END IF;
9540 END IF;
9541
9542
9543 -- Exit out of available demand lines loop if the MOL supply has been fully crossdocked.
9544 -- There is no need to consider anymore demand lines for crossdocking.
9545 IF (l_supply_atr_qty <= 0) THEN
9546 EXIT;
9547 END IF;
9548
9549 <<next_demand>>
9550 -- Exit when all demand lines have been considered
9551 EXIT WHEN l_demand_index = l_shopping_basket_tb.LAST;
9552 l_demand_index := l_shopping_basket_tb.NEXT(l_demand_index);
9553 END LOOP; -- End looping through demand lines in shopping basket table
9554 l_progress := '540';
9555
9556 -- Done with crossdocking logic
9557 -- This label should come before the post crossdocking logic to update WDD records.
9558 -- If the MOL is completely used to fulfill an existing reservation, we will go to
9559 -- this label and the logic to update the WDD records needs to be done.
9560 <<end_crossdock>>
9561
9562 -- Section 5: Post crossdocking logic
9563 -- 5.1 - For all crossdocked WDD lines, call the shipping API to update the
9564 -- released_status and move_order_line_id columns.
9565 -- 5.2 - Bug 5194761: clear the temp table wms_xdock_pegging_gtmp
9566 -- {{
9567 -- Make sure the shipping API to update crossdocked WDD lines is only called if necessary
9568 -- and properly updates the WDD records. }}
9569 IF (l_detail_info_tab.COUNT > 0) THEN
9570 IF (l_debug = 1) THEN
9571 print_debug('5.1 - Call the Create_Update_Delivery_Detail API for ' ||
9572 l_detail_info_tab.COUNT || ' crossdocked WDD records');
9573 END IF;
9574
9575 l_in_rec.caller := 'WMS_XDOCK_PEGGING_PUB';
9576 l_in_rec.action_code := 'UPDATE';
9577
9578 WSH_INTERFACE_EXT_GRP.Create_Update_Delivery_Detail
9579 (p_api_version_number => 1.0,
9580 p_init_msg_list => fnd_api.g_false,
9581 p_commit => fnd_api.g_false,
9582 x_return_status => x_return_status,
9583 x_msg_count => x_msg_count,
9584 x_msg_data => x_msg_data,
9585 p_detail_info_tab => l_detail_info_tab,
9586 p_in_rec => l_in_rec,
9587 x_out_rec => l_out_rec
9588 );
9589
9590 IF (x_return_status <> FND_API.G_RET_STS_SUCCESS) THEN
9591 IF (l_debug = 1) THEN
9592 print_debug('5.1 - Error returned from Create_Update_Delivery_Detail API: '
9593 || x_return_status);
9594 END IF;
9595 RAISE FND_API.G_EXC_ERROR;
9596 ELSE
9597 IF (l_debug = 1) THEN
9598 print_debug('5.1 - Successfully updated the crossdocked WDD records');
9599 END IF;
9600 END IF;
9601 END IF;
9602 l_progress := '550';
9603
9604 -- Bug 5194761: delete records from wms_xdock_pegging_gtmp
9605 DELETE wms_xdock_pegging_gtmp;
9606 IF (l_debug = 1) AND SQL%FOUND THEN
9607 print_debug('5.2 - Cleared the temp table wms_xdock_pegging_gtmp');
9608 END IF;
9609
9610 -- If we have reached this point, the return status should be set to success.
9611 -- This variable is reused each time we call another API but we try to continue with the
9612 -- flow and raise an exception only when absolutely necessary. Since this is a planning
9613 -- and pegging API, if exceptions occur, we should just not peg anything instead of throwing
9614 -- errors.
9615 x_return_status := fnd_api.g_ret_sts_success;
9616 l_progress := '560';
9617
9618 IF (l_debug = 1) THEN
9619 print_debug('***End of Opportunistic_Cross_Dock***');
9620 END IF;
9621
9622 -- Stop the profiler
9623 -- dbms_profiler.stop_profiler;
9624
9625 EXCEPTION
9626 WHEN FND_API.G_EXC_ERROR THEN
9627 ROLLBACK TO Opportunistic_Cross_Dock_sp;
9628 x_return_status := fnd_api.g_ret_sts_error;
9629 fnd_msg_pub.count_and_get(p_count => x_msg_count,
9630 p_data => x_msg_data);
9631 IF (l_debug = 1) THEN
9632 print_debug('Exiting Opportunistic_Cross_Dock - Execution error: ' ||
9633 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
9634 END IF;
9635
9636 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
9637 ROLLBACK TO Opportunistic_Cross_Dock_sp;
9638 x_return_status := fnd_api.g_ret_sts_unexp_error;
9639 fnd_msg_pub.count_and_get(p_count => x_msg_count,
9640 p_data => x_msg_data);
9641 IF (l_debug = 1) THEN
9642 print_debug('Exiting Opportunistic_Cross_Dock - Unexpected error: ' ||
9643 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
9644 END IF;
9645
9646 WHEN OTHERS THEN
9647 ROLLBACK TO Opportunistic_Cross_Dock_sp;
9648 x_return_status := fnd_api.g_ret_sts_unexp_error;
9649 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
9650 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
9651 END IF;
9652 fnd_msg_pub.count_and_get(p_count => x_msg_count,
9653 p_data => x_msg_data);
9654 IF (l_debug = 1) THEN
9655 print_debug('Exiting Opportunistic_Cross_Dock - Others exception: ' ||
9656 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
9657 END IF;
9658
9659 END Opportunistic_Cross_Dock;
9660 -- {{ }}
9661 -- {{******************** End Opportunistic_Cross_Dock ********************}}
9662 -- {{ }}
9663
9664
9665 -- p_source_type_id refers to new lookup_type in mfg_lookups called 'Reservation_Types'
9666 -- Valid supplies:
9667 -- 1 - Purchase Order
9668 -- 7 - Internal Requisition
9669 -- 25 - ASN
9670 -- 26 - In Transit Shipment
9671 -- Valid demands:
9672 -- 2 - Sales Order
9673 -- 8 - Internal Order
9674 -- Supply of type Receiving is material already received so there is no need to get an expected
9675 -- receipt time for that. SYSDATE at the time the crossdock peg is created will be used and stamped
9676 -- on the reservation. Demand of type WIP (backordered component demand) will always use the
9677 -- date_required field in the view wip_material_shortages_v as the expected ship time. Other
9678 -- source types will not currently be supported in this API.
9679 -- {{ }}
9680 -- {{******************** Procedure Get_Expected_Time ********************}}
9681 PROCEDURE Get_Expected_Time
9682 (p_source_type_id IN NUMBER,
9683 p_source_header_id IN NUMBER,
9684 p_source_line_id IN NUMBER,
9685 p_source_line_detail_id IN NUMBER,
9686 p_supply_or_demand IN NUMBER,
9687 p_crossdock_criterion_id IN NUMBER,
9688 x_return_status OUT NOCOPY VARCHAR2,
9689 x_msg_count OUT NOCOPY NUMBER,
9690 x_msg_data OUT NOCOPY VARCHAR2,
9691 x_dock_start_time OUT NOCOPY DATE,
9692 x_dock_mean_time OUT NOCOPY DATE,
9693 x_dock_end_time OUT NOCOPY DATE,
9694 x_expected_time OUT NOCOPY DATE)
9695 IS
9696 l_api_name CONSTANT VARCHAR2(30) := 'Get_Expected_Time';
9697 l_progress VARCHAR2(10);
9698 l_debug NUMBER := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
9699
9700 -- This variable is used to indicate if the custom API was used to determine
9701 -- the expected time values.
9702 l_api_is_implemented BOOLEAN;
9703
9704 -- Cursor to retrieve the trip stop id, carrier id, and expected ship time
9705 -- (without considering dock appointments) for a WDD demand line.
9706 -- The order to look for this information is documented in the Crossdock Pegging TDD.
9707 -- Make use of outer joins in a cascading manner since records might not exist in all
9708 -- of the tables. WSH_DELIVERY_LEGS could have multiple trip stops for the same delivery.
9709 -- For our purposes, we want to pick the first one, hence choose the one with the minimum
9710 -- value for the sequence_number. This is contingent upon a delivery being present for
9711 -- the WDD demand line. For WDD demand lines, reservations will store the mtl sales order
9712 -- header ID, OE order line ID, and WDD delivery detail ID as the source header ID, line ID,
9713 -- and line detail ID respectively.
9714 CURSOR wdd_rec_cursor IS
9715 SELECT wdd.organization_id AS organization_id,
9716 wts.stop_id AS trip_stop_id,
9717 NVL(wt.carrier_id,
9718 NVL(NVL(wnd.carrier_id, wcs_wnd.carrier_id),
9719 NVL(NVL(wdd.carrier_id, wcs_wdd.carrier_id),
9720 NVL(wc_ool.carrier_id, wcs_ool.carrier_id)))) AS carrier_id,
9721 NVL(wts.planned_departure_date,
9722 NVL(wdd.date_scheduled,
9723 NVL(ool.schedule_ship_date, ool.promise_date))) AS expected_ship_date
9724 FROM wsh_delivery_details wdd, oe_order_lines_all ool,
9725 wsh_delivery_assignments_v wda, wsh_new_deliveries wnd, wsh_delivery_legs wdl,
9726 wsh_trip_stops wts, wsh_trips wt, wsh_carrier_services wcs_wnd,
9727 wsh_carrier_services wcs_wdd, wsh_carrier_services wcs_ool, wsh_carriers wc_ool
9728 WHERE wdd.delivery_detail_id = p_source_line_detail_id
9729 AND ool.line_id = p_source_line_id
9730 AND wdd.source_line_id = ool.line_id
9731 AND inv_salesorder.get_salesorder_for_oeheader(wdd.source_header_id) = p_source_header_id
9732 AND wdd.delivery_detail_id = wda.delivery_detail_id (+)
9733 AND wda.delivery_id = wnd.delivery_id (+)
9734 AND wnd.delivery_id = wdl.delivery_id (+)
9735 AND (wdl.sequence_number IS NULL OR
9736 wdl.sequence_number = (SELECT MIN(sequence_number)
9737 FROM wsh_delivery_legs wdl_first_leg
9738 WHERE wdl_first_leg.delivery_id = wdl.delivery_id))
9739 AND wdl.pick_up_stop_id = wts.stop_id (+)
9740 AND wts.trip_id = wt.trip_id (+)
9741 AND wnd.ship_method_code = wcs_wnd.ship_method_code (+)
9742 AND wdd.ship_method_code = wcs_wdd.ship_method_code (+)
9743 AND ool.shipping_method_code = wcs_ool.ship_method_code (+)
9744 AND ool.freight_carrier_code = wc_ool.freight_code (+);
9745
9746
9747 -- Cursor to retrieve the trip stop id, carrier id, and expected receipt time
9748 -- (without considering dock appointments) for a PO supply line.
9749 -- For PO supply lines, reservations will store the PO header ID, PO line location ID,
9750 -- and NULL as the source header ID, line ID, and line detail ID respectively.
9751 -- NOTE REGARDING INBOUND TRIPS:
9752 -- Currently, when an Inbound Trip is created, the trip has a planned arrival date
9753 -- set to be the last accept date for the inbound supply. When a shipment is created,
9754 -- the planned arrival date of the trip does not get updated. Thus the expected
9755 -- receipt date returned from this cursor is not the most accurate until the issue
9756 -- with trips is resolved.
9757 CURSOR po_rec_cursor IS
9758 SELECT poll.ship_to_organization_id AS organization_id,
9759 wts.stop_id AS trip_stop_id,
9760 NVL(wt.carrier_id,
9761 NVL(NVL(wnd.carrier_id, wcs_wnd.carrier_id),
9762 NVL(NVL(wdd.carrier_id, wcs_wdd.carrier_id),
9763 wc_poll.carrier_id))) AS carrier_id,
9764 NVL(wts.planned_arrival_date,
9765 NVL(poll.promised_date, poll.need_by_date)) AS expected_receipt_date
9766 FROM po_line_locations_all poll, wsh_delivery_details wdd,
9767 wsh_delivery_assignments_v wda, wsh_new_deliveries wnd, wsh_delivery_legs wdl,
9768 wsh_trip_stops wts, wsh_trips wt, wsh_carrier_services wcs_wnd,
9769 wsh_carrier_services wcs_wdd, wsh_carriers wc_poll
9770 WHERE poll.po_header_id = p_source_header_id
9771 AND poll.line_location_id = p_source_line_id
9772 AND poll.po_header_id = wdd.source_header_id (+)
9773 AND poll.po_line_id = wdd.source_line_id (+)
9774 AND poll.line_location_id = wdd.po_shipment_line_id (+)
9775 AND 'PO' = wdd.source_code (+)
9776 AND 'I' = wdd.line_direction (+)
9777 AND 'L' <> wdd.released_status (+)
9778 AND wdd.delivery_detail_id = wda.delivery_detail_id (+)
9779 AND wda.delivery_id = wnd.delivery_id (+)
9780 AND wnd.delivery_id = wdl.delivery_id (+)
9781 AND (wdl.sequence_number IS NULL OR
9782 wdl.sequence_number = (SELECT MIN(sequence_number)
9783 FROM wsh_delivery_legs wdl_first_leg
9784 WHERE wdl_first_leg.delivery_id = wdl.delivery_id))
9785 AND wdl.drop_off_stop_id = wts.stop_id (+)
9786 AND wts.trip_id = wt.trip_id (+)
9787 AND wnd.ship_method_code = wcs_wnd.ship_method_code (+)
9788 AND wdd.ship_method_code = wcs_wdd.ship_method_code (+)
9789 AND poll.ship_via_lookup_code = wc_poll.freight_code (+)
9790 ORDER BY expected_receipt_date ASC;
9791
9792
9793 -- Cursor to retrieve the trip stop id, carrier id, and expected receipt time
9794 -- (without considering dock appointments) for an ASN supply line.
9795 -- For ASN supply lines, reservations will store the PO header ID, PO line location ID,
9796 -- and RCV shipment line ID as the source header ID, line ID, and line detail ID respectively.
9797 -- NOTE REGARDING INBOUND TRIPS:
9798 -- Currently, when an Inbound Trip is created, the trip has a planned arrival date
9799 -- set to be the last accept date for the inbound supply. When a shipment is created,
9800 -- the planned arrival date of the trip does not get updated. Thus the expected
9801 -- receipt date returned from this cursor is not the most accurate until the issue
9802 -- with trips is resolved.
9803 CURSOR asn_rec_cursor IS
9804 SELECT rsl.to_organization_id AS organization_id,
9805 wts.stop_id AS trip_stop_id,
9806 NVL(wt.carrier_id,
9807 NVL(NVL(wnd.carrier_id, wcs_wnd.carrier_id),
9808 NVL(NVL(wdd.carrier_id, wcs_wdd.carrier_id),
9809 NVL(wc_rsh.carrier_id,
9810 wc_poll.carrier_id)))) AS carrier_id,
9811 NVL(wts.planned_arrival_date,
9812 NVL(NVL(rsh.expected_receipt_date, rsh.shipped_date),
9813 NVL(poll.promised_date, poll.need_by_date))) AS expected_receipt_date
9814 FROM po_line_locations_all poll, wsh_delivery_details wdd,
9815 rcv_shipment_headers rsh, rcv_shipment_lines rsl,
9816 wsh_delivery_assignments_v wda, wsh_new_deliveries wnd, wsh_delivery_legs wdl,
9817 wsh_trip_stops wts, wsh_trips wt, wsh_carrier_services wcs_wnd,
9818 wsh_carrier_services wcs_wdd, wsh_carriers wc_poll, wsh_carriers wc_rsh
9819 WHERE rsl.po_header_id = p_source_header_id
9820 AND rsl.po_line_location_id = p_source_line_id
9821 AND rsl.shipment_line_id = p_source_line_detail_id
9822 AND poll.po_header_id = rsl.po_header_id
9823 AND poll.po_line_id = rsl.po_line_id
9824 AND poll.line_location_id = rsl.po_line_location_id
9825 AND rsl.shipment_header_id = rsh.shipment_header_id
9826 AND rsh.shipment_num IS NOT NULL
9827 AND rsh.receipt_source_code = 'VENDOR'
9828 AND rsh.asn_type IN ('ASN', 'ASBN')
9829 AND rsl.po_header_id = wdd.source_header_id (+)
9830 AND rsl.po_line_id = wdd.source_line_id (+)
9831 AND rsl.po_line_location_id = wdd.po_shipment_line_id (+)
9832 AND rsl.shipment_line_id = wdd.rcv_shipment_line_id (+)
9833 AND 'PO' = wdd.source_code (+)
9834 AND 'I' = wdd.line_direction (+)
9835 AND 'L' <> wdd.released_status (+)
9836 AND wdd.delivery_detail_id = wda.delivery_detail_id (+)
9837 AND wda.delivery_id = wnd.delivery_id (+)
9838 AND wnd.delivery_id = wdl.delivery_id (+)
9839 AND (wdl.sequence_number IS NULL OR
9840 wdl.sequence_number = (SELECT MIN(sequence_number)
9841 FROM wsh_delivery_legs wdl_first_leg
9842 WHERE wdl_first_leg.delivery_id = wdl.delivery_id))
9843 AND wdl.drop_off_stop_id = wts.stop_id (+)
9844 AND wts.trip_id = wt.trip_id (+)
9845 AND wnd.ship_method_code = wcs_wnd.ship_method_code (+)
9846 AND wdd.ship_method_code = wcs_wdd.ship_method_code (+)
9847 AND poll.ship_via_lookup_code = wc_poll.freight_code (+)
9848 AND rsh.freight_carrier_code = wc_rsh.freight_code (+);
9849
9850
9851 -- Cursor to retrieve the trip stop id, carrier id, and expected receipt time
9852 -- (without considering dock appointments) for an Internal Requisition supply line.
9853 -- For Internal Req supply lines, reservations will store the Req header ID, Req line ID,
9854 -- and NULL as the source header ID, line ID, and line detail ID respectively.
9855 -- For release R12, since reservations for Internal Requisitions will only be at the
9856 -- Req header and line level, there can be multiple shipments tied to a given reservation.
9857 -- Ideally reservations should also be at the shipment line level for Internal Reqs that
9858 -- have shipped. Due to this limitation, when determining the expected receipt time,
9859 -- just use the earliest expected_receipt_date. There can be multiple records returned
9860 -- from this cursor if multiple shipment lines for the Internal Req exist.
9861 -- NOTE REGARDING INBOUND TRIPS:
9862 -- Currently, when an Inbound Trip is created, the trip has a planned arrival date
9863 -- set to be the last accept date for the inbound supply. When a shipment is created,
9864 -- the planned arrival date of the trip does not get updated. Thus the expected
9865 -- receipt date returned from this cursor is not the most accurate until the issue
9866 -- with trips is resolved.
9867 CURSOR intreq_rec_cursor IS
9868 SELECT prl.destination_organization_id AS organization_id,
9869 wts.stop_id AS trip_stop_id,
9870 NVL(wt.carrier_id,
9871 NVL(NVL(wnd.carrier_id, wcs_wnd.carrier_id),
9872 NVL(NVL(wdd.carrier_id, wcs_wdd.carrier_id),
9873 NVL(NVL(wc_ool.carrier_id, wcs_ool.carrier_id),
9874 NVL(wc_rsh.carrier_id,
9875 wcs_prl.carrier_id))))) AS carrier_id,
9876 NVL(wts.planned_arrival_date,
9877 NVL(NVL(rsh.expected_receipt_date, rsh.shipped_date),
9878 prl.need_by_date)) AS expected_receipt_date
9879 FROM po_requisition_lines_all prl, rcv_shipment_lines rsl, rcv_shipment_headers rsh,
9880 oe_order_lines_all ool, wsh_delivery_details wdd,
9881 wsh_delivery_assignments_v wda, wsh_new_deliveries wnd, wsh_delivery_legs wdl,
9882 wsh_trip_stops wts, wsh_trips wt, wsh_carrier_services wcs_wnd,
9883 wsh_carrier_services wcs_wdd, wsh_carrier_services wcs_ool,
9884 wsh_carriers wc_ool, wsh_carriers wc_rsh, wsh_carrier_services wcs_prl
9885 WHERE prl.requisition_header_id = p_source_header_id
9886 AND prl.requisition_line_id = p_source_line_id
9887 AND prl.source_type_code = 'INVENTORY'
9888 AND NVL(prl.cancel_flag, 'N') = 'N'
9889 AND prl.requisition_line_id = rsl.requisition_line_id (+)
9890 AND rsl.shipment_header_id = rsh.shipment_header_id (+)
9891 AND 10 = ool.order_source_id (+) -- Internal Order source type
9892 AND prl.requisition_header_id = ool.source_document_id (+)
9893 AND prl.requisition_line_id = ool.source_document_line_id (+)
9894 AND prl.item_id = ool.inventory_item_id (+)
9895 AND ool.header_id = wdd.source_header_id (+)
9896 AND ool.line_id = wdd.source_line_id (+)
9897 AND 'OE' = wdd.source_code (+)
9898 AND 'IO' = wdd.line_direction (+)
9899 AND 'L' <> wdd.released_status (+)
9900 AND wdd.delivery_detail_id = wda.delivery_detail_id (+)
9901 AND wda.delivery_id = wnd.delivery_id (+)
9902 AND wnd.delivery_id = wdl.delivery_id (+)
9903 AND (wdl.sequence_number IS NULL OR
9904 wdl.sequence_number = (SELECT MIN(sequence_number)
9905 FROM wsh_delivery_legs wdl_first_leg
9906 WHERE wdl_first_leg.delivery_id = wdl.delivery_id))
9907 AND wdl.drop_off_stop_id = wts.stop_id (+)
9908 AND wts.trip_id = wt.trip_id (+)
9909 AND wnd.ship_method_code = wcs_wnd.ship_method_code (+)
9910 AND wdd.ship_method_code = wcs_wdd.ship_method_code (+)
9911 AND ool.shipping_method_code = wcs_ool.ship_method_code (+)
9912 AND ool.freight_carrier_code = wc_ool.freight_code (+)
9913 AND rsh.freight_carrier_code = wc_rsh.freight_code (+)
9914 AND prl.ship_method = wcs_prl.ship_method_code (+)
9915 ORDER BY expected_receipt_date ASC;
9916
9917
9918 -- Cursor to retrieve the trip stop id, carrier id, and expected receipt time
9919 -- (without considering dock appointments) for an In Transit Shipment supply line.
9920 -- For In Transit Shipment supply lines, reservations will store the RCV shipment header ID,
9921 -- RCV shipment line ID and NULL as the source header ID, line ID, and line detail ID
9922 -- respectively.
9923 CURSOR intship_rec_cursor IS
9924 SELECT rsl.to_organization_id AS organization_id,
9925 NULL AS trip_stop_id,
9926 wc_rsh.carrier_id as carrier_id,
9927 NVL(rsh.expected_receipt_date,
9928 NVL(rsh.shipped_date + NVL(mism.intransit_time, 0),
9929 rsh.shipped_date)) AS expected_receipt_date
9930 FROM rcv_shipment_lines rsl, rcv_shipment_headers rsh,
9931 wsh_carriers wc_rsh, mtl_interorg_ship_methods mism
9932 WHERE rsl.shipment_header_id = p_source_header_id
9933 AND rsl.shipment_line_id = p_source_line_id
9934 AND rsl.shipment_header_id = rsh.shipment_header_id
9935 AND rsh.shipment_num IS NOT NULL
9936 AND rsh.receipt_source_code = 'INVENTORY'
9937 AND rsh.freight_carrier_code = wc_rsh.freight_code (+)
9938 AND rsl.from_organization_id = mism.from_organization_id (+)
9939 AND rsl.to_organization_id = mism.to_organization_id (+)
9940 AND 1 = mism.default_flag (+);
9941
9942 -- Variables to retrieve the values from the source line cursors
9943 l_organization_id NUMBER;
9944 l_trip_stop_id NUMBER;
9945 l_carrier_id NUMBER;
9946 l_expected_date DATE;
9947
9948 -- Variables for calling the dock appointment API
9949 l_dock_appt_list WMS_DOCK_APPOINTMENTS_PUB.dock_appt_tb_tp;
9950
9951 -- Variables to loop through all dock appointments returned to find the one
9952 -- closest to the expected receipt/ship time.
9953 l_dock_schedule_method NUMBER;
9954 l_dock_start_time DATE;
9955 l_dock_mean_time DATE;
9956 l_dock_end_time DATE;
9957 l_dock_appt_time DATE;
9958 l_current_dock_appt_time DATE;
9959
9960 BEGIN
9961 IF (l_debug = 1) THEN
9962 print_debug('***Calling Get_Expected_Time with the following parameters***');
9963 print_debug('Package Version: ==========> ' || g_pkg_version);
9964 print_debug('p_source_type_id: =========> ' || p_source_type_id);
9965 print_debug('p_source_header_id: =======> ' || p_source_header_id);
9966 print_debug('p_source_line_id: =========> ' || p_source_line_id);
9967 print_debug('p_source_line_detail_id: ==> ' || p_source_line_detail_id);
9968 print_debug('p_supply_or_demand: =======> ' || p_supply_or_demand);
9969 print_debug('p_crossdock_criterion_id: => ' || p_crossdock_criterion_id);
9970 END IF;
9971
9972 -- Set the savepoint
9973 SAVEPOINT Get_Expected_Time_sp;
9974 l_progress := '10';
9975
9976 -- Initialize message list to clear any existing messages
9977 fnd_msg_pub.initialize;
9978 l_progress := '20';
9979
9980 -- Initialize API return status to success
9981 x_return_status := fnd_api.g_ret_sts_success;
9982 l_progress := '30';
9983
9984 -- Validate p_supply_or_demand
9985 -- {{
9986 -- Make sure API errors out if input variable p_supply_or_demand is not valid. }}
9987 IF (p_supply_or_demand NOT IN (G_SRC_TYPE_SUP, G_SRC_TYPE_DEM)) THEN
9988 IF (l_debug = 1) THEN
9989 print_debug('Invalid value for p_supply_or_demand: ' || p_supply_or_demand);
9990 END IF;
9991 RAISE fnd_api.g_exc_unexpected_error;
9992 END IF;
9993 l_progress := '40';
9994
9995 -- Validate that source type matches supply or demand
9996 IF (p_supply_or_demand = G_SRC_TYPE_SUP) THEN
9997 -- Check that source type is a valid supply source
9998 -- {{
9999 -- Make sure API errors out if supply type passed in is not valid. }}
10000 IF (p_source_type_id NOT IN (1, 7, 25, 26)) THEN
10001 IF (l_debug = 1) THEN
10002 print_debug('Invalid supply source type: ' || p_source_type_id);
10003 END IF;
10004 RAISE fnd_api.g_exc_unexpected_error;
10005 END IF;
10006 ELSIF (p_supply_or_demand = G_SRC_TYPE_DEM) THEN
10007 -- Check that source type is a valid demand source
10008 -- {{
10009 -- Make sure API errors out if demand type passed in is not valid. }}
10010 IF (p_source_type_id NOT IN (2, 8)) THEN
10011 IF (l_debug = 1) THEN
10012 print_debug('Invalid demand source type: ' || p_source_type_id);
10013 END IF;
10014 RAISE fnd_api.g_exc_unexpected_error;
10015 END IF;
10016 END IF;
10017 l_progress := '50';
10018
10019 -- If the crossdock criterion is passed, query and cache the value
10020 IF (p_crossdock_criterion_id IS NOT NULL) THEN
10021 IF (NOT set_crossdock_criteria(p_crossdock_criterion_id)) THEN
10022 IF (l_debug = 1) THEN
10023 print_debug('Unable to set the crossdock criterion: ' || p_crossdock_criterion_id);
10024 RAISE fnd_api.g_exc_unexpected_error;
10025 END IF;
10026 END IF;
10027
10028 -- Get the dock schedule method from the crossdock criterion
10029 -- {{
10030 -- If crossdock criterion is passed, make sure a valid non-null value for
10031 -- the dock schedule method is retrieved. }}
10032 IF (p_supply_or_demand = G_SRC_TYPE_SUP) THEN
10033 l_dock_schedule_method :=
10034 g_crossdock_criteria_tb(p_crossdock_criterion_id).supply_schedule_method;
10035 ELSIF (p_supply_or_demand = G_SRC_TYPE_DEM) THEN
10036 l_dock_schedule_method :=
10037 g_crossdock_criteria_tb(p_crossdock_criterion_id).demand_schedule_method;
10038 END IF;
10039 IF (l_debug = 1) THEN
10040 print_debug('Dock Schedule Method: ' || l_dock_schedule_method);
10041 END IF;
10042 END IF;
10043 l_progress := '60';
10044 -- End of validations and initializations
10045
10046
10047 -- Call the custom logic first to see if the API is implemented or not
10048 WMS_XDOCK_CUSTOM_APIS_PUB.Get_Expected_Time
10049 (p_source_type_id => p_source_type_id,
10050 p_source_header_id => p_source_header_id,
10051 p_source_line_id => p_source_line_id,
10052 p_source_line_detail_id => p_source_line_detail_id,
10053 p_supply_or_demand => p_supply_or_demand,
10054 p_crossdock_criterion_id => p_crossdock_criterion_id,
10055 p_dock_schedule_method => l_dock_schedule_method,
10056 x_return_status => x_return_status,
10057 x_msg_count => x_msg_count,
10058 x_msg_data => x_msg_data,
10059 x_api_is_implemented => l_api_is_implemented,
10060 x_dock_start_time => x_dock_start_time,
10061 x_dock_mean_time => x_dock_mean_time,
10062 x_dock_end_time => x_dock_end_time,
10063 x_expected_time => x_expected_time);
10064
10065 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
10066 IF (l_debug = 1) THEN
10067 print_debug('Success returned from Custom Get_Expected_Time API');
10068 END IF;
10069 ELSE
10070 IF (l_debug = 1) THEN
10071 print_debug('Failure returned from Custom Get_Expected_Time API');
10072 END IF;
10073 RAISE fnd_api.g_exc_error;
10074 END IF;
10075
10076 -- If the custom API is implemented, just use the values retrieved from there.
10077 -- Skip all further processing and logic in this API.
10078 IF (l_api_is_implemented) THEN
10079 IF (l_debug = 1) THEN
10080 print_debug('Custom API is implemented so using custom logic to get expected time');
10081 END IF;
10082 GOTO custom_logic_used;
10083 ELSE
10084 IF (l_debug = 1) THEN
10085 print_debug('Custom API is not implemented so using default logic to get expected time');
10086 END IF;
10087 END IF;
10088
10089 -- Check the source type to decide which cursor to open to retrieve the
10090 -- trip stop, carrier, and non-dock appointment derived expected receipt/ship time.
10091 IF (p_source_type_id IN (2, 8)) THEN
10092 -- Sales Order or Internal Order
10093 -- {{
10094 -- Get the expected time for a sales order and internal order demand. }}
10095 OPEN wdd_rec_cursor;
10096 FETCH wdd_rec_cursor INTO l_organization_id, l_trip_stop_id, l_carrier_id, l_expected_date;
10097 IF (wdd_rec_cursor%NOTFOUND) THEN
10098 IF (l_debug = 1) THEN
10099 print_debug('WDD cursor did not return any records!');
10100 END IF;
10101 CLOSE wdd_rec_cursor;
10102 RAISE fnd_api.g_exc_unexpected_error;
10103 END IF;
10104 CLOSE wdd_rec_cursor;
10105 ELSIF (p_source_type_id = 1) THEN
10106 -- Purchase Order
10107 -- {{
10108 -- Get the expected time for a PO. }}
10109 OPEN po_rec_cursor;
10110 FETCH po_rec_cursor INTO l_organization_id, l_trip_stop_id, l_carrier_id, l_expected_date;
10111 IF (po_rec_cursor%NOTFOUND) THEN
10112 IF (l_debug = 1) THEN
10113 print_debug('PO cursor did not return any records!');
10114 END IF;
10115 CLOSE po_rec_cursor;
10116 RAISE fnd_api.g_exc_unexpected_error;
10117 END IF;
10118 CLOSE po_rec_cursor;
10119 ELSIF (p_source_type_id = 25) THEN
10120 -- ASN
10121 -- {{
10122 -- Get the expected time for an ASN. }}
10123 OPEN asn_rec_cursor;
10124 FETCH asn_rec_cursor INTO l_organization_id, l_trip_stop_id, l_carrier_id, l_expected_date;
10125 IF (asn_rec_cursor%NOTFOUND) THEN
10126 IF (l_debug = 1) THEN
10127 print_debug('ASN cursor did not return any records!');
10128 END IF;
10129 CLOSE asn_rec_cursor;
10130 RAISE fnd_api.g_exc_unexpected_error;
10131 END IF;
10132 CLOSE asn_rec_cursor;
10133 ELSIF (p_source_type_id = 7) THEN
10134 -- Internal Requisition
10135 -- {{
10136 -- Get the expected time for an Internal Req. }}
10137 OPEN intreq_rec_cursor;
10138 FETCH intreq_rec_cursor INTO l_organization_id, l_trip_stop_id, l_carrier_id, l_expected_date;
10139 IF (intreq_rec_cursor%NOTFOUND) THEN
10140 IF (l_debug = 1) THEN
10141 print_debug('INTREQ cursor did not return any records!');
10142 END IF;
10143 CLOSE intreq_rec_cursor;
10144 RAISE fnd_api.g_exc_unexpected_error;
10145 END IF;
10146 CLOSE intreq_rec_cursor;
10147 ELSIF (p_source_type_id = 26) THEN
10148 -- In Transit Shipment
10149 -- {{
10150 -- Get the expected time for an In Transit Shipment. }}
10151 OPEN intship_rec_cursor;
10152 FETCH intship_rec_cursor INTO l_organization_id, l_trip_stop_id, l_carrier_id, l_expected_date;
10153 IF (intship_rec_cursor%NOTFOUND) THEN
10154 IF (l_debug = 1) THEN
10155 print_debug('INTSHIP cursor did not return any records!');
10156 END IF;
10157 CLOSE intship_rec_cursor;
10158 RAISE fnd_api.g_exc_unexpected_error;
10159 END IF;
10160 CLOSE intship_rec_cursor;
10161 END IF;
10162 l_progress := '70';
10163
10164 IF (l_debug = 1) THEN
10165 print_debug('Successfully retrieved data from cursor');
10166 print_debug('Organization ID: => ' || l_organization_id);
10167 print_debug('Trip Stop ID: ====> ' || l_trip_stop_id);
10168 print_debug('Carrier ID: ======> ' || l_carrier_id);
10169 print_debug('Expected Date: ===> ' || TO_CHAR(l_expected_date, 'DD-MON-YYYY HH24:MI:SS'));
10170 END IF;
10171 l_progress := '80';
10172
10173 -- If a trip stop is present, query for dock appointments associated with the trip stop.
10174 -- If a trip stop is passed to this API, the start and end date parameters are ignored
10175 -- and the first dock appointment associated with the trip stop is returned. This will
10176 -- return at most one dock appointment in the output variable table x_dock_appt_list.
10177 -- CORRECTION TO THE ABOVE:
10178 -- The dock appointment API, even if a trip stop is passed does take the p_start_date into
10179 -- account. Since dock appointment statuses do not exist yet, this API will only look for
10180 -- dock appointments tied to the trip stop that are >= p_start_date. This is done so we do
10181 -- not pick up older dock appointments that have already passed. (Though that should not be
10182 -- an issue for dock appointments tied to trip stops). Thus use SYSDATE for p_start_date
10183 -- instead of l_expected_date.
10184 -- {{
10185 -- Test for cases both with and without a dock appointment tied to an existing trip stop. }}
10186 IF (l_trip_stop_id IS NOT NULL) THEN
10187 IF (l_debug = 1) THEN
10188 print_debug('Call the get_dock_appointment_range API for a trip stop');
10189 END IF;
10190 l_progress := '90';
10191
10192 wms_dock_appointments_pub.get_dock_appointment_range
10193 (p_api_version => 1.0,
10194 p_init_msg_list => fnd_api.g_false,
10195 x_return_status => x_return_status,
10196 x_msg_count => x_msg_count,
10197 x_msg_data => x_msg_data,
10198 x_dock_appt_list => l_dock_appt_list,
10199 p_organization_id => l_organization_id,
10200 p_start_date => Trunc(Sysdate), --l_expected_date,
10201 p_end_date => l_expected_date,
10202 p_appointment_type => p_supply_or_demand,
10203 p_supplier_id => NULL,
10204 p_supplier_site_id => NULL,
10205 p_customer_id => NULL,
10206 p_customer_site_id => NULL,
10207 p_carrier_code => NULL,
10208 p_carrier_id => NULL,
10209 p_trip_stop_id => l_trip_stop_id,
10210 p_waybill_number => NULL,
10211 p_bill_of_lading => NULL,
10212 p_master_bol => NULL);
10213
10214 IF (l_debug = 1) THEN
10215 print_debug('Finished calling the get_dock_appointment_range API');
10216 END IF;
10217 l_progress := '100';
10218
10219 -- Check to see if the get_dock_appointment_range API returned successfully
10220 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
10221 IF (l_debug = 1) THEN
10222 print_debug('Success returned from get_dock_appointment_range API');
10223 END IF;
10224 ELSE
10225 IF (l_debug = 1) THEN
10226 print_debug('Failure returned from get_dock_appointment_range API');
10227 END IF;
10228 x_return_status := fnd_api.g_ret_sts_success;
10229 -- do not thrown an error but just go to the next way to calculate time
10230 --FND_MESSAGE.SET_NAME('WMS', 'WMS_TD_MO_ERROR');
10231 --FND_MSG_PUB.ADD;
10232 --RAISE fnd_api.g_exc_error;
10233 END IF;
10234 l_progress := '110';
10235 END IF;
10236
10237 -- If a dock appointment has not been found yet and a carrier ID is present,
10238 -- query for dock appointments associated with the carrier. For the start and end dates,
10239 -- we will use the date on the variable l_expected_date (sans time information if present)
10240 -- along with the times of 12AM midnight and 11:59:59PM as the start and end date.
10241 -- This will return a list of valid dock appointments (multiple appointments are possible).
10242 -- {{
10243 -- Test for cases both with and without a dock appointment tied to an existing carrier. }}
10244 -- {{
10245 -- Test for cases where multiple dock appointments exist for a given carrier. }}
10246 IF (l_dock_appt_list.COUNT = 0 AND l_carrier_id IS NOT NULL) THEN
10247 IF (l_debug = 1) THEN
10248 print_debug('Call the get_dock_appointment_range API for a carrier');
10249 END IF;
10250 l_progress := '120';
10251
10252 wms_dock_appointments_pub.get_dock_appointment_range
10253 (p_api_version => 1.0,
10254 p_init_msg_list => fnd_api.g_false,
10255 x_return_status => x_return_status,
10256 x_msg_count => x_msg_count,
10257 x_msg_data => x_msg_data,
10258 x_dock_appt_list => l_dock_appt_list,
10259 p_organization_id => l_organization_id,
10260 p_start_date => TRUNC(l_expected_date),
10261 p_end_date => TO_DATE(TO_CHAR(TRUNC(l_expected_date), 'DD-MON-YYYY') ||
10262 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS'),
10263 p_appointment_type => p_supply_or_demand,
10264 p_supplier_id => NULL,
10265 p_supplier_site_id => NULL,
10266 p_customer_id => NULL,
10267 p_customer_site_id => NULL,
10268 p_carrier_code => NULL,
10269 p_carrier_id => l_carrier_id,
10270 p_trip_stop_id => NULL,
10271 p_waybill_number => NULL,
10272 p_bill_of_lading => NULL,
10273 p_master_bol => NULL);
10274
10275 IF (l_debug = 1) THEN
10276 print_debug('Finished calling the get_dock_appointment_range API');
10277 END IF;
10278 l_progress := '130';
10279
10280 -- Check to see if the get_dock_appointment_range API returned successfully
10281 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
10282 IF (l_debug = 1) THEN
10283 print_debug('Success returned from get_dock_appointment_range API');
10284 END IF;
10285 ELSE
10286 IF (l_debug = 1) THEN
10287 print_debug('Failure returned from get_dock_appointment_range API');
10288 END IF;
10289 x_return_status := fnd_api.g_ret_sts_success;
10290 -- do not thrown an error but just go to the next way to calculate time
10291 --FND_MESSAGE.SET_NAME('WMS', 'WMS_TD_MO_ERROR');
10292 --FND_MSG_PUB.ADD;
10293 --RAISE fnd_api.g_exc_error;
10294 END IF;
10295 l_progress := '140';
10296 END IF;
10297
10298 IF (l_debug = 1) THEN
10299 print_debug('Number of dock appointments found: ' || l_dock_appt_list.COUNT);
10300 END IF;
10301 l_progress := '150';
10302
10303 -- See if any dock appointments were found. If multiple dock appointments exist,
10304 -- get the one closest to the expected receipt/ship date
10305 IF (l_dock_appt_list.COUNT > 0) THEN
10306 -- Loop through all available dock appointments
10307 -- {{
10308 -- For multiple dock appointments, make sure the 'closest' one is correctly selected. }}
10309 FOR i IN l_dock_appt_list.FIRST .. l_dock_appt_list.LAST LOOP
10310 IF (i = l_dock_appt_list.FIRST) THEN
10311 -- First dock appointment found
10312 l_dock_start_time := l_dock_appt_list(i).start_time;
10313 l_dock_end_time := l_dock_appt_list(i).end_time;
10314 l_dock_mean_time := (l_dock_end_time - l_dock_start_time)/2 + l_dock_start_time;
10315
10316 -- Based on the dock schedule method (if present) calculate a single
10317 -- dock appointment time based on the start and end time. If multiple dock
10318 -- appointments exist, this value will be compared with the expected receipt/ship
10319 -- date (non-dock appointment) and the closest dock appointment time will be used.
10320 IF (l_dock_schedule_method IS NULL OR l_dock_schedule_method = G_APPT_MEAN_TIME) THEN
10321 l_dock_appt_time := l_dock_mean_time;
10322 ELSIF (l_dock_schedule_method = G_APPT_START_TIME) THEN
10323 l_dock_appt_time := l_dock_start_time;
10324 ELSIF (l_dock_schedule_method = G_APPT_END_TIME) THEN
10325 l_dock_appt_time := l_dock_end_time;
10326 END IF;
10327 IF (l_debug = 1) THEN
10328 print_debug('Current closest dock appt time: ' ||
10329 TO_CHAR(l_dock_appt_time, 'DD-MON-YYYY HH24:MI:SS'));
10330 END IF;
10331 l_progress := '160';
10332 ELSE
10333 -- Calculate the current dock appointment time and compare it to the current
10334 -- best time to see if this one is even closer to the expected receipt/ship date.
10335 IF (l_dock_schedule_method IS NULL OR l_dock_schedule_method = G_APPT_MEAN_TIME) THEN
10336 l_current_dock_appt_time := (l_dock_appt_list(i).end_time -
10337 l_dock_appt_list(i).start_time)/2
10338 + l_dock_appt_list(i).start_time;
10339 ELSIF (l_dock_schedule_method = G_APPT_START_TIME) THEN
10340 l_current_dock_appt_time := l_dock_appt_list(i).start_time;
10341 ELSIF (l_dock_schedule_method = G_APPT_END_TIME) THEN
10342 l_current_dock_appt_time := l_dock_appt_list(i).end_time;
10343 END IF;
10344
10345 -- If the dock appointment time is closer to the expected receipt/ship date compared
10346 -- to the current best time, update the best dock appointment variables to
10347 -- point to the current dock appointment.
10348 IF (abs(l_current_dock_appt_time - l_expected_date) <
10349 abs(l_dock_appt_time - l_expected_date)) THEN
10350 l_dock_start_time := l_dock_appt_list(i).start_time;
10351 l_dock_end_time := l_dock_appt_list(i).end_time;
10352 l_dock_mean_time := (l_dock_end_time - l_dock_start_time)/2 + l_dock_start_time;
10353 l_dock_appt_time := l_current_dock_appt_time;
10354 IF (l_debug = 1) THEN
10355 print_debug('Closer dock appt time found: ' ||
10356 TO_CHAR(l_dock_appt_time, 'DD-MON-YYYY HH24:MI:SS'));
10357 END IF;
10358 END IF;
10359 l_progress := '170';
10360
10361 END IF;
10362 END LOOP;
10363
10364 IF (l_debug = 1) THEN
10365 print_debug('Closest dock appt start time: => ' ||
10366 TO_CHAR(l_dock_start_time, 'DD-MON-YYYY HH24:MI:SS'));
10367 print_debug('Closest dock appt end time: ===> ' ||
10368 TO_CHAR(l_dock_end_time, 'DD-MON-YYYY HH24:MI:SS'));
10369 print_debug('Closest dock appt mean time: ==> ' ||
10370 TO_CHAR(l_dock_mean_time, 'DD-MON-YYYY HH24:MI:SS'));
10371 print_debug('Closest dock appt time: =======> ' ||
10372 TO_CHAR(l_dock_appt_time, 'DD-MON-YYYY HH24:MI:SS'));
10373 END IF;
10374 l_progress := '180';
10375
10376 -- We have now found the closest dock appointment time to the expected time
10377 x_dock_start_time := l_dock_start_time;
10378 x_dock_mean_time := l_dock_mean_time;
10379 x_dock_end_time := l_dock_end_time;
10380 IF (p_crossdock_criterion_id IS NOT NULL) THEN
10381 x_expected_time := l_dock_appt_time;
10382 ELSE
10383 -- If a crossdock criterion is not passed, let the caller decide how to determine
10384 -- a single expected time based on the dock appointment start and end time.
10385 x_expected_time := NULL;
10386 END IF;
10387 l_progress := '190';
10388 END IF; -- End of dock appointments found
10389
10390 -- If a dock appointment was not found, just use the expected receipt/ship date
10391 -- retrieved from the cursors as the expected time.
10392 -- {{
10393 -- Ensure that the expected time calculated not based on dock appointments is returned
10394 -- in case no dock appointments exist for the inputted demand/supply line. }}
10395 IF (l_dock_appt_list.COUNT = 0) THEN
10396 x_dock_start_time := NULL;
10397 x_dock_mean_time := NULL;
10398 x_dock_end_time := NULL;
10399 x_expected_time := l_expected_date;
10400 END IF;
10401 l_progress := '200';
10402
10403 IF (l_debug = 1) THEN
10404 print_debug('Dock start time: => ' || TO_CHAR(x_dock_start_time, 'DD-MON-YYYY HH24:MI:SS'));
10405 print_debug('Dock mean time: ==> ' || TO_CHAR(x_dock_mean_time, 'DD-MON-YYYY HH24:MI:SS'));
10406 print_debug('Dock end time: ===> ' || TO_CHAR(x_dock_end_time, 'DD-MON-YYYY HH24:MI:SS'));
10407 print_debug('Expected time: ===> ' || TO_CHAR(x_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
10408 END IF;
10409
10410 <<custom_logic_used>>
10411 IF (l_debug = 1) THEN
10412 print_debug('***End of Get_Expected_Time***');
10413 END IF;
10414
10415 EXCEPTION
10416 WHEN FND_API.G_EXC_ERROR THEN
10417 ROLLBACK TO Get_Expected_Time_sp;
10418 x_return_status := fnd_api.g_ret_sts_error;
10419 fnd_msg_pub.count_and_get(p_count => x_msg_count,
10420 p_data => x_msg_data);
10421 IF (l_debug = 1) THEN
10422 print_debug('Exiting Get_Expected_Time - Execution error: ' ||
10423 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
10424 END IF;
10425
10426 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
10427 ROLLBACK TO Get_Expected_Time_sp;
10428 x_return_status := fnd_api.g_ret_sts_unexp_error;
10429 fnd_msg_pub.count_and_get(p_count => x_msg_count,
10430 p_data => x_msg_data);
10431 IF (l_debug = 1) THEN
10432 print_debug('Exiting Get_Expected_Time - Unexpected error: ' ||
10433 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
10434 END IF;
10435
10436 WHEN OTHERS THEN
10437 ROLLBACK TO Get_Expected_Time_sp;
10438 x_return_status := fnd_api.g_ret_sts_unexp_error;
10439 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
10440 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
10441 END IF;
10442 fnd_msg_pub.count_and_get(p_count => x_msg_count,
10443 p_data => x_msg_data);
10444 IF (l_debug = 1) THEN
10445 print_debug('Exiting Get_Expected_Time - Others exception: ' ||
10446 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
10447 END IF;
10448
10449 END Get_Expected_Time;
10450 -- {{ }}
10451 -- {{******************** End Get_Expected_Time ********************}}
10452 -- {{ }}
10453
10454
10455 -- {{ }}
10456 -- {{******************** Procedure Get_Expected_Delivery_Time ********************}}
10457 PROCEDURE Get_Expected_Delivery_Time
10458 (p_delivery_id IN NUMBER,
10459 p_crossdock_criterion_id IN NUMBER,
10460 x_return_status OUT NOCOPY VARCHAR2,
10461 x_msg_count OUT NOCOPY NUMBER,
10462 x_msg_data OUT NOCOPY VARCHAR2,
10463 x_dock_appointment_id OUT NOCOPY NUMBER,
10464 x_dock_start_time OUT NOCOPY DATE,
10465 x_dock_end_time OUT NOCOPY DATE,
10466 x_expected_time OUT NOCOPY DATE)
10467 IS
10468 l_api_name CONSTANT VARCHAR2(30) := 'Get_Expected_Delivery_Time';
10469 l_progress VARCHAR2(10);
10470 l_debug NUMBER := NVL(FND_PROFILE.VALUE('INV_DEBUG_TRACE'),0);
10471
10472 -- This variable is used to indicate if the custom API was used to determine
10473 -- the expected time values.
10474 l_api_is_implemented BOOLEAN;
10475
10476 -- Variable to store the dock schedule method for outbound demand lines
10477 -- from the crossdock criterion entered
10478 l_dock_schedule_method NUMBER;
10479
10480 -- Cursor to retrieve the trip stop id, carrier id, min expected ship date and max
10481 -- expected ship date (without considering dock appointments) for a given delivery.
10482 -- The carrier and expected ship dates come from the set of outbound WDD/OOL records
10483 -- already assigned to the delivery.
10484 CURSOR delivery_rec_cursor IS
10485 SELECT wnd.organization_id AS organization_id,
10486 wts.stop_id AS trip_stop_id,
10487 MIN(NVL(wt.carrier_id,
10488 NVL(NVL(wnd.carrier_id, wcs_wnd.carrier_id),
10489 NVL(NVL(wdd.carrier_id, wcs_wdd.carrier_id),
10490 NVL(wc_ool.carrier_id, wcs_ool.carrier_id))))) AS carrier_id,
10491 MIN(NVL(wts.planned_departure_date,
10492 NVL(wdd.date_scheduled,
10493 NVL(ool.schedule_ship_date, ool.promise_date)))) AS min_expected_ship_date,
10494 MAX(NVL(wts.planned_departure_date,
10495 NVL(wdd.date_scheduled,
10496 NVL(ool.schedule_ship_date, ool.promise_date)))) AS max_expected_ship_date
10497 FROM wsh_new_deliveries wnd, wsh_delivery_details wdd, wsh_delivery_assignments_v wda,
10498 wsh_delivery_legs wdl, wsh_trip_stops wts, wsh_trips wt, oe_order_lines_all ool,
10499 wsh_carrier_services wcs_wnd, wsh_carrier_services wcs_wdd,
10500 wsh_carrier_services wcs_ool, wsh_carriers wc_ool
10501 WHERE wnd.delivery_id = p_delivery_id
10502 AND wnd.shipment_direction = 'O'
10503 AND wnd.delivery_id = wda.delivery_id (+)
10504 AND wda.delivery_detail_id = wdd.delivery_detail_id (+)
10505 AND wdd.source_line_id = ool.line_id (+)
10506 AND wnd.delivery_id = wdl.delivery_id (+)
10507 AND (wdl.sequence_number IS NULL OR
10508 wdl.sequence_number = (SELECT MIN(sequence_number)
10509 FROM wsh_delivery_legs wdl_first_leg
10510 WHERE wdl_first_leg.delivery_id = wdl.delivery_id))
10511 AND wdl.pick_up_stop_id = wts.stop_id (+)
10512 AND wts.trip_id = wt.trip_id (+)
10513 AND wnd.ship_method_code = wcs_wnd.ship_method_code (+)
10514 AND wdd.ship_method_code = wcs_wdd.ship_method_code (+)
10515 AND ool.shipping_method_code = wcs_ool.ship_method_code (+)
10516 AND ool.freight_carrier_code = wc_ool.freight_code (+)
10517 GROUP BY wnd.organization_id, wnd.delivery_id, wts.stop_id;
10518
10519 -- Variables to retrieve the values from the delivery record cursor
10520 l_organization_id NUMBER;
10521 l_trip_stop_id NUMBER;
10522 l_carrier_id NUMBER;
10523 l_min_expected_date DATE;
10524 l_max_expected_date DATE;
10525 l_null_dates_retrieved BOOLEAN;
10526
10527 -- Variables for calling the dock appointment API
10528 l_dock_appt_list WMS_DOCK_APPOINTMENTS_PUB.dock_appt_tb_tp;
10529
10530 -- Variables to loop through all dock appointments returned to find the one
10531 -- closest to the expected receipt/ship time.
10532 l_dock_appointment_id NUMBER;
10533 l_dock_start_time DATE;
10534 l_dock_end_time DATE;
10535 l_dock_appt_time DATE;
10536 l_current_dock_appt_time DATE;
10537
10538 BEGIN
10539 IF (l_debug = 1) THEN
10540 print_debug('***Calling Get_Expected_Delivery_Time with the following parameters***');
10541 print_debug('Package Version: ==========> ' || g_pkg_version);
10542 print_debug('p_delivery_id: ============> ' || p_delivery_id);
10543 print_debug('p_crossdock_criterion_id: => ' || p_crossdock_criterion_id);
10544 END IF;
10545
10546 -- Set the savepoint
10547 SAVEPOINT Get_Expected_Delivery_Time_sp;
10548 l_progress := '10';
10549
10550 -- Initialize message list to clear any existing messages
10551 fnd_msg_pub.initialize;
10552 l_progress := '20';
10553
10554 -- Initialize API return status to success
10555 x_return_status := fnd_api.g_ret_sts_success;
10556 l_progress := '30';
10557
10558 -- Query and cache the crossdock criterion record
10559 IF (NOT set_crossdock_criteria(p_crossdock_criterion_id)) THEN
10560 IF (l_debug = 1) THEN
10561 print_debug('Unable to set the crossdock criterion: ' || p_crossdock_criterion_id);
10562 RAISE fnd_api.g_exc_unexpected_error;
10563 END IF;
10564 END IF;
10565 l_progress := '40';
10566
10567 -- No need to do the following validation since this can also be called for MOL lines that
10568 -- were Planned Crossdocked so the crossdock criterion there is of 'Planned' type.
10569 -- Validate that the crossdock criteria is of 'Opportunistic' type.
10570 /*IF (g_crossdock_criteria_tb(p_crossdock_criterion_id).criterion_type <> G_CRT_TYPE_OPP) THEN
10571 IF (l_debug = 1) THEN
10572 print_debug('Invalid crossdock criterion type: ' ||
10573 g_crossdock_criteria_tb(p_crossdock_criterion_id).criterion_type);
10574 END IF;
10575 RAISE fnd_api.g_exc_unexpected_error;
10576 END IF;*/
10577 l_progress := '50';
10578
10579 -- Get the dock schedule method from the crossdock criterion
10580 -- {{
10581 -- make sure a valid dock schedule method is retrieved from the crossdock criterion. }}
10582 l_dock_schedule_method :=
10583 g_crossdock_criteria_tb(p_crossdock_criterion_id).demand_schedule_method;
10584 IF (l_debug = 1) THEN
10585 print_debug('Dock Schedule Method: ' || l_dock_schedule_method);
10586 END IF;
10587 l_progress := '60';
10588 -- End of validations and initializations
10589
10590
10591 -- Call the custom logic first to see if the API is implemented or not
10592 WMS_XDOCK_CUSTOM_APIS_PUB.Get_Expected_Delivery_Time
10593 (p_delivery_id => p_delivery_id,
10594 p_crossdock_criterion_id => p_crossdock_criterion_id,
10595 p_dock_schedule_method => l_dock_schedule_method,
10596 x_return_status => x_return_status,
10597 x_msg_count => x_msg_count,
10598 x_msg_data => x_msg_data,
10599 x_api_is_implemented => l_api_is_implemented,
10600 x_dock_appointment_id => x_dock_appointment_id,
10601 x_dock_start_time => x_dock_start_time,
10602 x_dock_end_time => x_dock_end_time,
10603 x_expected_time => x_expected_time);
10604
10605 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
10606 IF (l_debug = 1) THEN
10607 print_debug('Success returned from Custom Get_Expected_Delivery_Time API');
10608 END IF;
10609 ELSE
10610 IF (l_debug = 1) THEN
10611 print_debug('Failure returned from Custom Get_Expected_Delivery_Time API');
10612 END IF;
10613 RAISE fnd_api.g_exc_error;
10614 END IF;
10615
10616 -- If the custom API is implemented, just use the values retrieved from there.
10617 -- Skip all further processing and logic in this API.
10618 IF (l_api_is_implemented) THEN
10619 IF (l_debug = 1) THEN
10620 print_debug('Custom API is implemented so using custom logic to get expected time');
10621 END IF;
10622 GOTO custom_logic_used;
10623 ELSE
10624 IF (l_debug = 1) THEN
10625 print_debug('Custom API is not implemented so using default logic to get expected time');
10626 END IF;
10627 END IF;
10628
10629 -- Open the delivery record cursor to retrieve the trip stop, carrier and
10630 -- non-dock appointment derived min and max expected ship times.
10631 -- {{
10632 -- Make sure API errors out properly if delivery entered is invalid. }}
10633 OPEN delivery_rec_cursor;
10634 FETCH delivery_rec_cursor INTO l_organization_id, l_trip_stop_id, l_carrier_id,
10635 l_min_expected_date, l_max_expected_date;
10636 IF (delivery_rec_cursor%NOTFOUND) THEN
10637 IF (l_debug = 1) THEN
10638 print_debug('Delivery cursor did not return any records!');
10639 END IF;
10640 CLOSE delivery_rec_cursor;
10641 RAISE fnd_api.g_exc_unexpected_error;
10642 END IF;
10643 CLOSE delivery_rec_cursor;
10644 l_progress := '70';
10645
10646 IF (l_debug = 1) THEN
10647 print_debug('Successfully retrieved data from cursor');
10648 print_debug('Organization ID: ===> ' || l_organization_id);
10649 print_debug('Trip Stop ID: ======> ' || l_trip_stop_id);
10650 print_debug('Carrier ID: ========> ' || l_carrier_id);
10651 print_debug('Min Expected Date: => ' || TO_CHAR(l_min_expected_date, 'DD-MON-YYYY HH24:MI:SS'));
10652 print_debug('Max Expected Date: => ' || TO_CHAR(l_max_expected_date, 'DD-MON-YYYY HH24:MI:SS'));
10653 END IF;
10654 l_progress := '80';
10655
10656 -- If values were not returned for the MIN/MAX expected ship dates, just use SYSDATE
10657 -- with a time of 12:00AM for the start time and 11:59PM for the end time.
10658 -- Either both or none of the expected ship dates should be NULL. Set a BOOLEAN variable
10659 -- to indicate if NULL date values were retrieved from the cursor or not. This can occur
10660 -- if no WDD records are assigned to the delivery.
10661 -- {{
10662 -- Test for deliveries that do not have any WDD records assigned to them yet. }}
10663 -- {{
10664 -- For deliveries with WDD records already assigned to them, make sure the min and max
10665 -- expected dates are calculated correctly. }}
10666 IF (l_min_expected_date IS NULL) THEN
10667 l_null_dates_retrieved := TRUE;
10668 l_min_expected_date := TRUNC(SYSDATE);
10669 l_max_expected_date := TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'DD-MON-YYYY') ||
10670 ' 23:59:59', 'DD-MON-YYYY HH24:MI:SS');
10671 IF (l_debug = 1) THEN
10672 print_debug('Set the MIN/MAX expected dates to use SYSDATE due to NULL values');
10673 END IF;
10674 ELSE
10675 l_null_dates_retrieved := FALSE;
10676 END IF;
10677 l_progress := '85';
10678
10679 -- If a trip stop is present, query for dock appointments associated with the trip stop.
10680 -- If a trip stop is passed to this API, the start and end date parameters are ignored
10681 -- and the first dock appointment associated with the trip stop is returned. This will
10682 -- return at most one dock appointment in the output variable table x_dock_appt_list.
10683 -- CORRECTION TO THE ABOVE:
10684 -- The dock appointment API, even if a trip stop is passed does take the p_start_date into
10685 -- account. Since dock appointment statuses do not exist yet, this API will only look for
10686 -- dock appointments tied to the trip stop that are >= p_start_date. This is done so we do
10687 -- not pick up older dock appointments that have already passed. (Though that should not be
10688 -- an issue for dock appointments tied to trip stops). Thus use SYSDATE for p_start_date
10689 -- instead of l_min_expected_date.
10690 -- {{
10691 -- Get the expected time both with and without a trip stop tied to the delivery. }}
10692 IF (l_trip_stop_id IS NOT NULL) THEN
10693 IF (l_debug = 1) THEN
10694 print_debug('Call the get_dock_appointment_range API for a trip stop');
10695 END IF;
10696 l_progress := '90';
10697
10698 wms_dock_appointments_pub.get_dock_appointment_range
10699 (p_api_version => 1.0,
10700 p_init_msg_list => fnd_api.g_false,
10701 x_return_status => x_return_status,
10702 x_msg_count => x_msg_count,
10703 x_msg_data => x_msg_data,
10704 x_dock_appt_list => l_dock_appt_list,
10705 p_organization_id => l_organization_id,
10706 p_start_date => Trunc(Sysdate), --l_min_expected_date,
10707 p_end_date => l_max_expected_date,
10708 p_appointment_type => G_SRC_TYPE_DEM, -- Outbound Demand type
10709 p_supplier_id => NULL,
10710 p_supplier_site_id => NULL,
10711 p_customer_id => NULL,
10712 p_customer_site_id => NULL,
10713 p_carrier_code => NULL,
10714 p_carrier_id => NULL,
10715 p_trip_stop_id => l_trip_stop_id,
10716 p_waybill_number => NULL,
10717 p_bill_of_lading => NULL,
10718 p_master_bol => NULL);
10719
10720 IF (l_debug = 1) THEN
10721 print_debug('Finished calling the get_dock_appointment_range API');
10722 END IF;
10723 l_progress := '100';
10724
10725 -- Check to see if the get_dock_appointment_range API returned successfully
10726 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
10727 IF (l_debug = 1) THEN
10728 print_debug('Success returned from get_dock_appointment_range API');
10729 END IF;
10730 ELSE
10731 IF (l_debug = 1) THEN
10732 print_debug('Failure returned from get_dock_appointment_range API');
10733 END IF;
10734 x_return_status := fnd_api.g_ret_sts_success;
10735 -- do not thrown an error but just go to the next way to calculate time
10736 --FND_MESSAGE.SET_NAME('WMS', 'WMS_TD_MO_ERROR');
10737 --FND_MSG_PUB.ADD;
10738 --RAISE fnd_api.g_exc_error;
10739 END IF;
10740 l_progress := '110';
10741 END IF;
10742
10743 -- If a dock appointment has not been found yet and a carrier ID is present,
10744 -- query for dock appointments associated with the carrier. For the start and end dates,
10745 -- use the MIN and MAX expected ship dates retrieved from the delivery record cursor.
10746 -- This will return a list of valid dock appointments (multiple appointments are possible).
10747 -- {{
10748 -- Get the expected delivery time both with and without a carrier tied to the delivery. }}
10749 -- {{
10750 -- Test for cases where multiple dock appointments are tied to the carrier. }}
10751 IF (l_dock_appt_list.COUNT = 0 AND l_carrier_id IS NOT NULL) THEN
10752 IF (l_debug = 1) THEN
10753 print_debug('Call the get_dock_appointment_range API for a carrier');
10754 END IF;
10755 l_progress := '120';
10756
10757 wms_dock_appointments_pub.get_dock_appointment_range
10758 (p_api_version => 1.0,
10759 p_init_msg_list => fnd_api.g_false,
10760 x_return_status => x_return_status,
10761 x_msg_count => x_msg_count,
10762 x_msg_data => x_msg_data,
10763 x_dock_appt_list => l_dock_appt_list,
10764 p_organization_id => l_organization_id,
10765 p_start_date => l_min_expected_date,
10766 p_end_date => l_max_expected_date,
10767 p_appointment_type => G_SRC_TYPE_DEM, -- Outbound Demand type
10768 p_supplier_id => NULL,
10769 p_supplier_site_id => NULL,
10770 p_customer_id => NULL,
10771 p_customer_site_id => NULL,
10772 p_carrier_code => NULL,
10773 p_carrier_id => l_carrier_id,
10774 p_trip_stop_id => NULL,
10775 p_waybill_number => NULL,
10776 p_bill_of_lading => NULL,
10777 p_master_bol => NULL);
10778
10779 IF (l_debug = 1) THEN
10780 print_debug('Finished calling the get_dock_appointment_range API');
10781 END IF;
10782 l_progress := '130';
10783
10784 -- Check to see if the get_dock_appointment_range API returned successfully
10785 IF (x_return_status = fnd_api.g_ret_sts_success) THEN
10786 IF (l_debug = 1) THEN
10787 print_debug('Success returned from get_dock_appointment_range API');
10788 END IF;
10789 ELSE
10790 IF (l_debug = 1) THEN
10791 print_debug('Failure returned from get_dock_appointment_range API');
10792 END IF;
10793 x_return_status := fnd_api.g_ret_sts_success;
10794 -- do not thrown an error but just go to the next way to calculate time
10795 --FND_MESSAGE.SET_NAME('WMS', 'WMS_TD_MO_ERROR');
10796 --FND_MSG_PUB.ADD;
10797 --RAISE fnd_api.g_exc_error;
10798 END IF;
10799 l_progress := '140';
10800 END IF;
10801
10802 IF (l_debug = 1) THEN
10803 print_debug('Number of dock appointments found: ' || l_dock_appt_list.COUNT);
10804 END IF;
10805 l_progress := '150';
10806
10807 -- See if any dock appointments were found. If multiple dock appointments exist,
10808 -- get the one closest to the MAX expected ship date. Since multiple WDD records could be
10809 -- assigned to the delivery, the latest expected ship date from that set is the limiting
10810 -- factor in when the delivery can be shipped out.
10811 IF (l_dock_appt_list.COUNT > 0) THEN
10812 -- Loop through all available dock appointments
10813 -- {{
10814 -- For multiple dock appointments, make sure the 'closest' one is selected. }}
10815 FOR i IN l_dock_appt_list.FIRST .. l_dock_appt_list.LAST LOOP
10816 IF (i = l_dock_appt_list.FIRST) THEN
10817 -- First dock appointment found
10818 l_dock_appointment_id := l_dock_appt_list(i).dock_appointment_id;
10819 l_dock_start_time := l_dock_appt_list(i).start_time;
10820 l_dock_end_time := l_dock_appt_list(i).end_time;
10821
10822 -- Based on the dock schedule method (if present) calculate a single
10823 -- dock appointment time based on the start and end time. If multiple dock
10824 -- appointments exist, this value will be compared with the MAX expected ship
10825 -- date (non-dock appointment) and the closest dock appointment time will be used.
10826 IF (l_dock_schedule_method IS NULL OR l_dock_schedule_method = G_APPT_MEAN_TIME) THEN
10827 l_dock_appt_time := (l_dock_end_time - l_dock_start_time)/2 + l_dock_start_time;
10828 ELSIF (l_dock_schedule_method = G_APPT_START_TIME) THEN
10829 l_dock_appt_time := l_dock_start_time;
10830 ELSIF (l_dock_schedule_method = G_APPT_END_TIME) THEN
10831 l_dock_appt_time := l_dock_end_time;
10832 END IF;
10833 IF (l_debug = 1) THEN
10834 print_debug('Current closest dock appt time: ' ||
10835 TO_CHAR(l_dock_appt_time, 'DD-MON-YYYY HH24:MI:SS'));
10836 END IF;
10837 l_progress := '160';
10838 ELSE
10839 -- Calculate the current dock appointment time and compare it to the current
10840 -- best time to see if this one is even closer to the MAX expected ship date.
10841 IF (l_dock_schedule_method IS NULL OR l_dock_schedule_method = G_APPT_MEAN_TIME) THEN
10842 l_current_dock_appt_time := (l_dock_appt_list(i).end_time -
10843 l_dock_appt_list(i).start_time)/2
10844 + l_dock_appt_list(i).start_time;
10845 ELSIF (l_dock_schedule_method = G_APPT_START_TIME) THEN
10846 l_current_dock_appt_time := l_dock_appt_list(i).start_time;
10847 ELSIF (l_dock_schedule_method = G_APPT_END_TIME) THEN
10848 l_current_dock_appt_time := l_dock_appt_list(i).end_time;
10849 END IF;
10850
10851 -- If the dock appointment time is closer to the MAX expected ship date compared
10852 -- to the current best time, update the best dock appointment variables to
10853 -- point to the current dock appointment.
10854 IF (abs(l_current_dock_appt_time - l_max_expected_date) <
10855 abs(l_dock_appt_time - l_max_expected_date)) THEN
10856 l_dock_appointment_id := l_dock_appt_list(i).dock_appointment_id;
10857 l_dock_start_time := l_dock_appt_list(i).start_time;
10858 l_dock_end_time := l_dock_appt_list(i).end_time;
10859 l_dock_appt_time := l_current_dock_appt_time;
10860 END IF;
10861 IF (l_debug = 1) THEN
10862 print_debug('Current closest dock appt time: ' ||
10863 TO_CHAR(l_dock_appt_time, 'DD-MON-YYYY HH24:MI:SS'));
10864 END IF;
10865 l_progress := '170';
10866 END IF;
10867 END LOOP;
10868
10869 IF (l_debug = 1) THEN
10870 print_debug('Closest dock appt ID: =========> ' || l_dock_appointment_id);
10871 print_debug('Closest dock appt start time: => ' ||
10872 TO_CHAR(l_dock_start_time, 'DD-MON-YYYY HH24:MI:SS'));
10873 print_debug('Closest dock appt end time: ===> ' ||
10874 TO_CHAR(l_dock_end_time, 'DD-MON-YYYY HH24:MI:SS'));
10875 print_debug('Closest dock appt time: =======> ' ||
10876 TO_CHAR(l_dock_appt_time, 'DD-MON-YYYY HH24:MI:SS'));
10877 END IF;
10878 l_progress := '180';
10879
10880 -- We have now found the closest dock appointment time to the MAX expected ship time
10881 x_dock_appointment_id := l_dock_appointment_id;
10882 x_dock_start_time := l_dock_start_time;
10883 x_dock_end_time := l_dock_end_time;
10884 x_expected_time := l_dock_appt_time;
10885 l_progress := '190';
10886
10887 END IF; -- End of dock appointments found
10888
10889 -- If a dock appointment was not found, just use the MIN and MAX expected ship date
10890 -- retrieved from the cursors as the dock start and end times. The expected time and
10891 -- dock appointment ID output variables will be NULL so the caller knows a dock appointment
10892 -- was not found. If NULL date values were retrieved from the cursor, this means that no
10893 -- WDD records are assigned to the delivery. In that case, return NULL values for the dock
10894 -- start and end time.
10895 -- {{
10896 -- For cases where no dock appointments exist, make sure the min and max expected dates
10897 -- from the WDD records assigned to the delivery are returned. }}
10898 -- {{
10899 -- For deliveries without dock appointments and no WDD records assigned to them, the
10900 -- expected times returned should all be null. }}
10901 IF (l_dock_appt_list.COUNT = 0) THEN
10902 x_dock_appointment_id := NULL;
10903 IF (l_null_dates_retrieved) THEN
10904 x_dock_start_time := NULL;
10905 x_dock_end_time := NULL;
10906 ELSE
10907 x_dock_start_time := l_min_expected_date;
10908 x_dock_end_time := l_max_expected_date;
10909 END IF;
10910 x_expected_time := NULL;
10911 END IF;
10912 l_progress := '200';
10913
10914 IF (l_debug = 1) THEN
10915 print_debug('Dock Appointment ID: => ' || x_dock_appointment_id);
10916 print_debug('Dock start time: =====> ' || TO_CHAR(x_dock_start_time, 'DD-MON-YYYY HH24:MI:SS'));
10917 print_debug('Dock end time: =======> ' || TO_CHAR(x_dock_end_time, 'DD-MON-YYYY HH24:MI:SS'));
10918 print_debug('Expected time: =======> ' || TO_CHAR(x_expected_time, 'DD-MON-YYYY HH24:MI:SS'));
10919 END IF;
10920
10921 <<custom_logic_used>>
10922 IF (l_debug = 1) THEN
10923 print_debug('***End of Get_Expected_Delivery_Time***');
10924 END IF;
10925
10926 EXCEPTION
10927 WHEN FND_API.G_EXC_ERROR THEN
10928 ROLLBACK TO Get_Expected_Delivery_Time_sp;
10929 x_return_status := fnd_api.g_ret_sts_error;
10930 fnd_msg_pub.count_and_get(p_count => x_msg_count,
10931 p_data => x_msg_data);
10932 IF (l_debug = 1) THEN
10933 print_debug('Exiting Get_Expected_Delivery_Time - Execution error: ' ||
10934 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
10935 END IF;
10936
10937 WHEN FND_API.G_EXC_UNEXPECTED_ERROR THEN
10938 ROLLBACK TO Get_Expected_Delivery_Time_sp;
10939 x_return_status := fnd_api.g_ret_sts_unexp_error;
10940 fnd_msg_pub.count_and_get(p_count => x_msg_count,
10941 p_data => x_msg_data);
10942 IF (l_debug = 1) THEN
10943 print_debug('Exiting Get_Expected_Delivery_Time - Unexpected error: ' ||
10944 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
10945 END IF;
10946
10947 WHEN OTHERS THEN
10948 ROLLBACK TO Get_Expected_Delivery_Time_sp;
10949 x_return_status := fnd_api.g_ret_sts_unexp_error;
10950 IF fnd_msg_pub.check_msg_level(fnd_msg_pub.g_msg_lvl_unexp_error) THEN
10951 fnd_msg_pub.add_exc_msg(g_pkg_name, l_api_name);
10952 END IF;
10953 fnd_msg_pub.count_and_get(p_count => x_msg_count,
10954 p_data => x_msg_data);
10955 IF (l_debug = 1) THEN
10956 print_debug('Exiting Get_Expected_Delivery_Time - Others exception: ' ||
10957 l_progress ||' '|| TO_CHAR(SYSDATE, 'YYYY-MM-DD HH:DD:SS'));
10958 END IF;
10959
10960 END Get_Expected_Delivery_Time;
10961 -- {{ }}
10962 -- {{******************** End Get_Expected_Delivery_Time ********************}}
10963 -- {{ }}
10964
10965
10966 END WMS_XDOCK_PEGGING_PUB;
10967