1 PACKAGE BODY MRP_KANBAN_PLAN_PK AS
2 /* $Header: MRPKPLNB.pls 120.8 2006/05/26 01:47:08 ksuleman noship $ */
3
4 -- ========================================================================
5 -- This function will update the plan_start_date column in mrp_kanban_plans
6 -- table to indicate that the plan has started to run. The user will not
7 -- be able to query up this plan until the plan has finished running.
8 -- ========================================================================
9 FUNCTION START_KANBAN_PLAN
10 RETURN BOOLEAN IS
11
12 l_plan_id number;
13 l_bom_effectivity date;
14 l_start_date date;
15 l_cutoff_date date;
16
17 -- declare exceptions we want to handle here
18 exc_error_condition exception;
19 exc_replan_error exception;
20
21 BEGIN
22
23 g_stmt_num := 20;
24 IF g_debug THEN
25 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
26 MRP_UTIL.MRP_LOG (g_log_message);
27 g_log_message := 'Entering Start_Kanban_Plan function';
28 MRP_UTIL.MRP_LOG (g_log_message);
29 END IF;
30
31
32 -- ------------------------------------------------------------------------
33 -- Validate the plan information
34 -- ------------------------------------------------------------------------
35 SELECT kanban_plan_id,
36 input_type,
37 input_designator,
38 bom_effectivity_date,
39 plan_start_date,
40 plan_cutoff_date
41 INTO l_plan_id,
42 g_kanban_info_rec.input_type,
43 g_kanban_info_rec.input_designator,
44 l_bom_effectivity,
45 l_start_date,
46 l_cutoff_date
47 FROM mrp_kanban_plans
48 WHERE kanban_plan_id = g_kanban_info_rec.kanban_plan_id;
49
50 -- clean out data in some tables depending on whether we are
51 -- replanning or not
52
53 IF nvl(g_kanban_info_rec.replan_flag,2) = 1 THEN -- 1 is Yes, 2 is No
54
55 g_kanban_info_rec.bom_effectivity := l_bom_effectivity;
56 g_kanban_info_rec.start_date := l_start_date;
57 g_kanban_info_rec.cutoff_date := l_cutoff_date;
58
59 IF g_kanban_info_rec.bom_effectivity IS NULL OR
60 g_kanban_info_rec.start_date IS NULL OR
61 g_kanban_info_rec.cutoff_date IS NULL THEN
62 raise exc_replan_error;
63 END IF;
64
65 -- delete all the entries from the low level codes table except
66 -- entries list of kanban items that we had got in the very first
67 -- snapshot of items during a regular plan run
68
69 DELETE FROM mrp_low_level_codes
70 WHERE plan_id = g_kanban_info_rec.kanban_plan_id
71 AND organization_id = g_kanban_info_rec.organization_id
72 AND (levels_below <> 1 OR
73 assembly_item_id = component_item_id OR
74 assembly_item_id = -1 );
75
76 -- update the low level code of each of the remaining records to null
77 UPDATE mrp_low_level_codes
78 SET low_level_code = null
79 WHERE plan_id = g_kanban_info_rec.kanban_plan_id
80 AND organization_id = g_kanban_info_rec.organization_id;
81
82 ELSIF nvl(g_kanban_info_rec.replan_flag,2) = 2 THEN
83
84 DELETE FROM mrp_low_level_codes
85 WHERE plan_id = g_kanban_info_rec.kanban_plan_id
86 AND organization_id = g_kanban_info_rec.organization_id;
87
88 DELETE FROM mtl_kanban_pull_sequences
89 WHERE kanban_plan_id = g_kanban_info_rec.kanban_plan_id;
90
91 END IF;
92
93 DELETE FROM mrp_kanban_demand
94 WHERE kanban_plan_id = g_kanban_info_rec.kanban_plan_id
95 AND organization_id = g_kanban_info_rec.organization_id;
96
97 /* this part of the code was originally in plan_kanban procedure
98 but we moved it to here because we want to commit the snapshot
99 data to have less impact on rollback segments
100 So, as you will see we have put a commit after the call
101 to snapshot_item_locations procedure
102 */
103 -- call the procedure to snapshot the item/locations and
104 -- populate mrp_low_level_codes table.
105 -- Note that we are calculating low level codes
106 -- only to detect loops and not for planning purposes.
107 -- We gather demand by looking at the input to the plan
108 -- and then blow it down to the component item/locations
109
110 IF NOT mrp_kanban_snapshot_pk.snapshot_item_locations THEN
111 g_log_message := 'Error in SNAPSHOT_ITEM_LOCATIONS';
112 MRP_UTIL.MRP_LOG (g_log_message);
113 raise exc_error_condition;
114 END IF;
115
116 commit;
117
118 -- ------------------------------------------------------------------------
119 -- Update some plan information in mrp_kanban_plans table
120 -- ------------------------------------------------------------------------
121 UPDATE mrp_kanban_plans
122 SET plan_start_date = g_kanban_info_rec.start_date,
123 plan_completion_date = NULL,
124 bom_effectivity_date = g_kanban_info_rec.bom_effectivity,
125 plan_cutoff_date = g_kanban_info_rec.cutoff_date
126 WHERE kanban_plan_id = g_kanban_info_rec.kanban_plan_id;
127
128 RETURN TRUE;
129
130 EXCEPTION
131
132 WHEN exc_error_condition THEN
133 ROLLBACK;
134 g_log_message := 'Program encountered Error condition Exception';
135 MRP_UTIL.MRP_LOG (g_log_message);
136 RETURN FALSE;
137
138 WHEN exc_replan_error THEN
139 g_log_message := 'Incomplete Information For Replan';
140 MRP_UTIL.MRP_LOG (g_log_message);
141 Return FALSE;
142
143 WHEN NO_DATA_FOUND THEN
144 g_log_message := 'Invalid Kanban Plan Id';
145 MRP_UTIL.MRP_LOG (g_log_message);
146 Return FALSE;
147
148 WHEN OTHERS THEN
149 g_log_message := 'START_KANBAN_PLAN Sql Error ';
150 MRP_UTIL.MRP_LOG (g_log_message);
151 g_log_message := sqlerrm;
152 MRP_UTIL.MRP_LOG (g_log_message);
153 RETURN FALSE;
154
155 END START_KANBAN_PLAN;
156
157 -- ========================================================================
158 -- This function will update the plan_completion_date column in
159 -- mrp_kanban_plans table to indicate that the plan has successfully
160 -- finished.
161 -- ========================================================================
162 FUNCTION END_KANBAN_PLAN
163 RETURN BOOLEAN IS
164 BEGIN
165
166 IF g_debug THEN
167 g_log_message := 'In End_Kanban_Plan function';
168 fnd_file.put_line (fnd_file.log, g_log_message);
169 END IF;
170
171 -- ------------------------------------------------------------------------
172 -- Update the plan_completion_date to sysdate
173 -- ------------------------------------------------------------------------
174 UPDATE mrp_kanban_plans
175 SET plan_completion_date = sysdate
176 WHERE kanban_plan_id = g_kanban_info_rec.kanban_plan_id;
177
178 -- commit the changes to the database
179 COMMIT;
180
181 RETURN TRUE;
182
183 EXCEPTION
184
185 WHEN OTHERS THEN
186 g_log_message := 'END_KANBAN_PLAN Sql Error ';
187 MRP_UTIL.MRP_LOG (g_log_message);
188 g_log_message := sqlerrm;
189 MRP_UTIL.MRP_LOG (g_log_message);
190 RETURN FALSE;
191
192 END END_KANBAN_PLAN;
193
194 -- ========================================================================
195 -- this function gets the # of working days between start and end dates
196 -- for a MDS and mulitplies that into the repetitive demnad
197 -- this is done only for the MDS and repetitive items.
198 -- ========================================================================
199
200 FUNCTION Get_Repetitive_Demand(
201 p_schedule_date IN DATE,
202 p_rate_end_date IN DATE,
203 p_repetitive_daily_rate IN NUMBER)
204 RETURN NUMBER IS
205 l_days NUMBER :=0;
206
207 CURSOR c1 IS
208 SELECT count(*) count
209 FROM bom_calendar_dates bcd,
210 mtl_parameters mp
211 WHERE mp.organization_id = g_kanban_info_rec.organization_id
212 AND bcd.calendar_code = mp.calendar_code
213 AND bcd.exception_set_id = mp.calendar_exception_set_id
214 AND bcd.calendar_date between
215 p_schedule_date and p_rate_end_date
216 AND bcd.seq_num IS NOT NULL;
217 BEGIN
218
219 IF NOT c1%ISOPEN THEN
220 OPEN c1;
221 END IF;
222 FETCH c1
223 INTO l_days;
224 l_days:= l_days * p_repetitive_daily_rate;
225 IF c1%ISOPEN THEN
226 CLOSE c1;
227 END IF;
228
229 RETURN l_days;
230 END Get_Repetitive_Demand;
231
232
233 -- ========================================================================
234 -- This function finds out if we need to prorate forecast demand and if
235 -- necessary prorates the demand for a weekly or periodic forecast, ie., when
236 -- a part of which falls outside the kanban plan start and cutoff dates
237 -- ========================================================================
238
239 FUNCTION Get_Prorated_Demand (
240 p_bucket_type IN number,
241 p_in_demand_date IN date,
242 p_in_rate_end_date IN date,
243 p_in_demand_qty IN number,
244 p_out_demand_date IN OUT NOCOPY date,
245 p_out_demand_qty IN OUT NOCOPY number
246 )
247 RETURN BOOLEAN
248 IS
249
250 l_total_workdays number;
251 l_current_workdays number;
252 l_demand_quantity number;
253 l_demand_date date;
254 l_next_date date;
255
256 BEGIN
257
258 IF g_debug THEN
259 g_log_message := 'Entering Get_Prorated_Demand Function';
260 MRP_UTIL.MRP_LOG (g_log_message);
261 g_log_message := 'Bucket_Type : ' || to_char (p_bucket_type);
262 MRP_UTIL.MRP_LOG (g_log_message);
263 g_log_message := 'In demand date : ' ||
264 fnd_date.date_to_canonical(p_in_demand_date);
265 MRP_UTIL.MRP_LOG (g_log_message);
266 g_log_message := 'In Rate end date : ' ||
267 fnd_date.date_to_canonical(p_in_rate_end_date);
268 MRP_UTIL.MRP_LOG (g_log_message);
269 g_log_message := 'In demand qty : ' || to_char (p_in_demand_qty);
270 MRP_UTIL.MRP_LOG (g_log_message);
271 END IF;
272 --initialize
273
274 l_demand_date := p_in_demand_date;
275 l_next_date := p_in_rate_end_date;
276 p_out_demand_date := p_in_demand_date;
277 p_out_demand_qty := p_in_demand_qty;
278
279 -- first find out if we need to prorate the demand or not
280
281 IF p_bucket_type = 1 THEN
282 -- daily forecast, no need to prorate
283 RETURN TRUE;
284
285 ELSIF p_bucket_type = 2 OR p_bucket_type = 3 THEN
286
287 IF p_in_rate_end_date IS NULL AND
288 (p_in_demand_date BETWEEN g_kanban_info_rec.start_date AND
289 Get_Offset_Date (g_kanban_info_rec.cutoff_date,
290 p_bucket_type )) THEN
291 --no need to prorate
292 RETURN TRUE;
293 ELSIF p_in_rate_end_date IS NOT NULL AND
294 (p_in_demand_date >= g_kanban_info_rec.start_date AND
295 p_in_rate_end_date <= Get_Offset_Date (
296 g_kanban_info_rec.cutoff_date,
297 p_bucket_type )) THEN
298 --no need to prorate
299 RETURN TRUE;
300
301 END IF;
302
303 END IF;
304
305 --If we come here then it means that we have to prorate the demand
306
307 --First Get the total number of workdays in the period we are
308 --about to consider
309
310 IF p_bucket_type = 2 THEN
311
312 SELECT count(*)
313 INTO l_total_workdays
314 FROM bom_calendar_dates cd,
315 bom_cal_week_start_dates ws,
316 mtl_parameters mp
317 WHERE mp.organization_id = g_kanban_info_rec.organization_id
318 AND ws.calendar_code = mp.calendar_code
319 AND ws.exception_set_id = mp.calendar_exception_set_id
320 AND ws.week_start_date = l_demand_date
321 AND cd.calendar_code = ws.calendar_code
322 AND cd.exception_set_id = ws.exception_set_id
323 AND (cd.calendar_date BETWEEN ws.week_start_date AND
324 ws.next_date)
325 AND cd.seq_num IS NOT NULL;
326
327 ELSIF p_bucket_type = 3 THEN
328
329 SELECT count(*)
330 INTO l_total_workdays
331 FROM bom_calendar_dates cd,
332 bom_period_start_dates ps,
333 mtl_parameters mp
334 WHERE mp.organization_id = g_kanban_info_rec.organization_id
335 AND ps.calendar_code = mp.calendar_code
336 AND ps.exception_set_id = mp.calendar_exception_set_id
337 AND ps.period_start_date = l_demand_date
338 AND cd.calendar_code = ps.calendar_code
339 AND cd.exception_set_id = ps.exception_set_id
340 AND (cd.calendar_date BETWEEN ps.period_start_date AND
341 ps.next_date)
342 AND cd.seq_num IS NOT NULL;
343
344 END IF;
345
346 -- alter the demand_date if necessary
347 IF l_demand_date < g_kanban_info_rec.start_date THEN
348 l_demand_date := g_kanban_info_rec.start_date;
349 END IF;
350
351 -- similarly alter the next_date if necessary
352 -- first get the next_date if it is null
353
354 IF l_next_date IS NULL THEN -- which it can be for non repetitive forecasts
355 IF p_bucket_type = 2 THEN
356
357 SELECT bw.next_date
358 INTO l_next_date
359 FROM bom_cal_week_start_dates bw,
360 mtl_parameters mp
361 WHERE mp.organization_id = g_kanban_info_rec.organization_id
362 AND bw.calendar_code = mp.calendar_code
363 AND bw.exception_set_id = mp.calendar_exception_set_id
364 AND bw.week_start_date <= l_demand_date
365 AND bw.next_date >= l_demand_date;
366
367 ELSIF p_bucket_type = 3 THEN
368
369 SELECT bp.next_date
370 INTO l_next_date
371 FROM bom_period_start_dates bp,
372 mtl_parameters mp
373 WHERE mp.organization_id = g_kanban_info_rec.organization_id
374 AND bp.calendar_code = mp.calendar_code
375 AND bp.exception_set_id = mp.calendar_exception_set_id
376 AND bp.period_start_date <= l_demand_date
377 AND bp.next_date >= l_demand_date;
378
379 END IF;
380
381 END IF;
382
383 IF l_next_date > g_kanban_info_rec.cutoff_date THEN
384 l_next_date := g_kanban_info_rec.cutoff_date;
385 END IF;
386
387 -- now calculate the number of workdays for which we have to
388 -- consider the demand out of the weekly/periodic forecast we
389 -- are working with
390
391 SELECT count(*)
392 INTO l_current_workdays
393 FROM bom_calendar_dates cd,
394 mtl_parameters mp
395 WHERE mp.organization_id = g_kanban_info_rec.organization_id
396 AND cd.calendar_code = mp.calendar_code
397 AND cd.exception_set_id = mp.calendar_exception_set_id
398 AND (cd.calendar_date BETWEEN l_demand_date AND l_next_date)
399 AND cd.seq_num IS NOT NULL;
400
401 -- once we mucked around with the dates, we have to arrive at the
402 -- correct demand quantity for the length of the week/period
403 l_demand_quantity := (l_current_workdays/l_total_workdays) *
404 p_in_demand_qty;
405
406 p_out_demand_date := l_demand_date;
407 p_out_demand_qty := l_demand_quantity;
408
409 IF g_debug THEN
410 g_log_message := 'Current workdays : ' || to_char (l_current_workdays);
411 MRP_UTIL.MRP_LOG (g_log_message);
412 g_log_message := 'Total Workdays : ' || to_char (l_total_workdays);
413 MRP_UTIL.MRP_LOG (g_log_message);
414 g_log_message := 'Out Demand Date : ' || to_char (l_demand_date);
415 MRP_UTIL.MRP_LOG (g_log_message);
416 g_log_message := 'Out Demand qty : ' || to_char (l_demand_quantity);
417 MRP_UTIL.MRP_LOG (g_log_message);
418 g_log_message := 'Exiting Get_Prorated_Demand Function';
419 MRP_UTIL.MRP_LOG (g_log_message);
420 END IF;
421
422 RETURN TRUE;
423
424 EXCEPTION
425 WHEN OTHERS THEN
426 g_log_message := 'GET_PRORATED_DEMAND Sql Error ';
427 MRP_UTIL.MRP_LOG (g_log_message);
428 g_log_message := sqlerrm;
429 MRP_UTIL.MRP_LOG (g_log_message);
430 RETURN FALSE;
431
432 END Get_Prorated_Demand;
433
434 -- ========================================================================
435 -- this function explodes the demand for repetitive forecast entries
436 -- ========================================================================
437
438 FUNCTION Explode_Repetitive_Forecast (
439 p_inventory_item_id IN number,
440 p_demand_quantity IN number,
441 p_demand_date IN date,
442 p_rate_end_date IN date,
443 p_bucket_type IN number,
444 p_demand_type IN number,
445 p_line_id IN number,
446 p_item_sub_inventory IN VARCHAR2,
447 p_item_locator IN number,
448 p_parent_sub_inventory IN VARCHAR2,
449 p_parent_locator IN number,
450 p_parent_item_id IN number,
451 p_kanban_item_flag IN VARCHAR2,
452 insert_or_cascade IN boolean)
453
454
455 RETURN BOOLEAN IS
456
457 l_rate_end_date date;
458 l_rate_start_date date;
459 l_demand_date date;
460 l_next_date date;
461 l_demand_quantity number;
462 l_current_workdays number;
463 l_total_workdays number;
464 l_line_id number;
465 l_ret_val boolean;
466
467 -- cursor for repetitive periodic forecast dates
468 cursor cur_periodic_forecasts is
469 SELECT bp.period_start_date, bp.next_date
470 FROM bom_period_start_dates bp, mtl_parameters mp
471 WHERE mp.organization_id = g_kanban_info_rec.organization_id
472 AND bp.calendar_code = mp.calendar_code
473 AND bp.exception_set_id = mp.calendar_exception_set_id
474 AND (bp.period_start_date BETWEEN p_demand_date AND
475 p_rate_end_date);
476
477 -- cursor for repetitive weekly forecast dates
478 cursor cur_weekly_forecasts is
479 SELECT bw.week_start_date, bw.next_date
480 FROM bom_cal_week_start_dates bw, mtl_parameters mp
481 WHERE mp.organization_id = g_kanban_info_rec.organization_id
482 AND bw.calendar_code = mp.calendar_code
483 AND bw.exception_set_id = mp.calendar_exception_set_id
484 AND (bw.week_start_date BETWEEN p_demand_date AND
485 p_rate_end_date);
486
487 -- cursor for repetitive daily forecast dates
488 cursor cur_daily_forecasts is
489 SELECT bcd.calendar_date
490 FROM bom_calendar_dates bcd, mtl_parameters mp
491 WHERE mp.organization_id = g_kanban_info_rec.organization_id
492 AND bcd.calendar_code = mp.calendar_code
493 AND bcd.exception_set_id = mp.calendar_exception_set_id
494 AND (bcd.calendar_date BETWEEN l_rate_start_date AND
495 l_rate_end_date)
496 AND bcd.seq_num is not null;
497
498 BEGIN
499
500 IF g_debug THEN
501 g_log_message := 'Entering Explode_Repetitive_Forecast Function';
502 MRP_UTIL.MRP_LOG (g_log_message);
503 END IF;
504
505 -- some constraints we have to consider for daily forecasts. The
506 -- processing for weekly and periodic forecasts is done later
507
508 -- check from what date we need to consider the daily repetitive forecast
509 IF p_demand_date > g_kanban_info_rec.start_date THEN
510 l_rate_start_date := p_demand_date;
511 ELSE
512 l_rate_start_date := g_kanban_info_rec.start_date;
513 END IF;
514
515 -- check upto what date we need to consider the daily repetitive forecast
516 IF p_rate_end_date > g_kanban_info_rec.cutoff_date THEN
517 l_rate_end_date := g_kanban_info_rec.cutoff_date;
518 ELSE
519 l_rate_end_date := p_rate_end_date;
520 END IF;
521
522 WHILE TRUE LOOP
523
524 -- Depending on the bucket type go after the respective cursor
525
526 IF g_debug THEN
527 g_log_message := 'Going in while loop inside Explode_Repetitive_Forecast';
528 MRP_UTIL.MRP_LOG (g_log_message);
529 END IF;
530
531 IF p_bucket_type = 1 THEN -- daily buckets
532
533 IF NOT cur_daily_forecasts%ISOPEN THEN
534 OPEN cur_daily_forecasts;
535 END IF;
536
537 FETCH cur_daily_forecasts
538 INTO l_demand_date;
539
540 EXIT WHEN cur_daily_forecasts%NOTFOUND;
541
542 ELSIF p_bucket_type = 2 THEN -- weekly buckets
543
544 IF NOT cur_weekly_forecasts%ISOPEN THEN
545 OPEN cur_weekly_forecasts;
546 END IF;
547
548 FETCH cur_weekly_forecasts
549 INTO l_demand_date,
550 l_next_date;
551
552 EXIT WHEN cur_weekly_forecasts%NOTFOUND;
553
554 ELSIF p_bucket_type = 3 THEN -- periodic buckets
555
556 IF NOT cur_periodic_forecasts%ISOPEN THEN
557 OPEN cur_periodic_forecasts;
558 END IF;
559
560 FETCH cur_periodic_forecasts
561 INTO l_demand_date,
562 l_next_date;
563
564 EXIT WHEN cur_periodic_forecasts%NOTFOUND;
565
566 END IF;
567
568 IF g_debug THEN
569 g_log_message := 'Done with the buckets';
570 MRP_UTIL.MRP_LOG (g_log_message);
571 END IF;
572
573 -- we need to do some extra work for weekly and periodic
574 -- forecasts in order to figure out the correct demand in the
575 -- specified period.
576
577 IF p_bucket_type = 2 OR p_bucket_type = 3 THEN
578 -- Call the prorating function
579 IF g_debug THEN
580 g_log_message := 'Call the prorating function';
581 MRP_UTIL.MRP_LOG (g_log_message);
582 END IF;
583
584 IF NOT Get_Prorated_Demand (
585 p_bucket_type,
586 l_demand_date,
587 l_next_date,
588 p_demand_quantity,
589 l_demand_date,
590 l_demand_quantity ) THEN
591 RETURN FALSE;
592 END IF;
593
594 ELSIF p_bucket_type = 1 THEN
595 l_demand_quantity := p_demand_quantity;
596 END IF;
597
598 -- now call the function to insert the demand and explode it through
599 -- to the bottom of the bill
600
601 IF (p_line_id is NULL) THEN
602 Begin
603 SELECT line_id
604 INTO l_line_id
605 FROM bom_operational_routings
606 WHERE alternate_routing_designator is NULL
607 AND assembly_item_id = p_inventory_item_id
608 AND organization_id = g_kanban_info_rec.organization_id;
609 Exception
610 When Others Then
611 Null;
612 End;
613 ELSE
614 l_line_id := p_line_id;
615 END IF;
616 IF g_debug THEN
617 g_log_message := 'Inserting into MRP_KANBAN_DEMAND';
618 MRP_UTIL.MRP_LOG (g_log_message);
619 g_log_message := 'LineN : ' || to_char(l_line_id);
620 MRP_UTIL.MRP_LOG (g_log_message);
621 g_log_message := 'in erd ItemN : ' || to_char(p_inventory_item_id);
622 MRP_UTIL.MRP_LOG (g_log_message);
623 g_log_message := 'in erd demand date: ' || to_char(l_demand_date);
624 MRP_UTIL.MRP_LOG (g_log_message);
625 g_log_message := 'in erd demand quant: ' || to_char(l_demand_quantity);
626 MRP_UTIL.MRP_LOG (g_log_message);
627
628 END IF;
629
630
631 IF l_demand_quantity > 0 THEN
632
633 IF INSERT_OR_CASCADE = TRUE THEN
634 INSERT INTO MRP_KANBAN_DEMAND (
635 DEMAND_ID,
636 KANBAN_PLAN_ID,
637 ORGANIZATION_ID,
638 INVENTORY_ITEM_ID,
639 SUBINVENTORY,
640 LOCATOR_ID,
641 ASSEMBLY_ITEM_ID,
642 ASSEMBLY_ORG_ID,
643 ASSEMBLY_SUBINVENTORY,
644 ASSEMBLY_LOCATOR_ID,
645 DEMAND_DATE,
646 DEMAND_QUANTITY,
647 ORDER_TYPE,
648 KANBAN_ITEM_FLAG,
649 REQUEST_ID,
650 PROGRAM_APPLICATION_ID,
651 PROGRAM_ID,
652 PROGRAM_UPDATE_DATE,
653 LAST_UPDATE_DATE,
654 LAST_UPDATED_BY,
655 CREATION_DATE,
656 CREATED_BY )
657 SELECT
658 mrp_kanban_demand_s.nextval,
659 g_kanban_info_rec.kanban_plan_id,
660 g_kanban_info_rec.organization_id,
661 p_inventory_item_id,
662 ps.subinventory_name,
663 ps.locator_id,
664 NULL,
665 NULL,
666 NULL,
667 NULL,
668 l_demand_date,
669 (NVL(ps.allocation_percent, 100) *
670 l_demand_quantity/ 100),
671 p_demand_type,
672 'Y',
673 fnd_global.conc_request_id,
674 fnd_global.prog_appl_id,
675 fnd_global.conc_program_id,
676 sysdate,
677 sysdate,
678 fnd_global.user_id,
679 sysdate,
680 fnd_global.user_id
681 FROM
682 mtl_kanban_pull_sequences ps
683 WHERE ps.wip_line_id = l_line_id
684 AND ps.source_type = G_PRODUCTION_SOURCE_TYPE
685 AND ps.kanban_plan_id = decode (g_kanban_info_rec.replan_flag,
686 2, G_PRODUCTION_KANBAN,
687 1, g_kanban_info_rec.kanban_plan_id,
688 G_PRODUCTION_KANBAN)
689 AND ps.inventory_item_id = p_inventory_item_id
690 AND ps.organization_id = g_kanban_info_rec.organization_id;
691 ELSE/* its cascade*/
692 INSERT INTO MRP_KANBAN_DEMAND (
693 DEMAND_ID,
694 KANBAN_PLAN_ID,
695 ORGANIZATION_ID,
696 INVENTORY_ITEM_ID,
697 SUBINVENTORY,
698 LOCATOR_ID,
699 ASSEMBLY_ORG_ID,
700 ASSEMBLY_ITEM_ID,
701 ASSEMBLY_SUBINVENTORY,
702 ASSEMBLY_LOCATOR_ID,
703 DEMAND_DATE,
704 DEMAND_QUANTITY,
705 ORDER_TYPE,
706 KANBAN_ITEM_FLAG,
707 REQUEST_ID,
708 PROGRAM_APPLICATION_ID,
709 PROGRAM_ID,
710 PROGRAM_UPDATE_DATE,
711 LAST_UPDATE_DATE,
712 LAST_UPDATED_BY,
713 CREATION_DATE,
714 CREATED_BY )
715 SELECT
716 mrp_kanban_demand_s.nextval,
717 g_kanban_info_rec.kanban_plan_id,
718 g_kanban_info_rec.organization_id,
719 p_inventory_item_id,
720 p_item_sub_inventory,
721 p_item_locator,
722 g_kanban_info_rec.organization_id,
723 p_parent_item_id,
724 p_parent_sub_inventory,
725 p_parent_locator,
726 l_demand_date,
727 l_demand_quantity,
728 p_demand_type,
729 p_kanban_item_flag,
730 fnd_global.conc_request_id,
731 fnd_global.prog_appl_id,
732 fnd_global.conc_program_id,
733 sysdate,
734 sysdate,
735 fnd_global.user_id,
736 sysdate,
737 fnd_global.user_id
738 FROM
739 DUAL;
740
741 END IF;
742 END IF;--demand > 0
743 END LOOP;
744
745 -- close whatever cursor is open
746 IF cur_daily_forecasts%ISOPEN THEN
747 CLOSE cur_daily_forecasts;
748 ELSIF cur_weekly_forecasts%ISOPEN THEN
749 CLOSE cur_weekly_forecasts;
750 ELSIF cur_periodic_forecasts%ISOPEN THEN
751 CLOSE cur_periodic_forecasts;
752 END IF;
753
754 RETURN TRUE;
755
756 --exception handling
757 EXCEPTION
758 WHEN OTHERS THEN
759 g_log_message := 'EXPLODE_REPETITIVE_FORECAST Sql Error ';
760 MRP_UTIL.MRP_LOG (g_log_message);
761 g_log_message := sqlerrm;
762 MRP_UTIL.MRP_LOG (g_log_message);
763 RETURN FALSE;
764 END Explode_Repetitive_Forecast;
765
766 -- ========================================================================
767 -- This function passes demand down to the components all the way down
768 -- to the bottom of the bill for the FORECAST/Actual Production
769 -- ========================================================================
770 FUNCTION Cascade_Fcst_Demand(
771 p_bill_or_ps IN NUMBER,
772 p_recursive IN BOOLEAN,
773 p_parent_line_id IN NUMBER,
774 p_line_id IN NUMBER,
775 p_top_item_id IN NUMBER,
776 p_assembly_item_id IN NUMBER,
777 p_cumulative_usage IN NUMBER,
778 p_subinventory IN VARCHAR2,
779 p_locator_id IN NUMBER,
780 p_demand_type IN NUMBER,
781 p_explode_always IN VARCHAR2,
782 p_sales_order_demand IN VARCHAR2,
783 p_assy_foq IN NUMBER )
784
785 RETURN BOOLEAN IS
786
787 --declare some local variables here
788 l_bill_or_ps number; -- 1 - bill; 2 - pull sequence
789
790 l_component_id number;
791 l_subinventory varchar2(10);
792 l_locator_id number;
793 l_component_usage number;
794 l_component_yield number;
795 l_operation_yield number;
796 l_net_planning_percent number;
797 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
798 l_planning_factor number;
799 l_item_num number;
800 /* End of Update */
801 l_kanban_item_flag varchar2(1);
802 l_demand_quantity number;
803 l_ret_val boolean;
804
805 l_line_id number;
806 l_forecast_quantity number;
807 l_forecast_date date;
808 l_rate_end_date date;
809 l_bucket_type number;
810 l_running_total_quantity number := 0;
811 l_cumulative_usage number;
812 l_wip_supply_type number;
813 l_basis_type number;
814 l_comp_foq number;
815 l_foq number;
816
817
818 CURSOR parent_schedule_entries IS
819 SELECT current_forecast_quantity,
820 forecast_date,
821 rate_end_date,
822 bucket_type
823 FROM mrp_forecast_dates
824 WHERE organization_id = g_kanban_info_rec.organization_id
825 AND ((forecast_designator = g_kanban_info_rec.input_designator) or
826 (forecast_designator in ( -- forecast set
827 select forecast_designator
828 from mrp_forecast_designators
829 where forecast_set = g_kanban_info_rec.input_designator)
830 )
831 )
832 AND inventory_item_id = p_top_item_id
833 AND origination_type = p_demand_type
834 AND nvl(line_id,0) = nvl(p_parent_line_id,0)
835 AND ((rate_end_date IS NULL AND
836 forecast_date BETWEEN Get_Offset_Date(
837 g_kanban_info_rec.start_date,
838 bucket_type )
839 AND g_kanban_info_rec.cutoff_date) OR
840 (rate_end_date is NOT NULL AND NOT
841 (rate_end_date < Get_Offset_Date(
842 g_kanban_info_rec.start_date,
843 bucket_type ) OR
844 forecast_date > g_kanban_info_rec.cutoff_date)));
845
846
847 -- cursor component_cursor1 is the cursor that passes down demand
848 -- to the components feeding into a line. Notice that we are driving
849 -- off of bom_operational_routings
850 -- also if supply sub and locator are null in bom_inventory_components
851 -- we get it from wip supply locations from mtl_system_items - this
852 -- is ok for R-11, though we might have an issue here for R12
853
854 CURSOR component_cursor1 IS
855 SELECT DISTINCT
856 bic.component_item_id,
857 decode(bic.supply_subinventory, NULL, msi.wip_supply_subinventory,
858 bic.supply_subinventory),
859 decode(bic.supply_locator_id, NULL, msi.wip_supply_locator_id,
860 bic.supply_locator_id),
861 bic.component_quantity,
862 bic.component_yield_factor,
863 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
864 bic.planning_factor,
865 bic.item_num,
866 /* End of Update */
867 mllc.operation_yield,
868 mllc.net_planning_percent,
869 mllc.kanban_item_flag,
870 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
871 mllc.wip_supply_type,
872 mllc.basis_type,
873 nvl(msi.fixed_order_quantity, nvl(msi.minimum_order_quantity, nvl(msi.maximum_order_quantity,1)))
874 FROM mtl_system_items msi,
875 mrp_low_level_codes mllc,
876 bom_inventory_components bic,
877 bom_bill_of_materials bbom,
878 bom_operational_routings bor,
879 mtl_parameters mp
880 WHERE mp.organization_id = g_kanban_info_rec.organization_id
881 AND bor.line_id (+) = p_line_id
882 AND bor.assembly_item_id (+) = p_assembly_item_id
883 AND bor.organization_id (+) = mp.organization_id
884 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_Min_Priority (
885 bor.assembly_item_id,
886 bor.organization_id,
887 bor.line_id,
888 bor.alternate_routing_designator)
889 /* BUG: 1668867 Double kanban demand */
890 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_assy_cfgitem (
891 p_assembly_item_id,
892 bic.component_item_id,
893 mp.organization_id)
894 AND bbom.assembly_item_id = p_assembly_item_id
895 AND bbom.organization_id = mp.organization_id
896 AND nvl(bbom.alternate_bom_designator, 'xxx') =
897 nvl(bor.alternate_routing_designator, 'xxx')
898 AND bic.bill_sequence_id = bbom.common_bill_sequence_id
899 AND nvl(bic.disable_date, g_kanban_info_rec.bom_effectivity + 1)
900 >= g_kanban_info_rec.bom_effectivity
901 AND bic.effectivity_date <= g_kanban_info_rec.bom_effectivity
902 AND NOT EXISTS (
903 SELECT NULL
904 FROM bom_inventory_components bic2
905 WHERE bic2.bill_sequence_id = bic.bill_sequence_id
906 AND bic2.component_item_id = bic.component_item_id
907 AND (decode(bic2.implementation_date, null,
908 bic2.old_component_sequence_id,
909 bic2.component_sequence_id) =
910 decode(bic.implementation_date, null,
911 bic.old_component_sequence_id,
912 bic.component_sequence_id)
913 OR bic2.operation_seq_num = bic.operation_seq_num)
914 AND bic2.effectivity_date <=
915 g_kanban_info_rec.bom_effectivity
916 AND bic2.effectivity_date > bic.effectivity_date
917 AND (bic2.implementation_date is not null OR
918 (bic2.implementation_date is null AND EXISTS
919 (SELECT NULL
920 FROM eng_revised_items eri
921 WHERE bic2.revised_item_sequence_id =
922 eri.revised_item_sequence_id
923 AND eri.mrp_active = 1 ))))
924 AND (bic.implementation_date is not null OR
925 (bic.implementation_date is null AND EXISTS
926 (SELECT NULL
927 FROM eng_revised_items eri
928 WHERE bic.revised_item_sequence_id =
929 eri.revised_item_sequence_id
930 AND eri.mrp_active = 1 )))
931 AND mllc.plan_id = g_kanban_info_rec.kanban_plan_id
932 AND mllc.organization_id = bbom.organization_id
933 AND mllc.assembly_item_id = bbom.assembly_item_id
934 AND mllc.component_item_id = bic.component_item_id
935 AND nvl(mllc.alternate_designator, 'xxx') =
936 nvl(bbom.alternate_bom_designator, 'xxx')
937 AND msi.inventory_item_id = mllc.component_item_id
938 AND msi.organization_id = mllc.organization_id
939 AND ((nvl(msi.ato_forecast_control, G_NO_FCST_CONTROL) = G_NO_FCST_CONTROL)
940 OR p_explode_always = 'Y'
941 OR (p_sales_order_demand = 'Y' AND msi.bom_item_type = 4));
942
943 -- cursor component_cursor2 blows down demand to the components
944 -- as stored in the mrp_low_level_codes table
945 CURSOR component_cursor2 IS
946 SELECT DISTINCT
947 mllc.component_item_id,
948 mllc.from_subinventory,
949 mllc.from_locator_id,
950 mllc.component_usage,
951 mllc.component_yield,
952 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
953 mllc.planning_factor,
954 mllc.item_num,
955 /* End of Update */
956 mllc.operation_yield,
957 mllc.net_planning_percent,
958 mllc.kanban_item_flag,
959 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
960 mllc.wip_supply_type,
961 mllc.basis_type,
962 nvl(msi.fixed_order_quantity, nvl(msi.minimum_order_quantity, nvl(msi.maximum_order_quantity,1)))
963 FROM mtl_system_items msi,
964 mrp_low_level_codes mllc
965 WHERE mllc.plan_id = g_kanban_info_rec.kanban_plan_id
966 AND mllc.organization_id + 0 = g_kanban_info_rec.organization_id
967 AND mllc.assembly_item_id = p_assembly_item_id
968 AND ((mllc.to_subinventory = p_subinventory
969 AND nvl(mllc.to_locator_id,-1) = nvl(p_locator_id,-1)) OR
970 (mllc.to_subinventory is NULL and p_bill_or_ps = 1) )
971 AND msi.inventory_item_id = mllc.component_item_id
972 AND msi.organization_id = mllc.organization_id
973 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
974 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_Min_Priority (
975 mllc.assembly_item_id,
976 mllc.organization_id,
977 null,
978 mllc.alternate_designator)
979 /* End of Update */
980 /* BUG 1668867, Double Kanban demand problem */
981 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_assy_cfgitem (
982 p_assembly_item_id,
983 mllc.component_item_id,
984 mllc.organization_id)
985 AND ((nvl(msi.ato_forecast_control, G_NO_FCST_CONTROL) = G_NO_FCST_CONTROL)
986 OR p_explode_always = 'Y'
987 OR (p_sales_order_demand = 'Y' AND msi.bom_item_type = 4));
988
989 BEGIN
990
991 IF g_debug THEN
992
993 g_log_message := 'Entering Cascade_Fcst_Demand function';
994 MRP_UTIL.MRP_LOG (g_log_message);
995 g_log_message := 'Cascading Demand For : ';
996 MRP_UTIL.MRP_LOG (g_log_message);
997 g_log_message := 'Line : ' || to_char(p_line_id);
998 MRP_UTIL.MRP_LOG (g_log_message);
999 g_log_message := 'Item : ' || to_char(p_assembly_item_id);
1000 MRP_UTIL.MRP_LOG (g_log_message);
1001 g_log_message := 'Sub : ' || p_subinventory;
1002 MRP_UTIL.MRP_LOG (g_log_message);
1003 g_log_message := 'Loc : ' || p_locator_id;
1004 MRP_UTIL.MRP_LOG (g_log_message);
1005 END IF;
1006
1007 -- Depending on the boolean flag p_recursive, we decide what cursor
1008 -- we want to go after. We know that we will have a line reference
1009 -- on the demand. So, when we call Cacade_Demand the first time, ie
1010 -- to pass down demand to components feeding into the line, then
1011 -- p_recursive is false. We just blow the demand down one level. Once
1012 -- we do that, we call Cascade_Fcst_Ap_Demand in the recursive mode with
1013 -- p_recursive set to true when we want to go after mrp_low_level_codes
1014 -- recursively and blow the demand all the way down.
1015
1016 IF NOT p_recursive THEN
1017 IF NOT component_cursor1%ISOPEN THEN
1018 OPEN component_cursor1;
1019 END IF;
1020
1021 ELSE
1022
1023 IF NOT component_cursor2%ISOPEN THEN
1024 OPEN component_cursor2;
1025 END IF;
1026 END IF;
1027
1028 WHILE TRUE LOOP
1029 IF not p_recursive THEN
1030 FETCH component_cursor1
1031 INTO l_component_id,
1032 l_subinventory,
1033 l_locator_id,
1034 l_component_usage,
1035 l_component_yield,
1036 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1037 l_planning_factor,
1038 l_item_num,
1039 /* End of Update */
1040 l_operation_yield,
1041 l_net_planning_percent,
1042 l_kanban_item_flag,
1043 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1044 l_wip_supply_type,
1045 l_basis_type,
1046 l_comp_foq;
1047 EXIT WHEN component_cursor1%NOTFOUND;
1048
1049 ELSE
1050
1051 FETCH component_cursor2
1052 INTO l_component_id,
1053 l_subinventory,
1054 l_locator_id,
1055 l_component_usage,
1056 l_component_yield,
1057 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1058 l_planning_factor,
1059 l_item_num,
1060 /* End of Update */
1061 l_operation_yield,
1062 l_net_planning_percent,
1063 l_kanban_item_flag,
1064 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1065 l_wip_supply_type,
1066 l_basis_type,
1067 l_comp_foq;
1068 EXIT WHEN component_cursor2%NOTFOUND;
1069
1070
1071 END IF;
1072
1073 IF g_debug THEN
1074 g_log_message := 'component_usage is : ' || to_char (l_component_usage);
1075 MRP_UTIL.MRP_LOG (g_log_message);
1076 g_log_message := 'Net_Planning_Percent is : ' ||
1077 to_char (l_net_planning_percent);
1078 MRP_UTIL.MRP_LOG (g_log_message);
1079 g_log_message := 'Operation_Yield is : ' || to_char (l_operation_yield);
1080 MRP_UTIL.MRP_LOG (g_log_message);
1081 g_log_message := 'Component_Yield is : ' || to_char (l_component_yield);
1082 MRP_UTIL.MRP_LOG (g_log_message);
1083
1084 g_log_message := 'Sub: ' || l_subinventory;
1085 MRP_UTIL.MRP_LOG (g_log_message);
1086 END IF;
1087
1088
1089 -- calculate the demand quantity to be passed down using all the
1090 -- percentages and yields stuff that we've got
1091
1092 IF NOT parent_schedule_entries%ISOPEN THEN
1093 OPEN parent_schedule_entries;
1094 END IF;
1095 WHILE TRUE LOOP
1096
1097 FETCH parent_schedule_entries
1098 INTO l_forecast_quantity,
1099 l_forecast_date,
1100 l_rate_end_date,
1101 l_bucket_type;
1102 EXIT WHEN parent_schedule_entries%NOTFOUND;
1103
1104 IF l_rate_end_date IS NULL THEN
1105 -- not a repetitive forecast - simple processing
1106
1107 IF l_bucket_type = 2 OR l_bucket_type = 3 THEN
1108 --Call the pro-rating function
1109 IF NOT Get_Prorated_Demand (
1110 l_bucket_type,
1111 l_forecast_date,
1112 l_rate_end_date,
1113 l_forecast_quantity,
1114 l_forecast_date,
1115 l_forecast_quantity) THEN
1116 RETURN FALSE;
1117 END IF;
1118 END IF;
1119
1120 l_running_total_quantity := l_running_total_quantity + nvl(
1121 l_forecast_quantity,0);
1122
1123 /* Added for lot based material support
1124 The p_assy_foq is the fixed order quantity of the assembly.
1125 It can be either the foq from the item master or it's parent (for phantom assembly).
1126 The p_assy_foq will be used to calculate the component's demand when the
1127 component has lot basis type and the demand is not from the pull sequence chain. */
1128 if (l_basis_type = WIP_CONSTANTS.LOT_BASED_MTL and l_component_id <> p_assembly_item_id) then
1129 l_foq := p_assy_foq;
1130 else
1131 l_foq := 1;
1132 end if;
1133
1134 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1135 /* l_demand_quantity := ROUND((l_forecast_quantity* nvl(l_component_usage, 1) *
1136 nvl(p_cumulative_usage,1)*
1137 (nvl(l_net_planning_percent, 100) /100)) /
1138 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1))); */
1139 l_demand_quantity := ((l_forecast_quantity* nvl(l_component_usage, 1) *
1140 nvl(p_cumulative_usage,1)*
1141 (nvl(l_planning_factor, 100) /100)) /
1142 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1)))/l_foq;
1143 /* End of Update */
1144
1145 IF g_debug THEN
1146 g_log_message := 'Deamnd Quantity:'||to_char(l_demand_quantity);
1147 MRP_UTIL.MRP_LOG (g_log_message);
1148 END IF;
1149
1150 -- now insert the demand into the kanban demand table if its > 0
1151
1152 IF l_demand_quantity > 0 THEN
1153
1154 INSERT INTO MRP_KANBAN_DEMAND (
1155 DEMAND_ID,
1156 KANBAN_PLAN_ID,
1157 ORGANIZATION_ID,
1158 INVENTORY_ITEM_ID,
1159 SUBINVENTORY,
1160 LOCATOR_ID,
1161 ASSEMBLY_ORG_ID,
1162 ASSEMBLY_ITEM_ID,
1163 ASSEMBLY_SUBINVENTORY,
1164 ASSEMBLY_LOCATOR_ID,
1165 DEMAND_DATE,
1166 DEMAND_QUANTITY,
1167 ORDER_TYPE,
1168 KANBAN_ITEM_FLAG,
1169 REQUEST_ID,
1170 PROGRAM_APPLICATION_ID,
1171 PROGRAM_ID,
1172 PROGRAM_UPDATE_DATE,
1173 LAST_UPDATE_DATE,
1174 LAST_UPDATED_BY,
1175 CREATION_DATE,
1176 CREATED_BY )
1177 SELECT
1178 mrp_kanban_demand_s.nextval,
1179 g_kanban_info_rec.kanban_plan_id,
1180 g_kanban_info_rec.organization_id,
1181 l_component_id,
1182 l_subinventory,
1183 l_locator_id,
1184 g_kanban_info_rec.organization_id,
1185 p_assembly_item_id,
1186 p_subinventory,
1187 p_locator_id,
1188 l_forecast_date,
1189 l_demand_quantity,
1190 8,
1191 l_kanban_item_flag,
1192 fnd_global.conc_request_id,
1193 fnd_global.prog_appl_id,
1194 fnd_global.conc_program_id,
1195 sysdate,
1196 sysdate,
1197 fnd_global.user_id,
1198 sysdate,
1199 fnd_global.user_id
1200 FROM
1201 DUAL;
1202
1203 END IF;
1204
1205 ELSIF l_rate_end_date IS NOT NULL THEN
1206 -- this is repetitive forecast entry - needs explosion of forecast
1207
1208 l_running_total_quantity := l_running_total_quantity + nvl(
1209 l_forecast_quantity,0);
1210
1211 if (l_basis_type = WIP_CONSTANTS.LOT_BASED_MTL and l_component_id <> p_assembly_item_id) then
1212 l_foq := p_assy_foq;
1213 else
1214 l_foq := 1;
1215 end if;
1216
1217 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1218 /* l_demand_quantity := ROUND((l_forecast_quantity* nvl(l_component_usage, 1) *
1219 nvl(p_cumulative_usage,1)*
1220 (nvl(l_net_planning_percent, 100) /100)) /
1221 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1))); */
1222 l_demand_quantity := ((l_forecast_quantity* nvl(l_component_usage, 1) *
1223 nvl(p_cumulative_usage,1)*
1224 (nvl(l_planning_factor, 100) /100)) /
1225 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1)))/l_foq;
1226 /* End of Update */
1227
1228 IF g_debug THEN
1229 g_log_message := 'Deamnd Quantity:'||to_char(l_demand_quantity);
1230 MRP_UTIL.MRP_LOG (g_log_message);
1231 END IF;
1232
1233 -- call the function that explodes repetitive foreast demand
1234
1235 l_ret_val := Explode_Repetitive_Forecast (
1236 l_component_id,
1237 l_demand_quantity,
1238 l_forecast_date,
1239 l_rate_end_date,
1240 l_bucket_type,
1241 8,
1242 l_line_id,
1243 l_subinventory,
1244 l_locator_id,
1245 p_subinventory,
1246 p_locator_id,
1247 p_assembly_item_id,
1248 l_kanban_item_flag,
1249 FALSE);
1250 IF NOT l_ret_val THEN
1251 return FALSE;
1252 END IF;
1253
1254 END IF;
1255
1256 END LOOP;-- end of my cursor
1257 IF parent_schedule_entries%ISOPEN THEN
1258 CLOSE parent_schedule_entries;
1259 END IF;
1260
1261 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1262 -- l_cumulative_usage := p_cumulative_usage * l_component_usage;
1263 l_cumulative_usage := p_cumulative_usage * l_component_usage * (nvl(l_planning_factor, 100)/100) / l_foq;
1264 /* End of Update */
1265
1266 IF ( l_running_total_quantity > 0) THEN
1267 IF g_debug THEN
1268 g_log_message := 'Calling Cascade_Forecast_Demand in recursive mode';
1269 MRP_UTIL.MRP_LOG (g_log_message);
1270 END IF;
1271
1272 if (p_assembly_item_id = l_component_id) then
1273 l_bill_or_ps := 2;
1274 else
1275 l_bill_or_ps := 1;
1276 end if;
1277
1278 /* Added for lot based material support
1279 For phantom, we do not use fixed order quantity of the component. We used
1280 the fixed order quantity of top level parent, that is the first non-phantom parent. */
1281 if (l_wip_supply_type = WIP_CONSTANTS.PHANTOM) then
1282 l_comp_foq := p_assy_foq;
1283 end if;
1284
1285 /* Modified for lot based material support.
1286 Push down the fixed order qty (l_comp_foq) to the component. */
1287 l_ret_val := Cascade_Fcst_Demand(
1288 l_bill_or_ps,
1289 TRUE,
1290 p_parent_line_id,
1291 NULL,
1292 p_top_item_id,
1293 l_component_id,
1294 l_cumulative_usage,
1295 l_subinventory,
1296 l_locator_id,
1297 p_demand_type,
1298 p_explode_always,
1299 p_sales_order_demand,
1300 l_comp_foq);
1301
1302 IF g_debug THEN
1303 g_log_message := 'returned from the Cascade_Fcst_Demand call';
1304 MRP_UTIL.MRP_LOG (g_log_message);
1305 END IF;
1306
1307 IF NOT l_ret_val THEN
1308 RETURN FALSE;
1309 END IF;
1310
1311 END IF;
1312
1313 END LOOP;
1314
1315 IF component_cursor1%ISOPEN THEN
1316 CLOSE component_cursor1;
1317 END IF;
1318 IF component_cursor2%ISOPEN THEN
1319 CLOSE component_cursor2;
1320 END IF;
1321
1322 RETURN TRUE;
1323
1324 --exception handling
1325
1326 EXCEPTION
1327 WHEN OTHERS THEN
1328 g_log_message := 'Cascade_Fcst_Demand Sql Error ';
1329 MRP_UTIL.MRP_LOG (g_log_message);
1330 g_log_message := sqlerrm;
1331 MRP_UTIL.MRP_LOG (g_log_message);
1332 RETURN FALSE;
1333
1334 END Cascade_Fcst_Demand;
1335
1336 -- ========================================================================
1337 -- This function passes demand down to the components all the way down
1338 -- to the bottom of the bill
1339 -- ========================================================================
1340 FUNCTION Cascade_Ap_Demand (
1341 p_bill_or_ps IN NUMBER,
1342 p_recursive IN BOOLEAN,
1343 p_parent_line_id IN NUMBER,
1344 p_line_id IN NUMBER,
1345 p_top_item_id IN NUMBER,
1346 p_top_alt IN VARCHAR2,
1347 p_assembly_item_id IN NUMBER,
1348 p_alt IN VARCHAR2,
1349 p_cumulative_usage IN NUMBER,
1350 p_subinventory IN VARCHAR2,
1351 p_locator_id IN NUMBER,
1352 p_demand_type IN NUMBER,
1353 p_explode_always IN VARCHAR2,
1354 p_sales_order_demand IN VARCHAR2,
1355 p_assy_foq IN NUMBER )
1356
1357 RETURN BOOLEAN IS
1358
1359 --declare some local variables here
1360 l_bill_or_ps number; -- 1 - bill; 2 - pull sequence
1361
1362 l_component_id number;
1363 l_subinventory varchar2(10);
1364 l_locator_id number;
1365 l_component_usage number;
1366 l_component_yield number;
1367 l_operation_yield number;
1368 l_net_planning_percent number;
1369 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1370 l_planning_factor number;
1371 l_item_num number;
1372 /* End of Update */
1373 l_kanban_item_flag varchar2(1);
1374 l_demand_quantity number;
1375 l_ret_val boolean;
1376 l_cumulative_usage number;
1377
1378 l_running_total_quantity number := 0;
1379 l_schedule_quantity number;
1380 l_schedule_date date;
1381
1382 l_wip_supply_type number;
1383 l_basis_type number;
1384 l_comp_foq number;
1385 l_foq number;
1386
1387 CURSOR parent_schedule_entries IS
1388 SELECT sum(planned_quantity) PQ,
1389 scheduled_completion_date
1390 FROM mrp_kanban_actual_prod_v
1391 WHERE organization_id = g_kanban_info_rec.organization_id
1392 AND scheduled_completion_date between g_kanban_info_rec.start_date AND
1393 g_kanban_info_rec.cutoff_date
1394 AND primary_item_id IN
1395 ( select COMPONENT_ITEM_ID from mrp_low_level_codes
1396 WHERE ORGANIZATION_ID = g_kanban_info_rec.organization_id
1397 AND PLAN_ID = g_kanban_info_rec.kanban_plan_id )
1398 AND primary_item_id = p_top_item_id
1399 AND nvl(alternate_bom_designator, 'NONE') = nvl(p_top_alt, 'NONE')
1400 AND nvl(line_id,0)=nvl(p_parent_line_id,0)
1401 group by scheduled_completion_date,schedule_type,line_id;
1402
1403
1404 -- cursor component_cursor1 is the cursor that passes down demand
1405 -- to the components feeding into a line. Notice that we are driving
1406 -- off of bom_operational_routings
1407 -- also if supply sub and locator are null in bom_inventory_components
1408 -- we get it from wip supply locations from mtl_system_items - this
1409 -- is ok for R-11, though we might have an issue here for R12
1410
1411 CURSOR component_cursor1 IS
1412 SELECT DISTINCT
1413 bic.component_item_id,
1414 decode(bic.supply_subinventory, NULL, msi.wip_supply_subinventory,
1415 bic.supply_subinventory),
1416 decode(bic.supply_subinventory, NULL, msi.wip_supply_locator_id,
1417 bic.supply_locator_id),
1418 bic.component_quantity,
1419 bic.component_yield_factor,
1420 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1421 bic.planning_factor,
1422 bic.item_num,
1423 /* End of Update */
1424 mllc.operation_yield,
1425 mllc.net_planning_percent,
1426 mllc.kanban_item_flag,
1427 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1428 mllc.wip_supply_type,
1429 mllc.basis_type,
1430 nvl(msi.fixed_order_quantity, nvl(msi.minimum_order_quantity, nvl(msi.maximum_order_quantity,1)))
1431 FROM mtl_system_items msi,
1432 mrp_low_level_codes mllc,
1433 bom_inventory_components bic,
1434 bom_bill_of_materials bbom
1435 WHERE
1436 bbom.assembly_item_id = p_assembly_item_id
1437 AND bbom.organization_id = g_kanban_info_rec.organization_id
1438 AND nvl(bbom.alternate_bom_designator, 'NONE') = nvl(p_top_alt, 'NONE')
1439 /* Bug 2279877, not pick up discrete jobs w/o line_id
1440 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_Min_Priority (
1441 bor.assembly_item_id,
1442 bor.organization_id,
1443 bor.line_id,
1444 bor.alternate_routing_designator)
1445 */
1446 /* BUG: 1668867 , Fix for double demand */
1447 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_assy_cfgitem (
1448 p_assembly_item_id,
1449 bic.component_item_id,
1450 g_kanban_info_rec.organization_id)
1451 AND bic.bill_sequence_id = bbom.common_bill_sequence_id
1452 AND nvl(bic.disable_date, g_kanban_info_rec.bom_effectivity + 1)
1453 >= g_kanban_info_rec.bom_effectivity
1454 AND bic.effectivity_date <= g_kanban_info_rec.bom_effectivity
1455 AND NOT EXISTS (
1456 SELECT NULL
1457 FROM bom_inventory_components bic2
1458 WHERE bic2.bill_sequence_id = bic.bill_sequence_id
1459 AND bic2.component_item_id = bic.component_item_id
1460 AND (decode(bic2.implementation_date, null,
1461 bic2.old_component_sequence_id,
1462 bic2.component_sequence_id) =
1463 decode(bic.implementation_date, null,
1464 bic.old_component_sequence_id,
1465 bic.component_sequence_id)
1466 OR bic2.operation_seq_num = bic.operation_seq_num)
1467 AND bic2.effectivity_date <=
1468 g_kanban_info_rec.bom_effectivity
1469 AND bic2.effectivity_date > bic.effectivity_date
1470 AND (bic2.implementation_date is not null OR
1471 (bic2.implementation_date is null AND EXISTS
1472 (SELECT NULL
1473 FROM eng_revised_items eri
1474 WHERE bic2.revised_item_sequence_id =
1475 eri.revised_item_sequence_id
1476 AND eri.mrp_active = 1 ))))
1477 AND (bic.implementation_date is not null OR
1478 (bic.implementation_date is null AND EXISTS
1479 (SELECT NULL
1480 FROM eng_revised_items eri
1481 WHERE bic.revised_item_sequence_id =
1482 eri.revised_item_sequence_id
1483 AND eri.mrp_active = 1 )))
1484 AND mllc.plan_id = g_kanban_info_rec.kanban_plan_id
1485 AND mllc.organization_id = bbom.organization_id
1486 AND mllc.assembly_item_id = bbom.assembly_item_id
1487 AND mllc.component_item_id = bic.component_item_id
1488 AND nvl(mllc.alternate_designator, 'xxx') =
1489 nvl(bbom.alternate_bom_designator, 'xxx')
1490 AND msi.inventory_item_id = mllc.component_item_id
1491 AND msi.organization_id = mllc.organization_id
1492 AND ((nvl(msi.ato_forecast_control, G_NO_FCST_CONTROL) = G_NO_FCST_CONTROL)
1493 OR p_explode_always = 'Y'
1494 OR (p_sales_order_demand = 'Y' AND msi.bom_item_type = 4));
1495
1496 -- cursor component_cursor2 blows down demand to the components
1497 -- as stored in the mrp_low_level_codes table
1498 CURSOR component_cursor2 IS
1499 SELECT DISTINCT
1500 mllc.component_item_id,
1501 mllc.from_subinventory,
1502 mllc.from_locator_id,
1503 mllc.component_usage,
1504 mllc.component_yield,
1505 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1506 mllc.planning_factor,
1507 mllc.item_num,
1508 /* End of Update */
1509 mllc.operation_yield,
1510 mllc.net_planning_percent,
1511 mllc.kanban_item_flag,
1512 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1513 mllc.wip_supply_type,
1514 mllc.basis_type,
1515 nvl(msi.fixed_order_quantity, nvl(msi.minimum_order_quantity, nvl(msi.maximum_order_quantity,1)))
1516 FROM mtl_system_items msi,
1517 mrp_low_level_codes mllc
1518 WHERE mllc.plan_id = g_kanban_info_rec.kanban_plan_id
1519 AND mllc.organization_id + 0 = g_kanban_info_rec.organization_id
1520 AND mllc.assembly_item_id = p_assembly_item_id
1521 AND ((mllc.to_subinventory = p_subinventory
1522 AND nvl(mllc.to_locator_id,-1) = nvl(p_locator_id,-1)) OR
1523 (mllc.to_subinventory is NULL and p_bill_or_ps = 1) )
1524 AND msi.inventory_item_id = mllc.component_item_id
1525 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1526 /* Bug 2279877, not pick up discrete jobs w/o line_id
1527 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_Min_Priority (
1528 mllc.assembly_item_id,
1529 mllc.organization_id,
1530 null,
1531 mllc.alternate_designator)
1532 */
1533 /* End of Update */
1534 /* Bug 1668867 : Double Kanban demand */
1535 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_assy_cfgitem (
1536 p_assembly_item_id,
1537 mllc.component_item_id,
1538 mllc.organization_id)
1539 AND msi.organization_id = mllc.organization_id
1540 AND ((nvl(msi.ato_forecast_control, G_NO_FCST_CONTROL) = G_NO_FCST_CONTROL)
1541 OR p_explode_always = 'Y'
1542 OR (p_sales_order_demand = 'Y' AND msi.bom_item_type = 4));
1543
1544 BEGIN
1545
1546 IF g_debug THEN
1547
1548 g_log_message := 'Entering Cascade_Ap_Demand function';
1549 MRP_UTIL.MRP_LOG (g_log_message);
1550 g_log_message := 'Cascading Demand For : ';
1551 MRP_UTIL.MRP_LOG (g_log_message);
1552 g_log_message := 'Line : ' || to_char(p_line_id);
1553 MRP_UTIL.MRP_LOG (g_log_message);
1554 g_log_message := 'Item : ' || to_char(p_assembly_item_id);
1555 MRP_UTIL.MRP_LOG (g_log_message);
1556 g_log_message := 'Sub : ' || p_subinventory;
1557 MRP_UTIL.MRP_LOG (g_log_message);
1558 g_log_message := 'Loc : ' || p_locator_id;
1559 MRP_UTIL.MRP_LOG (g_log_message);
1560
1561 END IF;
1562
1563
1564 -- Depending on the boolean flag p_recursive, we decide what cursor
1565 -- we want to go after. We know that we will have a line reference
1566 -- on the demand. So, when we call Cacade_Demand the first time, ie
1567 -- to pass down demand to components feeding into the line, then
1568 -- p_recursive is false. We just blow the demand down one level. Once
1569 -- we do that, we call Cascade_Mds_Mps_Demand in the recursive mode with
1570 -- p_recursive set to true when we want to go after mrp_low_level_codes
1571 -- recursively and blow the demand all the way down.
1572
1573 IF NOT p_recursive THEN
1574
1575 IF NOT component_cursor1%ISOPEN THEN
1576 OPEN component_cursor1;
1577 END IF;
1578
1579 ELSE
1580
1581 IF NOT component_cursor2%ISOPEN THEN
1582 OPEN component_cursor2;
1583 END IF;
1584 END IF;
1585
1586 WHILE TRUE LOOP
1587
1588 IF not p_recursive THEN
1589 FETCH component_cursor1
1590 INTO l_component_id,
1591 l_subinventory,
1592 l_locator_id,
1593 l_component_usage,
1594 l_component_yield,
1595 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1596 l_planning_factor,
1597 l_item_num,
1598 /* End of Update */
1599 l_operation_yield,
1600 l_net_planning_percent,
1601 l_kanban_item_flag,
1602 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1603 l_wip_supply_type,
1604 l_basis_type,
1605 l_comp_foq;
1606 EXIT WHEN component_cursor1%NOTFOUND;
1607
1608 ELSE
1609
1610 FETCH component_cursor2
1611 INTO l_component_id,
1612 l_subinventory,
1613 l_locator_id,
1614 l_component_usage,
1615 l_component_yield,
1616 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1617 l_planning_factor,
1618 l_item_num,
1619 /* End of Update */
1620 l_operation_yield,
1621 l_net_planning_percent,
1622 l_kanban_item_flag,
1623 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1624 l_wip_supply_type,
1625 l_basis_type,
1626 l_comp_foq;
1627 EXIT WHEN component_cursor2%NOTFOUND;
1628
1629
1630 END IF;
1631
1632 IF g_debug THEN
1633 g_log_message := 'component_usage is : ' || to_char (l_component_usage);
1634 MRP_UTIL.MRP_LOG (g_log_message);
1635 g_log_message := 'Net_Planning_Percent is : ' ||
1636 to_char (l_net_planning_percent);
1637 MRP_UTIL.MRP_LOG (g_log_message);
1638 g_log_message := 'Operation_Yield is : ' || to_char (l_operation_yield);
1639 MRP_UTIL.MRP_LOG (g_log_message);
1640 g_log_message := 'Component_Yield is : ' || to_char (l_component_yield);
1641 MRP_UTIL.MRP_LOG (g_log_message);
1642 END IF;
1643
1644 -- calculate the demand quantity to be passed down using all the
1645 -- percentages and yields stuff that we've got
1646
1647 IF NOT parent_schedule_entries%ISOPEN THEN
1648 OPEN parent_schedule_entries;
1649 END IF;
1650 WHILE TRUE LOOP
1651
1652 FETCH parent_schedule_entries
1653 INTO l_schedule_quantity,
1654 l_schedule_date;
1655 EXIT WHEN parent_schedule_entries%NOTFOUND;
1656
1657 l_running_total_quantity := l_running_total_quantity + nvl(
1658 l_schedule_quantity,0);
1659
1660 /* Added for lot based material support
1661 The p_assy_foq is the fixed order quantity of the assembly.
1662 It can be either the foq from the item master or it's parent (for phantom assembly).
1663 The p_assy_foq will be used to calculate the component's demand when the
1664 component has lot basis type and the demand is not from the pull sequence chain. */
1665 if (l_basis_type = WIP_CONSTANTS.LOT_BASED_MTL and l_component_id <> p_assembly_item_id) then
1666 l_foq := p_assy_foq;
1667 else
1668 l_foq := 1;
1669 end if;
1670
1671 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1672 /* l_demand_quantity := ROUND((l_schedule_quantity* nvl(l_component_usage, 1) *
1673 nvl(p_cumulative_usage,1)*
1674 (nvl(l_net_planning_percent, 100) /100)) /
1675 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1))); */
1676 l_demand_quantity := ((l_schedule_quantity* nvl(l_component_usage, 1) *
1677 nvl(p_cumulative_usage,1)*
1678 (nvl(l_planning_factor, 100) /100)) /
1679 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1)))/l_foq;
1680 /* End of Update */
1681
1682 IF g_debug THEN
1683 g_log_message := 'Deamnd Quantity:'||to_char(l_demand_quantity);
1684 MRP_UTIL.MRP_LOG (g_log_message);
1685 END IF;
1686
1687 -- now insert the demand into the kanban demand table if its > 0
1688
1689 IF l_demand_quantity > 0 THEN
1690
1691 INSERT INTO MRP_KANBAN_DEMAND (
1692 DEMAND_ID,
1693 KANBAN_PLAN_ID,
1694 ORGANIZATION_ID,
1695 INVENTORY_ITEM_ID,
1696 SUBINVENTORY,
1697 LOCATOR_ID,
1698 ASSEMBLY_ORG_ID,
1699 ASSEMBLY_ITEM_ID,
1700 ASSEMBLY_SUBINVENTORY,
1701 ASSEMBLY_LOCATOR_ID,
1702 DEMAND_DATE,
1703 DEMAND_QUANTITY,
1704 ORDER_TYPE,
1705 KANBAN_ITEM_FLAG,
1706 REQUEST_ID,
1707 PROGRAM_APPLICATION_ID,
1708 PROGRAM_ID,
1709 PROGRAM_UPDATE_DATE,
1710 LAST_UPDATE_DATE,
1711 LAST_UPDATED_BY,
1712 CREATION_DATE,
1713 CREATED_BY )
1714 SELECT
1715 mrp_kanban_demand_s.nextval,
1716 g_kanban_info_rec.kanban_plan_id,
1717 g_kanban_info_rec.organization_id,
1718 l_component_id,
1719 l_subinventory,
1720 l_locator_id,
1721 g_kanban_info_rec.organization_id,
1722 p_assembly_item_id,
1723 p_subinventory,
1724 p_locator_id,
1725 l_schedule_date,
1726 l_demand_quantity,
1727 8,
1728 l_kanban_item_flag,
1729 fnd_global.conc_request_id,
1730 fnd_global.prog_appl_id,
1731 fnd_global.conc_program_id,
1732 sysdate,
1733 sysdate,
1734 fnd_global.user_id,
1735 sysdate,
1736 fnd_global.user_id
1737 FROM
1738 DUAL;
1739
1740 END IF;
1741 END LOOP;-- end of my cursor
1742 IF parent_schedule_entries%ISOPEN THEN
1743 CLOSE parent_schedule_entries;
1744 END IF;
1745
1746 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1747 --l_cumulative_usage := p_cumulative_usage * l_component_usage;
1748 l_cumulative_usage := p_cumulative_usage * l_component_usage * (nvl(l_planning_factor, 100)/100) / l_foq;
1749 /* End of Update */
1750
1751 IF ( l_running_total_quantity > 0) THEN
1752 IF g_debug THEN
1753 g_log_message := 'Calling Cascade_Ap_Demand in recursive mode';
1754 MRP_UTIL.MRP_LOG (g_log_message);
1755 END IF;
1756
1757 if (p_assembly_item_id = l_component_id) then
1758 l_bill_or_ps := 2;
1759 else
1760 l_bill_or_ps := 1;
1761 end if;
1762
1763 /* Added for lot based material support
1764 For phantom, we do not use fixed order quantity of the component. We used
1765 the fixed order quantity of top level parent, that is the first non-phantom parent. */
1766 if (l_wip_supply_type = WIP_CONSTANTS.PHANTOM) then
1767 l_comp_foq := p_assy_foq;
1768 end if;
1769
1770 /* Modified for lot based material support.
1771 Push down the fixed order qty (l_comp_foq) to the component. */
1772 l_ret_val := Cascade_Ap_Demand(
1773 l_bill_or_ps,
1774 TRUE,
1775 p_parent_line_id,
1776 NULL,
1777 p_top_item_id,
1778 p_top_alt,
1779 l_component_id,
1780 null,
1781 l_cumulative_usage,
1782 l_subinventory,
1783 l_locator_id,
1784 p_demand_type,
1785 p_explode_always,
1786 p_sales_order_demand,
1787 l_comp_foq);
1788
1789 IF g_debug THEN
1790 g_log_message := 'returned from the cascade call';
1791 MRP_UTIL.MRP_LOG (g_log_message);
1792 END IF;
1793
1794
1795 IF NOT l_ret_val THEN
1796 RETURN FALSE;
1797 END IF;
1798
1799 END IF;
1800
1801 END LOOP;
1802
1803 IF component_cursor1%ISOPEN THEN
1804 CLOSE component_cursor1;
1805 END IF;
1806 IF component_cursor2%ISOPEN THEN
1807 CLOSE component_cursor2;
1808 END IF;
1809
1810 RETURN TRUE;
1811
1812 --exception handling
1813 EXCEPTION
1814 WHEN OTHERS THEN
1815 g_log_message := 'Cascade_Ap_Demand Sql Error ';
1816 MRP_UTIL.MRP_LOG (g_log_message);
1817 g_log_message := sqlerrm;
1818 MRP_UTIL.MRP_LOG (g_log_message);
1819 RETURN FALSE;
1820
1821 END Cascade_Ap_Demand;
1822
1823
1824 -- ========================================================================
1825 -- This function passes demand down to the components all the way down
1826 -- to the bottom of the bill
1827 -- ========================================================================
1828 FUNCTION Cascade_Mds_Mps_Demand (
1829 p_bill_or_ps IN NUMBER,
1830 p_recursive IN BOOLEAN,
1831 p_parent_line_id IN NUMBER,
1832 p_line_id IN NUMBER,
1833 p_top_item_id IN NUMBER,
1834 p_assembly_item_id IN NUMBER,
1835 p_cumulative_usage IN NUMBER,
1836 p_subinventory IN VARCHAR2,
1837 p_locator_id IN NUMBER,
1838 p_demand_type IN NUMBER,
1839 p_explode_always IN VARCHAR2,
1840 p_sales_order_demand IN VARCHAR2,
1841 p_assy_foq IN NUMBER )
1842 RETURN BOOLEAN IS
1843
1844 --declare some local variables here
1845 l_bill_or_ps number; -- 1 - bill; 2 - pull sequence
1846
1847 l_component_id number;
1848 l_subinventory varchar2(10);
1849 l_locator_id number;
1850 l_component_usage number;
1851 l_component_yield number;
1852 l_operation_yield number;
1853 l_net_planning_percent number;
1854 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1855 l_planning_factor number;
1856 l_item_num number;
1857 /* End of Update */
1858 l_kanban_item_flag varchar2(1);
1859 l_demand_quantity number;
1860 l_ret_val boolean;
1861 l_cumulative_usage number;
1862
1863 l_running_total_quantity number := 0;
1864 l_schedule_quantity number;
1865 l_schedule_date date;
1866
1867 l_wip_supply_type number;
1868 l_basis_type number;
1869 l_comp_foq number;
1870 l_foq number;
1871
1872
1873 CURSOR parent_schedule_entries IS
1874 SELECT
1875 decode(schedule_quantity,NULL,MRP_KANBAN_PLAN_PK.Get_Repetitive_Demand(
1876 schedule_date,rate_end_date,repetitive_daily_rate),schedule_quantity),
1877 schedule_date
1878 FROM mrp_schedule_dates
1879 WHERE organization_id = g_kanban_info_rec.organization_id
1880 AND schedule_designator = g_kanban_info_rec.input_designator
1881 AND schedule_level = 2
1882 AND schedule_date BETWEEN g_kanban_info_rec.start_date AND
1883 g_kanban_info_rec.cutoff_date
1884 AND inventory_item_id = p_top_item_id
1885 AND nvl(line_id,0)=nvl(p_parent_line_id,0)
1886 AND schedule_origination_type = p_demand_type ;
1887
1888
1889 -- cursor component_cursor1 is the cursor that passes down demand
1890 -- to the components feeding into a line. Notice that we are driving
1891 -- off of bom_operational_routings
1892 -- also if supply sub and locator are null in bom_inventory_components
1893 -- we get it from wip supply locations from mtl_system_items - this
1894 -- is ok for R-11, though we might have an issue here for R12
1895
1896 CURSOR component_cursor1 IS
1897 SELECT DISTINCT
1898 bic.component_item_id,
1899 decode(bic.supply_subinventory, NULL, msi.wip_supply_subinventory,
1900 bic.supply_subinventory),
1901 decode(bic.supply_locator_id, NULL, msi.wip_supply_locator_id,
1902 bic.supply_locator_id),
1903 bic.component_quantity,
1904 bic.component_yield_factor,
1905 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1906 bic.planning_factor,
1907 bic.item_num,
1908 /* End of Update */
1909 mllc.operation_yield,
1910 mllc.net_planning_percent,
1911 mllc.kanban_item_flag,
1912 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
1913 mllc.wip_supply_type,
1914 mllc.basis_type,
1915 nvl(msi.fixed_order_quantity, nvl(msi.minimum_order_quantity, nvl(msi.maximum_order_quantity,1)))
1916 FROM mtl_system_items msi,
1917 mrp_low_level_codes mllc,
1918 bom_inventory_components bic,
1919 bom_bill_of_materials bbom,
1920 bom_operational_routings bor,
1921 mtl_parameters mp
1922 WHERE mp.organization_id = g_kanban_info_rec.organization_id
1923 AND bor.line_id (+) = p_line_id
1924 AND bor.assembly_item_id (+) = p_assembly_item_id
1925 AND bor.organization_id (+) = mp.organization_id
1926 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_Min_Priority (
1927 bor.assembly_item_id,
1928 bor.organization_id,
1929 bor.line_id,
1930 bor.alternate_routing_designator)
1931 AND bbom.assembly_item_id = p_assembly_item_id
1932 AND bbom.organization_id = mp.organization_id
1933 AND nvl(bbom.alternate_bom_designator, 'xxx') =
1934 nvl(bor.alternate_routing_designator, 'xxx')
1935 AND bic.bill_sequence_id = bbom.common_bill_sequence_id
1936 AND nvl(bic.disable_date, g_kanban_info_rec.bom_effectivity + 1)
1937 >= g_kanban_info_rec.bom_effectivity
1938 AND bic.effectivity_date <= g_kanban_info_rec.bom_effectivity
1939 /* BUG: 1821216 Double kanban demand */
1940 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_assy_cfgitem (
1941 p_assembly_item_id,
1942 bic.component_item_id,
1943 mp.organization_id)
1944 AND NOT EXISTS (
1945 SELECT NULL
1946 FROM bom_inventory_components bic2
1947 WHERE bic2.bill_sequence_id = bic.bill_sequence_id
1948 AND bic2.component_item_id = bic.component_item_id
1949 AND (decode(bic2.implementation_date, null,
1950 bic2.old_component_sequence_id,
1951 bic2.component_sequence_id) =
1952 decode(bic.implementation_date, null,
1953 bic.old_component_sequence_id,
1954 bic.component_sequence_id)
1955 OR bic2.operation_seq_num = bic.operation_seq_num)
1956 AND bic2.effectivity_date <=
1957 g_kanban_info_rec.bom_effectivity
1958 AND bic2.effectivity_date > bic.effectivity_date
1959 AND (bic2.implementation_date is not null OR
1960 (bic2.implementation_date is null AND EXISTS
1961 (SELECT NULL
1962 FROM eng_revised_items eri
1963 WHERE bic2.revised_item_sequence_id =
1964 eri.revised_item_sequence_id
1965 AND eri.mrp_active = 1 ))))
1966 AND (bic.implementation_date is not null OR
1967 (bic.implementation_date is null AND EXISTS
1968 (SELECT NULL
1969 FROM eng_revised_items eri
1970 WHERE bic.revised_item_sequence_id =
1971 eri.revised_item_sequence_id
1972 AND eri.mrp_active = 1 )))
1973 AND mllc.plan_id = g_kanban_info_rec.kanban_plan_id
1974 AND mllc.organization_id = bbom.organization_id
1975 AND mllc.assembly_item_id = bbom.assembly_item_id
1976 AND mllc.component_item_id = bic.component_item_id
1977 AND nvl(mllc.alternate_designator, 'xxx') =
1978 nvl(bbom.alternate_bom_designator, 'xxx')
1979 AND msi.inventory_item_id = mllc.component_item_id
1980 AND msi.organization_id = mllc.organization_id
1981 AND ((nvl(msi.ato_forecast_control, G_NO_FCST_CONTROL) = G_NO_FCST_CONTROL)
1982 OR p_explode_always = 'Y'
1983 OR (p_sales_order_demand = 'Y' AND msi.bom_item_type = 4));
1984
1985 -- cursor component_cursor2 blows down demand to the components
1986 -- as stored in the mrp_low_level_codes table
1987 CURSOR component_cursor2 IS
1988 SELECT DISTINCT
1989 mllc.component_item_id,
1990 mllc.from_subinventory,
1991 mllc.from_locator_id,
1992 mllc.component_usage,
1993 mllc.component_yield,
1994 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
1995 mllc.planning_factor,
1996 mllc.item_num,
1997 /* End of Update */
1998 mllc.operation_yield,
1999 mllc.net_planning_percent,
2000 mllc.kanban_item_flag,
2001 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
2002 mllc.wip_supply_type,
2003 mllc.basis_type,
2004 nvl(msi.fixed_order_quantity, nvl(msi.minimum_order_quantity, nvl(msi.maximum_order_quantity,1)))
2005 FROM mtl_system_items msi,
2006 mrp_low_level_codes mllc
2007 WHERE mllc.plan_id = g_kanban_info_rec.kanban_plan_id
2008 AND mllc.organization_id + 0 = g_kanban_info_rec.organization_id
2009 AND mllc.assembly_item_id = p_assembly_item_id
2010 AND ((mllc.to_subinventory = p_subinventory
2011 AND nvl(mllc.to_locator_id,-1) = nvl(p_locator_id,-1)) OR
2012 (mllc.to_subinventory is NULL and p_bill_or_ps = 1) )
2013 /* Bug 1668867 : Double Kanban demand */
2014 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_assy_cfgitem (
2015 p_assembly_item_id,
2016 mllc.component_item_id,
2017 mllc.organization_id)
2018 AND msi.inventory_item_id = mllc.component_item_id
2019 AND msi.organization_id = mllc.organization_id
2020 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
2021 AND 1 = MRP_KANBAN_SNAPSHOT_PK.Check_Min_Priority (
2022 mllc.assembly_item_id,
2023 mllc.organization_id,
2024 null,
2025 mllc.alternate_designator)
2026 /* End of Update */
2027 AND ((nvl(msi.ato_forecast_control, G_NO_FCST_CONTROL) = G_NO_FCST_CONTROL)
2028 OR p_explode_always = 'Y'
2029 OR (p_sales_order_demand = 'Y' AND msi.bom_item_type = 4));
2030
2031 BEGIN
2032
2033 IF g_debug THEN
2034
2035 g_log_message := 'Entering Cascade_Mds_Mps_Demand function';
2036 MRP_UTIL.MRP_LOG (g_log_message);
2037 g_log_message := 'Cascading Demand For : ';
2038 MRP_UTIL.MRP_LOG (g_log_message);
2039 g_log_message := 'Line : ' || to_char(p_line_id);
2040 MRP_UTIL.MRP_LOG (g_log_message);
2041 g_log_message := 'Item : ' || to_char(p_assembly_item_id);
2042 MRP_UTIL.MRP_LOG (g_log_message);
2043 g_log_message := 'Sub : ' || p_subinventory;
2044 MRP_UTIL.MRP_LOG (g_log_message);
2045 g_log_message := 'Loc : ' || p_locator_id;
2046 MRP_UTIL.MRP_LOG (g_log_message);
2047
2048
2049 END IF;
2050
2051
2052 -- Depending on the boolean flag p_recursive, we decide what cursor
2053 -- we want to go after. We know that we will have a line reference
2054 -- on the demand. So, when we call Cacade_Demand the first time, ie
2055 -- to pass down demand to components feeding into the line, then
2056 -- p_recursive is false. We just blow the demand down one level. Once
2057 -- we do that, we call Cascade_Mds_Mps_Demand in the recursive mode with
2058 -- p_recursive set to true when we want to go after mrp_low_level_codes
2059 -- recursively and blow the demand all the way down.
2060
2061 IF NOT p_recursive THEN
2062
2063 IF NOT component_cursor1%ISOPEN THEN
2064 OPEN component_cursor1;
2065 END IF;
2066
2067 ELSE
2068
2069 IF NOT component_cursor2%ISOPEN THEN
2070 OPEN component_cursor2;
2071 END IF;
2072 END IF;
2073
2074 WHILE TRUE LOOP
2075
2076 IF not p_recursive THEN
2077 FETCH component_cursor1
2078 INTO l_component_id,
2079 l_subinventory,
2080 l_locator_id,
2081 l_component_usage,
2082 l_component_yield,
2083 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
2084 l_planning_factor,
2085 l_item_num,
2086 /* End of Update */
2087 l_operation_yield,
2088 l_net_planning_percent,
2089 l_kanban_item_flag,
2090 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
2091 l_wip_supply_type,
2092 l_basis_type,
2093 l_comp_foq;
2094 EXIT WHEN component_cursor1%NOTFOUND;
2095
2096 ELSE
2097
2098 FETCH component_cursor2
2099 INTO l_component_id,
2100 l_subinventory,
2101 l_locator_id,
2102 l_component_usage,
2103 l_component_yield,
2104 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
2105 l_planning_factor,
2106 l_item_num,
2107 /* End of Update */
2108 l_operation_yield,
2109 l_net_planning_percent,
2110 l_kanban_item_flag,
2111 /* Added for lot based material support. Need to query wip_supply_type, basis_type and fixed_order_qty */
2112 l_wip_supply_type,
2113 l_basis_type,
2114 l_comp_foq;
2115 EXIT WHEN component_cursor2%NOTFOUND;
2116
2117
2118 END IF;
2119
2120 IF g_debug THEN
2121 g_log_message := 'component_usage is : ' || to_char (l_component_usage);
2122 MRP_UTIL.MRP_LOG (g_log_message);
2123 g_log_message := 'Net_Planning_Percent is : ' ||
2124 to_char (l_net_planning_percent);
2125 MRP_UTIL.MRP_LOG (g_log_message);
2126 g_log_message := 'Operation_Yield is : ' || to_char (l_operation_yield);
2127 MRP_UTIL.MRP_LOG (g_log_message);
2128 g_log_message := 'Component_Yield is : ' || to_char (l_component_yield);
2129 MRP_UTIL.MRP_LOG (g_log_message);
2130 END IF;
2131
2132 -- calculate the demand quantity to be passed down using all the
2133 -- percentages and yields stuff that we've got
2134
2135 IF NOT parent_schedule_entries%ISOPEN THEN
2136 OPEN parent_schedule_entries;
2137 END IF;
2138 WHILE TRUE LOOP
2139
2140 FETCH parent_schedule_entries
2141 INTO l_schedule_quantity,
2142 l_schedule_date;
2143 EXIT WHEN parent_schedule_entries%NOTFOUND;
2144
2145 l_running_total_quantity := l_running_total_quantity + nvl(
2146 l_schedule_quantity,0);
2147
2148 /* Added for lot based material support
2149 The p_assy_foq is the fixed order quantity of the assembly.
2150 It can be either the foq from the item master or it's parent (for phantom assembly).
2151 The p_assy_foq will be used to calculate the component's demand when the
2152 component has lot basis type and the demand is not from the pull sequence chain. */
2153 if (l_basis_type = WIP_CONSTANTS.LOT_BASED_MTL and l_component_id <> p_assembly_item_id) then
2154 l_foq := p_assy_foq;
2155 else
2156 l_foq := 1;
2157 end if;
2158
2159 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
2160 /* l_demand_quantity := ROUND((l_schedule_quantity* nvl(l_component_usage, 1) *
2161 nvl(p_cumulative_usage,1)*
2162 (nvl(l_net_planning_percent, 100) /100)) /
2163 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1)));*/
2164 l_demand_quantity := ((l_schedule_quantity* nvl(l_component_usage, 1) *
2165 nvl(p_cumulative_usage,1)*
2166 (nvl(l_planning_factor, 100) /100)) /
2167 (nvl(l_operation_yield, 1) * nvl(l_component_yield, 1)))/l_foq;
2168 /* End of Update */
2169
2170 IF g_debug THEN
2171 g_log_message := 'Deamnd Quantity:'||to_char(l_demand_quantity);
2172 MRP_UTIL.MRP_LOG (g_log_message);
2173 END IF;
2174
2175 -- now insert the demand into the kanban demand table if its > 0
2176
2177 IF l_demand_quantity > 0 THEN
2178
2179 INSERT INTO MRP_KANBAN_DEMAND (
2180 DEMAND_ID,
2181 KANBAN_PLAN_ID,
2182 ORGANIZATION_ID,
2183 INVENTORY_ITEM_ID,
2184 SUBINVENTORY,
2185 LOCATOR_ID,
2186 ASSEMBLY_ORG_ID,
2187 ASSEMBLY_ITEM_ID,
2188 ASSEMBLY_SUBINVENTORY,
2189 ASSEMBLY_LOCATOR_ID,
2190 DEMAND_DATE,
2191 DEMAND_QUANTITY,
2192 ORDER_TYPE,
2193 KANBAN_ITEM_FLAG,
2194 REQUEST_ID,
2195 PROGRAM_APPLICATION_ID,
2196 PROGRAM_ID,
2197 PROGRAM_UPDATE_DATE,
2198 LAST_UPDATE_DATE,
2199 LAST_UPDATED_BY,
2200 CREATION_DATE,
2201 CREATED_BY )
2202 SELECT
2203 mrp_kanban_demand_s.nextval,
2204 g_kanban_info_rec.kanban_plan_id,
2205 g_kanban_info_rec.organization_id,
2206 l_component_id,
2207 l_subinventory,
2208 l_locator_id,
2209 g_kanban_info_rec.organization_id,
2210 p_assembly_item_id,
2211 p_subinventory,
2212 p_locator_id,
2213 l_schedule_date,
2214 l_demand_quantity,
2215 8,
2216 l_kanban_item_flag,
2217 fnd_global.conc_request_id,
2218 fnd_global.prog_appl_id,
2219 fnd_global.conc_program_id,
2220 sysdate,
2221 sysdate,
2222 fnd_global.user_id,
2223 sysdate,
2224 fnd_global.user_id
2225 FROM
2226 DUAL;
2227
2228 END IF;
2229 END LOOP;-- end of my cursor
2230 IF parent_schedule_entries%ISOPEN THEN
2231 CLOSE parent_schedule_entries;
2232 END IF;
2233
2234 /* Updated by Liye Ma 4/30/2001 for bug 1757798 and 1745046*/
2235 --l_cumulative_usage := p_cumulative_usage * l_component_usage;
2236 l_cumulative_usage := p_cumulative_usage * l_component_usage * (nvl(l_planning_factor, 100)/100) / l_foq;
2237 /* End of Update */
2238
2239 IF ( l_running_total_quantity > 0) THEN
2240 IF g_debug THEN
2241 g_log_message := 'Calling Cascade_Mds_Mps_Demand in recursive mode';
2242 MRP_UTIL.MRP_LOG (g_log_message);
2243 END IF;
2244
2245 if (p_assembly_item_id = l_component_id) then
2246 l_bill_or_ps := 2;
2247 else
2248 l_bill_or_ps := 1;
2249 end if;
2250
2251 /* Added for lot based material support
2252 For phantom, we do not use fixed order quantity of the component. We used
2253 the fixed order quantity of top level parent, that is the first non-phantom parent. */
2254 if (l_wip_supply_type = WIP_CONSTANTS.PHANTOM) then
2255 l_comp_foq := p_assy_foq;
2256 end if;
2257
2258 /* Modified for lot based material support.
2259 Push down the fixed order qty (l_comp_foq) to the component. */
2260 l_ret_val := Cascade_Mds_Mps_Demand(
2261 l_bill_or_ps,
2262 TRUE,
2263 p_parent_line_id,
2264 NULL,
2265 p_top_item_id,
2266 l_component_id,
2267 l_cumulative_usage,
2268 l_subinventory,
2269 l_locator_id,
2270 p_demand_type,
2271 p_explode_always,
2272 p_sales_order_demand,
2273 l_comp_foq);
2274
2275 IF g_debug THEN
2276 g_log_message := 'returned from the cascade call';
2277 MRP_UTIL.MRP_LOG (g_log_message);
2278 END IF;
2279
2280
2281 IF NOT l_ret_val THEN
2282 RETURN FALSE;
2283 END IF;
2284
2285 END IF;
2286
2287 END LOOP;
2288
2289 IF component_cursor1%ISOPEN THEN
2290 CLOSE component_cursor1;
2291 END IF;
2292 IF component_cursor2%ISOPEN THEN
2293 CLOSE component_cursor2;
2294 END IF;
2295
2296 RETURN TRUE;
2297
2298 --exception handling
2299 EXCEPTION
2300 WHEN OTHERS THEN
2301 g_log_message := 'Cascade_Mds_Mps_Demand Sql Error ';
2302 MRP_UTIL.MRP_LOG (g_log_message);
2303 g_log_message := sqlerrm;
2304 MRP_UTIL.MRP_LOG (g_log_message);
2305 RETURN FALSE;
2306
2307 END Cascade_Mds_Mps_Demand;
2308
2309 -- ========================================================================
2310 -- this function inserts demand for FORECAST entries and
2311 -- explodes the demand all the way down to the bottom of the bill
2312 -- ========================================================================
2313 FUNCTION Insert_Fcst_Demand(
2314 p_inventory_item_id IN number,
2315 p_demand_type IN number,
2316 p_line_id IN number )
2317 RETURN BOOLEAN IS
2318 l_line_id number;
2319 l_bom_item_type number;
2320 l_ret_val boolean;
2321 l_explode_always VARCHAR2(1) := 'N'; /* This is a very important flag. It
2322 essentially tells us whether to overlook the forecast
2323 control setting on a component item and explode down
2324 the demand in the function Cascade_Fcst_Ap_Demand*/
2325 l_sales_order_demand VARCHAR2(1) := 'N'; /* Again this flag helps us in
2326 deciding whether to explode down demand from an MDS or
2327 not */
2328
2329 l_forecast_quantity number;
2330 l_forecast_date date;
2331 l_rate_end_date date;
2332 l_bucket_type number;
2333 l_origination_type number;
2334 l_foq number;
2335
2336 CURSOR item_schedule_entries IS
2337 SELECT current_forecast_quantity,
2338 forecast_date,
2339 rate_end_date,
2340 bucket_type,
2341 origination_type,
2342 line_id
2343 FROM mrp_forecast_dates
2344 WHERE organization_id = g_kanban_info_rec.organization_id
2345 /*
2346 AND ((forecast_designator = g_kanban_info_rec.input_designator) or
2347 (forecast_designator in ( -- forecast set
2348 select forecast_designator
2349 from mrp_forecast_designators
2350 where forecast_set = g_kanban_info_rec.input_designator)
2351 )
2352 )
2353 */ --bug 5237549
2354 AND FORECAST_DESIGNATOR in (
2355 select g_kanban_info_rec.input_designator from dual
2356 union all
2357 SELECT FORECAST_DESIGNATOR
2358 FROM MRP_FORECAST_DESIGNATORS
2359 WHERE FORECAST_SET = g_kanban_info_rec.input_designator )
2360 AND inventory_item_id = p_inventory_item_id
2361 AND origination_type = p_demand_type
2362 AND nvl(line_id,0) = nvl(p_line_id,0)
2363 AND ((rate_end_date IS NULL AND
2364 forecast_date BETWEEN Get_Offset_Date(
2365 g_kanban_info_rec.start_date,
2366 bucket_type )
2367 AND g_kanban_info_rec.cutoff_date) OR
2368 (rate_end_date is NOT NULL AND NOT
2369 (rate_end_date < Get_Offset_Date(
2370 g_kanban_info_rec.start_date,
2371 bucket_type ) OR
2372 forecast_date > g_kanban_info_rec.cutoff_date)));
2373
2374 BEGIN
2375
2376 IF g_debug THEN
2377 g_log_message := 'Inserting Demand For :';
2378 MRP_UTIL.MRP_LOG (g_log_message);
2379 g_log_message := 'Item : ' || to_char(p_inventory_item_id) ;
2380 MRP_UTIL.MRP_LOG (g_log_message);
2381 g_log_message := 'Line Reference :' || to_char(p_line_id);
2382 MRP_UTIL.MRP_LOG (g_log_message);
2383 END IF;
2384
2385 g_stmt_num := 170;
2386 IF g_debug THEN
2387 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
2388 MRP_UTIL.MRP_LOG (g_log_message);
2389 END IF;
2390
2391 -- the first insert here is for the item for which we have
2392 -- foreacast based on the allocation percentages mentioned
2393 -- in the mtl_kanban_pull_sequences table
2394
2395 IF NOT item_schedule_entries%ISOPEN THEN
2396 OPEN item_schedule_entries;
2397 END IF;
2398
2399 WHILE TRUE LOOP
2400
2401 FETCH item_schedule_entries
2402 INTO l_forecast_quantity,
2403 l_forecast_date,
2404 l_rate_end_date,
2405 l_bucket_type,
2406 l_origination_type,
2407 l_line_id;
2408 EXIT WHEN item_schedule_entries%NOTFOUND;
2409
2410 IF (l_line_id is NULL) THEN
2411 Begin
2412 SELECT line_id
2413 INTO l_line_id
2414 FROM bom_operational_routings
2415 WHERE alternate_routing_designator is NULL
2416 AND assembly_item_id = p_inventory_item_id
2417 AND organization_id = g_kanban_info_rec.organization_id;
2418 Exception
2419 When Others Then
2420 Null;
2421 End;
2422 END IF;
2423 IF g_debug THEN
2424 g_log_message := 'demand quantity:'||to_char(l_forecast_quantity);
2425 MRP_UTIL.MRP_LOG (g_log_message);
2426 g_log_message := 'demand date:'||to_char(l_forecast_date);
2427 MRP_UTIL.MRP_LOG (g_log_message);
2428 END IF;
2429
2430 IF l_rate_end_date IS NULL THEN
2431 -- not a repetitive forecast - simple processing
2432
2433 IF l_bucket_type = 2 OR l_bucket_type = 3 THEN
2434 --Call the pro-rating function
2435 IF NOT Get_Prorated_Demand (
2436 l_bucket_type,
2437 l_forecast_date,
2438 l_rate_end_date,
2439 l_forecast_quantity,
2440 l_forecast_date,
2441 l_forecast_quantity) THEN
2442 RETURN FALSE;
2443 END IF;
2444 END IF;
2445
2446 INSERT INTO MRP_KANBAN_DEMAND (
2447 DEMAND_ID,
2448 KANBAN_PLAN_ID,
2449 ORGANIZATION_ID,
2450 INVENTORY_ITEM_ID,
2451 SUBINVENTORY,
2452 LOCATOR_ID,
2453 ASSEMBLY_ITEM_ID,
2454 ASSEMBLY_ORG_ID,
2455 ASSEMBLY_SUBINVENTORY,
2456 ASSEMBLY_LOCATOR_ID,
2457 DEMAND_DATE,
2458 DEMAND_QUANTITY,
2459 ORDER_TYPE,
2460 KANBAN_ITEM_FLAG,
2461 REQUEST_ID,
2462 PROGRAM_APPLICATION_ID,
2463 PROGRAM_ID,
2464 PROGRAM_UPDATE_DATE,
2465 LAST_UPDATE_DATE,
2466 LAST_UPDATED_BY,
2467 CREATION_DATE,
2468 CREATED_BY )
2469 SELECT
2470 mrp_kanban_demand_s.nextval,
2471 g_kanban_info_rec.kanban_plan_id,
2472 g_kanban_info_rec.organization_id,
2473 p_inventory_item_id,
2474 ps.subinventory_name,
2475 ps.locator_id,
2476 NULL,
2477 NULL,
2478 NULL,
2479 NULL,
2480 l_forecast_date,
2481 (NVL(ps.allocation_percent, 100) *
2482 l_forecast_quantity/ 100),
2483 l_origination_type,
2484 'Y',
2485 fnd_global.conc_request_id,
2486 fnd_global.prog_appl_id,
2487 fnd_global.conc_program_id,
2488 sysdate,
2489 sysdate,
2490 fnd_global.user_id,
2491 sysdate,
2492 fnd_global.user_id
2493 FROM
2494 mtl_kanban_pull_sequences ps
2495 WHERE ps.wip_line_id = l_line_id
2496 AND ps.source_type = G_PRODUCTION_SOURCE_TYPE
2497 AND ps.kanban_plan_id = decode (g_kanban_info_rec.replan_flag,
2498 2, G_PRODUCTION_KANBAN,
2499 1, g_kanban_info_rec.kanban_plan_id,
2500 G_PRODUCTION_KANBAN)
2501 AND ps.inventory_item_id = p_inventory_item_id
2502 AND ps.organization_id = g_kanban_info_rec.organization_id;
2503
2504
2505 ELSIF l_rate_end_date IS NOT NULL THEN
2506
2507 -- this is repetitive forecast entry - needs explosion of forecast
2508 -- call the function that explodes repetitive foreast demand
2509 l_ret_val := Explode_Repetitive_Forecast (
2510 p_inventory_item_id,
2511 l_forecast_quantity,
2512 l_forecast_date,
2513 l_rate_end_date,
2514 l_bucket_type,
2515 l_origination_type,
2516 l_line_id,
2517 NULL,
2518 NULL,
2519 NULL,
2520 NULL,
2521 NULL,
2522 NULL,
2523 TRUE);
2524 IF NOT l_ret_val THEN
2525 return FALSE;
2526 END IF;
2527 END IF;
2528
2529 END LOOP; -- loop for my cursor
2530 IF item_schedule_entries%ISOPEN THEN
2531 CLOSE item_schedule_entries;
2532 END IF;
2533
2534
2535 -- -------------------------------------------------
2536 -- Pass down the dependent demand for each component
2537 -- By calling the recusive function
2538 -- First the demand flows to the components that are
2539 -- supplying to the line on which we have the demand
2540 -- and as we follow through our recursion process
2541 -- the demand flows to the components all the way
2542 -- to the bottom of the bill
2543 -- -------------------------------------------------
2544
2545 g_stmt_num := 175;
2546 IF g_debug THEN
2547 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
2548 MRP_UTIL.MRP_LOG (g_log_message);
2549 g_log_message := 'Calling Cascade_Fcst_Demand in NON Recursive Mode';
2550 MRP_UTIL.MRP_LOG (g_log_message);
2551 END IF;
2552
2553 -- Before we call the function Cascade_Fcst_Demand,
2554 -- we need to set the flags
2555 -- l_explode_always and l_sales_order_demand.
2556 -- Setting l_sales_order demand is very straight forward.
2557 -- l_explode_always is set to TRUE if the demand_type is Manual for
2558 -- either forecast or schedule inputs or if the item type is 'Standard'
2559
2560 l_sales_order_demand := 'N';
2561
2562 -- check to see if we are dealing with a standard item
2563 SELECT bom_item_type,
2564 nvl(fixed_order_quantity, nvl(minimum_order_quantity, nvl(maximum_order_quantity,1)))
2565 INTO l_bom_item_type,
2566 l_foq
2567 FROM mtl_system_items
2568 WHERE inventory_item_id = p_inventory_item_id
2569 AND organization_id = g_kanban_info_rec.organization_id;
2570
2571 IF p_demand_type = 1 OR l_bom_item_type = 4 THEN
2572 l_explode_always := 'Y';
2573 ELSE
2574 l_explode_always := 'N';
2575 END IF;
2576
2577 l_ret_val := Cascade_Fcst_Demand(
2578 1,
2579 FALSE,
2580 p_line_id,
2581 l_line_id,
2582 p_inventory_item_id,
2583 p_inventory_item_id,
2584 1,
2585 NULL,
2586 NULL,
2587 p_demand_type,
2588 l_explode_always,
2589 l_sales_order_demand,
2590 l_foq);
2591
2592 IF NOT l_ret_val THEN
2593 RETURN FALSE;
2594 END IF;
2595
2596 RETURN TRUE;
2597
2598 --exception handling
2599 EXCEPTION
2600 WHEN OTHERS THEN
2601 g_log_message := 'INSERT_FCST_DEMAND Sql Error ';
2602 MRP_UTIL.MRP_LOG (g_log_message);
2603 g_log_message := sqlerrm;
2604 MRP_UTIL.MRP_LOG (g_log_message);
2605 RETURN FALSE;
2606
2607 END Insert_Fcst_Demand;
2608
2609
2610 -- ========================================================================
2611 -- this function inserts demand for Acutal Production entries and explodes
2612 -- the demand all the way down to the bottom of the bill
2613 -- ========================================================================
2614 FUNCTION Insert_Ap_Demand(
2615 p_inventory_item_id IN number,
2616 p_alt_bom IN varchar,
2617 p_line_id IN number )
2618 RETURN BOOLEAN IS
2619
2620 l_item_id number;
2621 l_schedule_quantity number;
2622 l_schedule_date date;
2623 l_schedule_type number;
2624 l_line_id number;
2625 l_bom_item_type number;
2626 l_ret_val boolean;
2627 l_explode_always VARCHAR2(1) := 'N'; /* This is a very important flag. It
2628 essentially tells us whether to overlook the forecast
2629 control setting on a component item and explode down
2630 the demand in the function Cascade_Mds_Mps_Demand*/
2631 l_sales_order_demand VARCHAR2(1) := 'N'; /* Again this flag helps us in
2632 deciding whether to explode down demand from an MDS or
2633 not */
2634 l_foq number;
2635
2636 CURSOR item_schedule_entries IS
2637 SELECT sum(planned_quantity) PQ,
2638 scheduled_completion_date,
2639 schedule_type,
2640 line_id
2641 FROM mrp_kanban_actual_prod_v
2642 WHERE organization_id = g_kanban_info_rec.organization_id
2643 AND scheduled_completion_date between g_kanban_info_rec.start_date AND
2644 g_kanban_info_rec.cutoff_date
2645 AND primary_item_id IN
2646 ( select COMPONENT_ITEM_ID from mrp_low_level_codes
2647 WHERE ORGANIZATION_ID = g_kanban_info_rec.organization_id
2648 AND PLAN_ID = g_kanban_info_rec.kanban_plan_id )
2649 AND primary_item_id = p_inventory_item_id
2650 AND nvl(alternate_bom_designator, 'NONE') = nvl(p_alt_bom , 'NONE')
2651 AND nvl(line_id,0)=nvl(p_line_id,0)
2652 group by scheduled_completion_date,schedule_type,line_id;
2653
2654 BEGIN
2655 -- ---------------------------------------------
2656 -- Attribute the independent demand using
2657 -- allocation percent to the completion sub s
2658 -- as maintained in the pull sequences table
2659 -- ---------------------------------------------
2660
2661 IF g_debug THEN
2662 g_log_message := 'Inserting Demand For :';
2663 MRP_UTIL.MRP_LOG (g_log_message);
2664 g_log_message := 'Item : ' || to_char(p_inventory_item_id) ;
2665 MRP_UTIL.MRP_LOG (g_log_message);
2666 g_log_message := 'Alternate : ' || p_alt_bom ;
2667 MRP_UTIL.MRP_LOG (g_log_message);
2668 g_log_message := 'Line Reference :' || to_char(p_line_id);
2669 MRP_UTIL.MRP_LOG (g_log_message);
2670 END IF;
2671
2672 g_stmt_num := 170;
2673 IF g_debug THEN
2674 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
2675 MRP_UTIL.MRP_LOG (g_log_message);
2676 END IF;
2677
2678 -- the first insert here is for the item for which we have
2679 -- mds/mps based on the allocation percentages mentioned
2680 -- in the mtl_kanban_pull_sequences table
2681
2682 l_item_id := p_inventory_item_id;
2683 IF NOT item_schedule_entries%ISOPEN THEN
2684 OPEN item_schedule_entries;
2685 END IF;
2686
2687 WHILE TRUE LOOP
2688
2689 FETCH item_schedule_entries
2690 INTO l_schedule_quantity,
2691 l_schedule_date,
2692 l_schedule_type,
2693 l_line_id;
2694 EXIT WHEN item_schedule_entries%NOTFOUND;
2695
2696 IF g_debug THEN
2697 g_log_message := 'demand quantity:'||to_char(l_schedule_quantity);
2698 MRP_UTIL.MRP_LOG (g_log_message);
2699 g_log_message := 'demand date:'||to_char(l_schedule_date);
2700 MRP_UTIL.MRP_LOG (g_log_message);
2701 END IF;
2702
2703 /* Bug 2279877, we allow null-line for discrete and not get line from primary rtg
2704 IF (l_line_id is NULL) THEN
2705 Begin
2706 SELECT line_id
2707 INTO l_line_id
2708 FROM bom_operational_routings
2709 WHERE alternate_routing_designator is NULL
2710 AND assembly_item_id = p_inventory_item_id
2711 AND organization_id = g_kanban_info_rec.organization_id;
2712 Exception
2713 When Others Then
2714 Null;
2715 End;
2716 END IF;
2717 */
2718
2719 INSERT INTO MRP_KANBAN_DEMAND (
2720 DEMAND_ID,
2721 KANBAN_PLAN_ID,
2722 ORGANIZATION_ID,
2723 INVENTORY_ITEM_ID,
2724 SUBINVENTORY,
2725 LOCATOR_ID,
2726 ASSEMBLY_ITEM_ID,
2727 ASSEMBLY_ORG_ID,
2728 ASSEMBLY_SUBINVENTORY,
2729 ASSEMBLY_LOCATOR_ID,
2730 DEMAND_DATE,
2731 DEMAND_QUANTITY,
2732 ORDER_TYPE,
2733 KANBAN_ITEM_FLAG,
2734 REQUEST_ID,
2735 PROGRAM_APPLICATION_ID,
2736 PROGRAM_ID,
2737 PROGRAM_UPDATE_DATE,
2738 LAST_UPDATE_DATE,
2739 LAST_UPDATED_BY,
2740 CREATION_DATE,
2741 CREATED_BY )
2742 SELECT
2743 mrp_kanban_demand_s.nextval,
2744 g_kanban_info_rec.kanban_plan_id,
2745 g_kanban_info_rec.organization_id,
2746 p_inventory_item_id,
2747 ps.subinventory_name,
2748 ps.locator_id,
2749 NULL,
2750 NULL,
2751 NULL,
2752 NULL,
2753 l_schedule_date,
2754 (NVL(ps.allocation_percent, 100) *
2755 l_schedule_quantity/ 100),
2756 l_schedule_type,
2757 'Y',
2758 fnd_global.conc_request_id,
2759 fnd_global.prog_appl_id,
2760 fnd_global.conc_program_id,
2761 sysdate,
2762 sysdate,
2763 fnd_global.user_id,
2764 sysdate,
2765 fnd_global.user_id
2766 FROM
2767 mtl_kanban_pull_sequences ps
2768 WHERE ps.wip_line_id = l_line_id
2769 AND ps.source_type = G_PRODUCTION_SOURCE_TYPE
2770 AND ps.kanban_plan_id = decode (g_kanban_info_rec.replan_flag,
2771 2, G_PRODUCTION_KANBAN,
2772 1, g_kanban_info_rec.kanban_plan_id,
2773 G_PRODUCTION_KANBAN)
2774 AND ps.inventory_item_id = p_inventory_item_id
2775 AND ps.organization_id = g_kanban_info_rec.organization_id;
2776
2777 END LOOP; -- loop for my cursor
2778 IF item_schedule_entries%ISOPEN THEN
2779 CLOSE item_schedule_entries;
2780 END IF;
2781
2782 -- -------------------------------------------------
2783 -- Pass down the dependent demand for each component
2784 -- By calling the recusive function
2785 -- First the demand flows to the components that are
2786 -- supplying to the line on which we have the demand
2787 -- and as we follow through our recursion process
2788 -- the demand flows to the components all the way
2789 -- to the bottom of the bill
2790 -- -------------------------------------------------
2791
2792 g_stmt_num := 175;
2793 IF g_debug THEN
2794 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
2795 MRP_UTIL.MRP_LOG (g_log_message);
2796 g_log_message := 'Calling Cascade_Ap_Demand in NON Recursive Mode';
2797 MRP_UTIL.MRP_LOG (g_log_message);
2798 END IF;
2799
2800 -- Before we call the function Cascade_Ap_Demand,
2801 -- we need to set the flags
2802 -- l_explode_always and l_sales_order_demand.
2803 -- Setting l_sales_order demand is very straight forward.
2804
2805 l_sales_order_demand := 'N';
2806
2807 -- check to see if we are dealing with a standard item
2808 SELECT bom_item_type,
2809 nvl(fixed_order_quantity, nvl(minimum_order_quantity, nvl(maximum_order_quantity,1)))
2810 INTO l_bom_item_type,
2811 l_foq
2812 FROM mtl_system_items
2813 WHERE inventory_item_id = p_inventory_item_id
2814 AND organization_id = g_kanban_info_rec.organization_id;
2815
2816 l_explode_always := 'Y';
2817
2818 l_ret_val := Cascade_Ap_Demand(
2819 1,
2820 FALSE,
2821 p_line_id,
2822 l_line_id,
2823 p_inventory_item_id,
2824 p_alt_bom,
2825 p_inventory_item_id,
2826 p_alt_bom,
2827 1,
2828 NULL,
2829 NULL,
2830 l_schedule_type,
2831 l_explode_always,
2832 l_sales_order_demand,
2833 l_foq);
2834
2835 IF NOT l_ret_val THEN
2836 RETURN FALSE;
2837 END IF;
2838
2839 RETURN TRUE;
2840
2841 --exception handling
2842 EXCEPTION
2843 WHEN OTHERS THEN
2844 g_log_message := 'INSERT_AP_DEMAND Sql Error ';
2845 MRP_UTIL.MRP_LOG (g_log_message);
2846 g_log_message := sqlerrm;
2847 MRP_UTIL.MRP_LOG (g_log_message);
2848 RETURN FALSE;
2849
2850 END Insert_Ap_Demand;
2851
2852 -- ========================================================================
2853 -- this function inserts demand for MDS/MPS entries and explodes
2854 -- the demand all the way down to the bottom of the bill
2855 -- ========================================================================
2856 FUNCTION Insert_Mds_Mps_Demand(
2857 p_inventory_item_id IN number,
2858 p_demand_type IN number,
2859 p_line_id IN number )
2860 RETURN BOOLEAN IS
2861 l_item_id number;
2862 l_schedule_quantity number;
2863 l_schedule_date date;
2864 l_schedule_origination_type number;
2865 l_line_id number;
2866 l_bom_item_type number;
2867 l_ret_val boolean;
2868 l_explode_always VARCHAR2(1) := 'N'; /* This is a very important flag. It
2869 essentially tells us whether to overlook the forecast
2870 control setting on a component item and explode down
2871 the demand in the function Cascade_Mds_Mps_Demand*/
2872 l_sales_order_demand VARCHAR2(1) := 'N'; /* Again this flag helps us in
2873 deciding whether to explode down demand from an MDS or
2874 not */
2875 l_foq number;
2876
2877 CURSOR item_schedule_entries IS
2878 SELECT
2879 decode(schedule_quantity,NULL,MRP_KANBAN_PLAN_PK.Get_Repetitive_Demand(
2880 schedule_date,rate_end_date,repetitive_daily_rate),schedule_quantity),
2881 schedule_date,
2882 schedule_origination_type,
2883 line_id
2884 FROM mrp_schedule_dates
2885 WHERE organization_id = g_kanban_info_rec.organization_id
2886 AND schedule_designator = g_kanban_info_rec.input_designator
2887 AND schedule_level = 2
2888 AND schedule_date BETWEEN g_kanban_info_rec.start_date AND
2889 g_kanban_info_rec.cutoff_date
2890 AND inventory_item_id = p_inventory_item_id
2891 AND nvl(line_id,0)=nvl(p_line_id,0)
2892 AND schedule_origination_type = p_demand_type ;
2893
2894
2895
2896 BEGIN
2897 -- ---------------------------------------------
2898 -- Attribute the independent demand using
2899 -- allocation percent to the completion sub s
2900 -- as maintained in the pull sequences table
2901 -- ---------------------------------------------
2902
2903 IF g_debug THEN
2904 g_log_message := 'Inserting Demand For :';
2905 MRP_UTIL.MRP_LOG (g_log_message);
2906 g_log_message := 'Item : ' || to_char(p_inventory_item_id) ;
2907 MRP_UTIL.MRP_LOG (g_log_message);
2908 g_log_message := 'Line Reference :' || to_char(p_line_id);
2909 MRP_UTIL.MRP_LOG (g_log_message);
2910 END IF;
2911
2912 g_stmt_num := 170;
2913 IF g_debug THEN
2914 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
2915 MRP_UTIL.MRP_LOG (g_log_message);
2916 END IF;
2917
2918 -- the first insert here is for the item for which we have
2919 -- mds/mps based on the allocation percentages mentioned
2920 -- in the mtl_kanban_pull_sequences table
2921
2922 l_item_id := p_inventory_item_id;
2923 IF NOT item_schedule_entries%ISOPEN THEN
2924 OPEN item_schedule_entries;
2925 END IF;
2926
2927 WHILE TRUE LOOP
2928
2929 FETCH item_schedule_entries
2930 INTO l_schedule_quantity,
2931 l_schedule_date,
2932 l_schedule_origination_type,
2933 l_line_id;
2934 EXIT WHEN item_schedule_entries%NOTFOUND;
2935
2936 IF g_debug THEN
2937 g_log_message := 'demand quantity:'||to_char(l_schedule_quantity);
2938 MRP_UTIL.MRP_LOG (g_log_message);
2939 g_log_message := 'demand date:'||to_char(l_schedule_date);
2940 MRP_UTIL.MRP_LOG (g_log_message);
2941 END IF;
2942
2943 IF (l_line_id is NULL) THEN
2944 Begin
2945 SELECT line_id
2946 INTO l_line_id
2947 FROM bom_operational_routings
2948 WHERE alternate_routing_designator is NULL
2949 AND assembly_item_id = p_inventory_item_id
2950 AND organization_id = g_kanban_info_rec.organization_id;
2951 Exception
2952 When Others Then
2953 Null;
2954 End;
2955 END IF;
2956
2957 INSERT INTO MRP_KANBAN_DEMAND (
2958 DEMAND_ID,
2959 KANBAN_PLAN_ID,
2960 ORGANIZATION_ID,
2961 INVENTORY_ITEM_ID,
2962 SUBINVENTORY,
2963 LOCATOR_ID,
2964 ASSEMBLY_ITEM_ID,
2965 ASSEMBLY_ORG_ID,
2966 ASSEMBLY_SUBINVENTORY,
2967 ASSEMBLY_LOCATOR_ID,
2968 DEMAND_DATE,
2969 DEMAND_QUANTITY,
2970 ORDER_TYPE,
2971 KANBAN_ITEM_FLAG,
2972 REQUEST_ID,
2973 PROGRAM_APPLICATION_ID,
2974 PROGRAM_ID,
2975 PROGRAM_UPDATE_DATE,
2976 LAST_UPDATE_DATE,
2977 LAST_UPDATED_BY,
2978 CREATION_DATE,
2979 CREATED_BY )
2980 SELECT
2981 mrp_kanban_demand_s.nextval,
2982 g_kanban_info_rec.kanban_plan_id,
2983 g_kanban_info_rec.organization_id,
2984 p_inventory_item_id,
2985 ps.subinventory_name,
2986 ps.locator_id,
2987 NULL,
2988 NULL,
2989 NULL,
2990 NULL,
2991 l_schedule_date,
2992 (NVL(ps.allocation_percent, 100) *
2993 l_schedule_quantity/ 100),
2994 l_schedule_origination_type,
2995 'Y',
2996 fnd_global.conc_request_id,
2997 fnd_global.prog_appl_id,
2998 fnd_global.conc_program_id,
2999 sysdate,
3000 sysdate,
3001 fnd_global.user_id,
3002 sysdate,
3003 fnd_global.user_id
3004 FROM
3005 mtl_kanban_pull_sequences ps
3006 WHERE ps.wip_line_id = l_line_id
3007 AND ps.source_type = G_PRODUCTION_SOURCE_TYPE
3008 AND ps.kanban_plan_id = decode (g_kanban_info_rec.replan_flag,
3009 2, G_PRODUCTION_KANBAN,
3010 1, g_kanban_info_rec.kanban_plan_id,
3011 G_PRODUCTION_KANBAN)
3012 AND ps.inventory_item_id = p_inventory_item_id
3013 AND ps.organization_id = g_kanban_info_rec.organization_id;
3014
3015 END LOOP; -- loop for my cursor
3016 IF item_schedule_entries%ISOPEN THEN
3017 CLOSE item_schedule_entries;
3018 END IF;
3019
3020 -- -------------------------------------------------
3021 -- Pass down the dependent demand for each component
3022 -- By calling the recusive function
3023 -- First the demand flows to the components that are
3024 -- supplying to the line on which we have the demand
3025 -- and as we follow through our recursion process
3026 -- the demand flows to the components all the way
3027 -- to the bottom of the bill
3028 -- -------------------------------------------------
3029
3030 g_stmt_num := 175;
3031 IF g_debug THEN
3032 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
3033 MRP_UTIL.MRP_LOG (g_log_message);
3034 g_log_message := 'Calling Cascade_Mds_Mps_Demand in NON Recursive Mode';
3035 MRP_UTIL.MRP_LOG (g_log_message);
3036 END IF;
3037
3038 -- Before we call the function Cascade_Mds_Mps_Demand,
3039 -- we need to set the flags
3040 -- l_explode_always and l_sales_order_demand.
3041 -- Setting l_sales_order demand is very straight forward.
3042 -- l_explode_always is set to TRUE if the demand_type is Manual for
3043 -- either forecast or schedule inputs or if the item type is 'Standard'
3044
3045 IF ((g_kanban_info_rec.input_type = 2 OR
3046 g_kanban_info_rec.input_type = 3) AND p_demand_type = 3) THEN
3047 l_sales_order_demand := 'Y';
3048 ELSE
3049 l_sales_order_demand := 'N';
3050 END IF;
3051
3052 -- check to see if we are dealing with a standard item
3053 SELECT bom_item_type,
3054 nvl(fixed_order_quantity, nvl(minimum_order_quantity, nvl(maximum_order_quantity,1)))
3055 INTO l_bom_item_type,
3056 l_foq
3057 FROM mtl_system_items
3058 WHERE inventory_item_id = p_inventory_item_id
3059 AND organization_id = g_kanban_info_rec.organization_id;
3060
3061 IF p_demand_type = 1 OR l_bom_item_type = 4 THEN
3062 l_explode_always := 'Y';
3063 ELSE
3064 l_explode_always := 'N';
3065 END IF;
3066
3067 l_ret_val := Cascade_Mds_Mps_Demand(
3068 1,
3069 FALSE,
3070 p_line_id,
3071 l_line_id,
3072 p_inventory_item_id,
3073 p_inventory_item_id,
3074 1,
3075 NULL,
3076 NULL,
3077 p_demand_type,
3078 l_explode_always,
3079 l_sales_order_demand,
3080 l_foq);
3081
3082 IF NOT l_ret_val THEN
3083 RETURN FALSE;
3084 END IF;
3085
3086 RETURN TRUE;
3087
3088 --exception handling
3089 EXCEPTION
3090 WHEN OTHERS THEN
3091 g_log_message := 'INSERT_DEMAND Sql Error ';
3092 MRP_UTIL.MRP_LOG (g_log_message);
3093 g_log_message := sqlerrm;
3094 MRP_UTIL.MRP_LOG (g_log_message);
3095 RETURN FALSE;
3096
3097 END Insert_Mds_Mps_Demand;
3098
3099
3100 -- ========================================================================
3101 -- This function gets the offset start date to be considered when we look
3102 -- at forecast demand. for example a weekly forecast demand might have
3103 -- a start date 2 days before our kanban start date and we would have to
3104 -- consider a part of this forecast demand for our kanban calculation, else
3105 -- we would be underestimating our demand
3106 -- ========================================================================
3107 FUNCTION Get_Offset_Date (
3108 p_start_date IN date,
3109 p_bucket_type IN NUMBER
3110 )
3111 RETURN DATE IS
3112
3113 l_offset_date date;
3114
3115 BEGIN
3116
3117 IF p_bucket_type = 1 THEN
3118 -- no offsetting here
3119 l_offset_date := p_start_date;
3120
3121 ELSIF p_bucket_type = 2 THEN
3122
3123 SELECT /*+ first_rows */ bw.week_start_date --bug 5237549
3124 INTO l_offset_date
3125 FROM bom_cal_week_start_dates bw,
3126 mtl_parameters mp
3127 WHERE mp.organization_id = g_kanban_info_rec.organization_id
3128 AND bw.calendar_code = mp.calendar_code
3129 AND bw.exception_set_id = mp.calendar_exception_set_id
3130 AND bw.week_start_date <= p_start_date
3131 AND bw.next_date >= p_start_date;
3132
3133 ELSIF p_bucket_type = 3 THEN
3134
3135 SELECT bp.period_start_date
3136 INTO l_offset_date
3137 FROM bom_period_start_dates bp,
3138 mtl_parameters mp
3139 WHERE mp.organization_id = g_kanban_info_rec.organization_id
3140 AND bp.calendar_code = mp.calendar_code
3141 AND bp.exception_set_id = mp.calendar_exception_set_id
3142 AND bp.period_start_date <= p_start_date
3143 AND bp.next_date >= p_start_date;
3144
3145 END IF;
3146
3147 RETURN l_offset_date;
3148
3149 EXCEPTION
3150 WHEN OTHERS THEN
3151 RETURN p_start_date;
3152
3153 END Get_Offset_Date;
3154
3155
3156 -- ========================================================================
3157 -- this function retrieves the kanban demand based on the
3158 -- input to the kanban plan and passes it down to the components
3159 -- as in the mrp_low_level_codes table
3160 -- ========================================================================
3161 FUNCTION Retrieve_Kanban_Demand RETURN BOOLEAN IS
3162
3163 -- declare local variables
3164
3165 l_demand_rec demand_rec_type; -- record that stores demand info
3166 l_rate_end_date date;
3167 l_bucket_type number;
3168 l_line_id number;
3169 l_alt_bom varchar(10);
3170 l_demand_type number;
3171 l_repetitive_forecast boolean := FALSE;
3172 l_ret_val boolean;
3173
3174 -- declare cursors
3175
3176 -- cursor to retrieve forecast entries
3177 CURSOR cur_forecast_entries IS
3178 SELECT inventory_item_id,
3179 origination_type,
3180 line_id
3181 FROM mrp_forecast_dates
3182 WHERE organization_id = g_kanban_info_rec.organization_id
3183 /*
3184 AND ((forecast_designator = g_kanban_info_rec.input_designator) or
3185 (forecast_designator in ( -- forecast set
3186 select forecast_designator
3187 from mrp_forecast_designators
3188 where forecast_set = g_kanban_info_rec.input_designator)
3189 )
3190 )
3191 */ --bug 5237549
3192 AND FORECAST_DESIGNATOR in (
3193 select g_kanban_info_rec.input_designator from dual
3194 union all
3195 SELECT FORECAST_DESIGNATOR
3196 FROM MRP_FORECAST_DESIGNATORS
3197 WHERE FORECAST_SET = g_kanban_info_rec.input_designator )
3198
3199 AND ((rate_end_date IS NULL AND
3200 forecast_date BETWEEN Get_Offset_Date(
3201 g_kanban_info_rec.start_date,
3202 bucket_type )
3203 AND g_kanban_info_rec.cutoff_date) OR
3204 (rate_end_date is NOT NULL AND NOT
3205 (rate_end_date < Get_Offset_Date(
3206 g_kanban_info_rec.start_date,
3207 bucket_type ) OR
3208 forecast_date > g_kanban_info_rec.cutoff_date)))
3209 GROUP BY inventory_item_id,origination_type,line_id;
3210
3211 -- cursor to retrieve MPS/MDS entries
3212 CURSOR cur_schedule_entries IS
3213 SELECT inventory_item_id,
3214 schedule_origination_type,
3215 line_id
3216 FROM mrp_schedule_dates
3217 WHERE organization_id = g_kanban_info_rec.organization_id
3218 AND schedule_designator = g_kanban_info_rec.input_designator
3219 AND schedule_level = 2
3220 AND schedule_date BETWEEN g_kanban_info_rec.start_date AND
3221 g_kanban_info_rec.cutoff_date
3222 GROUP BY inventory_item_id,schedule_origination_type,line_id;
3223
3224 -- cursor to retrieve actual production
3225 CURSOR GetActualProductionDemand IS
3226 SELECT primary_item_id,
3227 alternate_bom_designator,
3228 line_id
3229 FROM mrp_kanban_actual_prod_v
3230 WHERE organization_id = g_kanban_info_rec.organization_id
3231 AND scheduled_completion_date between g_kanban_info_rec.start_date AND
3232 g_kanban_info_rec.cutoff_date
3233 AND primary_item_id IN
3234 ( select COMPONENT_ITEM_ID from mrp_low_level_codes
3235 where ORGANIZATION_ID = g_kanban_info_rec.organization_id
3236 AND PLAN_ID = g_kanban_info_rec.kanban_plan_id )
3237 group by primary_item_id,alternate_bom_designator,line_id;
3238 BEGIN
3239
3240
3241 WHILE TRUE LOOP -- begin demand entries loop
3242
3243 IF g_kanban_info_rec.input_type = 1 THEN
3244 -- input type is a forecast
3245
3246 IF NOT cur_forecast_entries%ISOPEN THEN
3247 OPEN cur_forecast_entries;
3248 END IF;
3249
3250 FETCH cur_forecast_entries
3251 INTO l_demand_rec.inventory_item_id,
3252 l_demand_type,
3253 l_line_id;
3254
3255 EXIT WHEN cur_forecast_entries%NOTFOUND;
3256
3257 IF g_debug THEN
3258 g_log_message := 'Forecast Entry Details : ' ;
3259 MRP_UTIL.MRP_LOG (g_log_message);
3260 g_log_message := 'Item : ' || to_char(l_demand_rec.inventory_item_id) ;
3261 MRP_UTIL.MRP_LOG (g_log_message);
3262 END IF;
3263
3264 ELSIF ( g_kanban_info_rec.input_type = 2 OR
3265 g_kanban_info_rec.input_type = 3 ) THEN
3266 -- input is an MDS (type = 2) or MPS (type = 3)
3267
3268 IF NOT cur_schedule_entries%ISOPEN THEN
3269 OPEN cur_schedule_entries;
3270 END IF;
3271
3272 FETCH cur_schedule_entries
3273 INTO l_demand_rec.inventory_item_id,
3274 l_demand_type,
3275 l_line_id;
3276
3277 EXIT WHEN cur_schedule_entries%NOTFOUND;
3278
3279 IF g_debug THEN
3280 g_log_message := 'Schedule Entry Details : ' ;
3281 MRP_UTIL.MRP_LOG (g_log_message);
3282 g_log_message := 'Item : ' || to_char(l_demand_rec.inventory_item_id) ;
3283 MRP_UTIL.MRP_LOG (g_log_message);
3284 g_log_message := 'Line Reference :' || to_char(l_line_id);
3285 MRP_UTIL.MRP_LOG (g_log_message);
3286 END IF;
3287 ELSIF ( g_kanban_info_rec.input_type = 4) THEN
3288 -- input is Actual Production (type = 4)
3289
3290 IF NOT GetActualProductionDemand%ISOPEN THEN
3291 OPEN GetActualProductionDemand;
3292 END IF;
3293
3294 FETCH GetActualProductionDemand
3295 INTO l_demand_rec.inventory_item_id,
3296 l_alt_bom,
3297 l_line_id;
3298
3299 EXIT WHEN GetActualProductionDemand%NOTFOUND;
3300
3301 IF g_debug THEN
3302 g_log_message := 'Schedule Entry Details : ' ;
3303 MRP_UTIL.MRP_LOG (g_log_message);
3304 g_log_message := 'Item : ' || to_char(l_demand_rec.inventory_item_id) ;
3305 MRP_UTIL.MRP_LOG (g_log_message);
3306 g_log_message := 'Alternate : ' || l_alt_bom;
3307 MRP_UTIL.MRP_LOG (g_log_message);
3308 g_log_message := 'Line Reference :' || to_char(l_line_id);
3309 MRP_UTIL.MRP_LOG (g_log_message);
3310 END IF;
3311 END IF;
3312
3313 g_stmt_num := 160;
3314 IF g_debug THEN
3315 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
3316 MRP_UTIL.MRP_LOG (g_log_message);
3317 g_log_message := 'Calling Insert Demand function';
3318 MRP_UTIL.MRP_LOG (g_log_message);
3319 END IF;
3320
3321 -- call the function to insert demand and explode it through
3322 -- to the bottom of the bill
3323 IF g_kanban_info_rec.input_type = 1 THEN
3324 -- input is an Forecast
3325 l_ret_val := Insert_Fcst_Demand( l_demand_rec.inventory_item_id,
3326 l_demand_type,
3327 l_line_id );
3328 ELSIF ( g_kanban_info_rec.input_type = 2 OR
3329 g_kanban_info_rec.input_type = 3 ) THEN
3330 -- input is an MDS (type = 2) or MPS (type = 3)
3331 l_ret_val := Insert_Mds_Mps_Demand( l_demand_rec.inventory_item_id,
3332 l_demand_type,
3333 l_line_id );
3334 ELSIF g_kanban_info_rec.input_type = 4 THEN
3335 -- input is an Actual Production
3336 l_ret_val := Insert_Ap_Demand( l_demand_rec.inventory_item_id,
3337 l_alt_bom,
3338 l_line_id );
3339
3340 END IF;
3341
3342 IF NOT l_ret_val THEN
3343 RETURN FALSE;
3344 END IF;
3345
3346 END LOOP; -- demand entries loop
3347
3348 IF cur_forecast_entries%ISOPEN THEN
3349 CLOSE cur_forecast_entries;
3350 ELSIF cur_schedule_entries%ISOPEN THEN
3351 CLOSE cur_schedule_entries;
3352 ELSIF GetActualProductionDemand%ISOPEN THEN
3353 CLOSE GetActualProductionDemand;
3354 END IF;
3355
3356 RETURN TRUE;
3357
3358 --exception handling
3359 EXCEPTION
3360 WHEN OTHERS THEN
3361 g_log_message := 'RETRIEVE_KANBAN_DEMAND Sql Error ';
3362 MRP_UTIL.MRP_LOG (g_log_message);
3363 g_log_message := sqlerrm;
3364 MRP_UTIL.MRP_LOG (g_log_message);
3365 RETURN FALSE;
3366
3367 END Retrieve_Kanban_Demand;
3368
3369 -- ========================================================================
3370 -- This function calculates the Kanban Size/Number
3371 -- ========================================================================
3372 function Kanban_Calculation_Pvt (
3373 p_average_demand IN NUMBER,
3374 p_minimum_order_quantity IN NUMBER,
3375 p_fixed_lot_multiplier IN NUMBER,
3376 p_safety_stock_days IN NUMBER,
3377 p_replenishment_lead_time IN NUMBER,
3378 p_kanban_flag IN NUMBER,
3379 p_kanban_size IN OUT NOCOPY NUMBER,
3380 p_kanban_number IN OUT NOCOPY NUMBER )
3381 RETURN BOOLEAN IS
3382
3383 l_current_demand NUMBER;
3384 l_order_quantity NUMBER;
3385 l_kanban_number NUMBER;
3386
3387 BEGIN
3388
3389 -- check if p_kanban_number is passed in as 1 and bump it
3390 -- upto 2 so that the math does'nt croak
3391 IF p_kanban_number = 1 THEN
3392 l_kanban_number := 2;
3393 ELSE
3394 l_kanban_number := p_kanban_number;
3395 END If;
3396
3397 -- first calculate the Kanban Size or Kanban Number
3398 -- depending on the Kanban flag
3399
3400 IF p_kanban_flag = G_CALC_KANBAN_NUMBER THEN
3401
3402 p_kanban_number :=
3403 CEIL(((p_average_demand * (nvl(p_replenishment_lead_time,1) +
3404 nvl(p_safety_stock_days, 0) ))/p_kanban_size) + 1);
3405
3406 ELSIF p_kanban_flag = G_CALC_KANBAN_SIZE THEN
3407
3408 p_kanban_size :=
3409 CEIL((p_average_demand * (nvl(p_replenishment_lead_time,1) +
3410 nvl(p_safety_stock_days, 0)))/(l_kanban_number - 1));
3411 END IF;
3412
3413 -- now go ahead and apply the order modifiers
3414 -- If we are calculating Kanban size, we look at all the three order
3415 -- modifiers, ie, fixed days supply, min order quantity and fixed
3416 -- lot multiplier.
3417 -- If we are calculating number of Kanban cards, then we look at only
3418 -- the min order quantity.
3419
3420 IF p_kanban_flag = G_CALC_KANBAN_SIZE THEN
3421
3422 IF p_minimum_order_quantity IS NOT NULL THEN
3423 IF p_kanban_size < p_minimum_order_quantity THEN
3424 p_kanban_size := p_minimum_order_quantity;
3425 END IF;
3426 END IF;
3427
3428 IF p_fixed_lot_multiplier IS NOT NULL THEN
3429 IF p_kanban_size < p_fixed_lot_multiplier THEN
3430 p_kanban_size := p_fixed_lot_multiplier;
3431 ELSIF MOD (p_kanban_size, p_fixed_lot_multiplier) > 0 THEN
3432 p_kanban_size := p_kanban_size + ( p_fixed_lot_multiplier
3433 - MOD (p_kanban_size, p_fixed_lot_multiplier));
3434 END IF;
3435 END IF;
3436
3437 ELSIF p_kanban_flag = G_CALC_KANBAN_NUMBER THEN
3438
3439 -- Take min order quantity into consideration such that
3440 -- (Num. of Cards - 1) * Kanban Size is NOT LESS THAN
3441 -- (Min. Order Qty + Demand Over Lead Time ).
3442
3443 IF (p_minimum_order_quantity IS NOT NULL AND
3444 p_minimum_order_quantity > p_kanban_size) THEN
3445 IF (p_kanban_size * (p_kanban_number - 1)) <
3446 nvl(p_minimum_order_quantity,0) + (p_average_demand *
3447 nvl(p_replenishment_lead_time,1)) THEN
3448 p_kanban_number := CEIL((nvl(p_minimum_order_quantity,0) +
3449 (p_average_demand * nvl(p_replenishment_lead_time,1)))
3450 / p_kanban_size) + 1;
3451 END IF;
3452 END IF;
3453
3454 END IF;
3455
3456 RETURN TRUE;
3457
3458 Exception
3459 WHEN OTHERS THEN
3460 g_log_message := 'KANBAN_CALCULATION_PVT Sql Error ';
3461 MRP_UTIL.MRP_LOG (g_log_message);
3462 g_log_message := sqlerrm;
3463 MRP_UTIL.MRP_LOG (g_log_message);
3464 RETURN FALSE;
3465
3466 END Kanban_Calculation_Pvt;
3467 -- ========================================================================
3468 -- this function calculates the kanban size/number for each
3469 -- kanban item/location that we need to plan in this plan run
3470 -- and inserts the information into mtl_kanban_pull_sequences table
3471 -- ========================================================================
3472
3473 FUNCTION Calculate_Kanban_Quantity (p_total_workdays IN NUMBER)
3474 RETURN BOOLEAN IS
3475
3476 -- declare local variables here
3477 l_average_demand number;
3478 l_item_id number;
3479 l_subinventory varchar2(10);
3480 l_locator_id number;
3481 l_replenishment_lead_time number;
3482 l_fixed_lot_multiplier number;
3483 l_safety_stock_days number;
3484 l_minimum_order_quantity number;
3485 l_api_version number;
3486 l_pull_sequence_rec INV_Kanban_PVT.pull_sequence_Rec_type;
3487 l_return_status varchar2(1);
3488
3489 -- declare a cursor to summarize the demand for each
3490 -- distinct item/location and calculate the average demand
3491 -- for this item/location over the user defined time period
3492
3493 CURSOR cur_kanban_demand IS
3494 SELECT (sum(demand_quantity)/p_total_workdays),
3495 inventory_item_id,
3496 subinventory,
3497 locator_id
3498 FROM mrp_kanban_demand
3499 WHERE kanban_plan_id = g_kanban_info_rec.kanban_plan_id
3500 AND organization_id = g_kanban_info_rec.organization_id
3501 AND (demand_date >= g_kanban_info_rec.start_date
3502 AND demand_date <= g_kanban_info_rec.cutoff_date )
3503 AND kanban_item_flag = 'Y'
3504 GROUP BY
3505 inventory_item_id,
3506 subinventory,
3507 locator_id;
3508
3509 -- Cursor to retrieve information from pull sequences table
3510 CURSOR cur_pull_sequence IS
3511 SELECT source_type,
3512 supplier_id,
3513 supplier_site_id,
3514 source_organization_id,
3515 source_subinventory,
3516 source_locator_id,
3517 wip_line_id,
3518 replenishment_lead_time,
3519 calculate_kanban_flag,
3520 kanban_size,
3521 fixed_lot_multiplier,
3522 safety_stock_days,
3523 number_of_cards,
3524 minimum_order_quantity,
3525 aggregation_type,
3526 allocation_percent,
3527 release_kanban_flag
3528 FROM mtl_kanban_pull_sequences
3529 WHERE kanban_plan_id = decode (g_kanban_info_rec.replan_flag,
3530 2, G_PRODUCTION_KANBAN,
3531 1, g_kanban_info_rec.kanban_plan_id,
3532 G_PRODUCTION_KANBAN)
3533 AND organization_id = g_kanban_info_rec.organization_id
3534 AND inventory_item_id = l_item_id
3535 AND subinventory_name = l_subinventory
3536 AND nvl(locator_id,-1) = nvl(l_locator_id,-1);
3537
3538 BEGIN
3539
3540 IF g_debug THEN
3541 g_log_message := 'Entering Calculate_Kanban_Quantity Function';
3542 MRP_UTIL.MRP_LOG (g_log_message);
3543 END IF;
3544
3545 OPEN cur_kanban_demand;
3546
3547 WHILE TRUE LOOP
3548 FETCH cur_kanban_demand
3549 INTO l_average_demand,
3550 l_item_id,
3551 l_subinventory,
3552 l_locator_id;
3553
3554 IF g_debug THEN
3555 g_log_message := 'Item Id : ' || to_char (l_item_id);
3556 MRP_UTIL.MRP_LOG (g_log_message);
3557 g_log_message := 'SubInventory : ' || l_subinventory;
3558 MRP_UTIL.MRP_LOG (g_log_message);
3559 g_log_message := 'Locator : ' || to_char(l_locator_id);
3560 MRP_UTIL.MRP_LOG (g_log_message);
3561 END IF;
3562
3563
3564 EXIT WHEN cur_kanban_demand%NOTFOUND;
3565
3566 -- now get some information about this item/location from
3567 -- mtl_kanban_pull_sequences
3568
3569 OPEN cur_pull_sequence;
3570
3571 FETCH cur_pull_sequence
3572 INTO l_pull_sequence_rec.source_type,
3573 l_pull_sequence_rec.supplier_id,
3574 l_pull_sequence_rec.supplier_site_id,
3575 l_pull_sequence_rec.source_organization_id,
3576 l_pull_sequence_rec.source_subinventory,
3577 l_pull_sequence_rec.source_locator_id,
3578 l_pull_sequence_rec.wip_line_id,
3579 l_pull_sequence_rec.replenishment_lead_time,
3580 l_pull_sequence_rec.calculate_kanban_flag,
3581 l_pull_sequence_rec.kanban_size,
3582 l_pull_sequence_rec.fixed_lot_multiplier,
3583 l_pull_sequence_rec.safety_stock_days,
3584 l_pull_sequence_rec.number_of_cards,
3585 l_pull_sequence_rec.minimum_order_quantity,
3586 l_pull_sequence_rec.aggregation_type,
3587 l_pull_sequence_rec.allocation_percent,
3588 l_pull_sequence_rec.release_kanban_flag;
3589
3590
3591 --call the kanban quantity calculation api if we find pull sequence info
3592
3593 IF cur_pull_sequence%FOUND THEN
3594
3595 l_return_status := 'S'; -- initialize to success
3596
3597 -- initialize either kanban size/number to null depending on what
3598 -- we are calculating. This is important because we call our local
3599 -- kanban calculation API if the public API (stubbed out) returns
3600 -- a null value in what we want to calculate
3601
3602 IF l_pull_sequence_rec.calculate_kanban_flag = G_CALC_KANBAN_SIZE THEN
3603 l_pull_sequence_rec.kanban_size := NULL;
3604 ELSIF l_pull_sequence_rec.calculate_kanban_flag =
3605 G_CALC_KANBAN_NUMBER THEN
3606 l_pull_sequence_rec.number_of_cards := NULL;
3607 END IF;
3608
3609
3610 IF g_debug THEN
3611 g_log_message := 'Calling Kanban Qty Calc API';
3612 MRP_UTIL.MRP_LOG (g_log_message);
3613 g_log_message := 'Parameters Passed to the Kanban Qty Calc API : ';
3614 MRP_UTIL.MRP_LOG (g_log_message);
3615 g_log_message := 'Demand :' || to_char (l_average_demand);
3616 MRP_UTIL.MRP_LOG (g_log_message);
3617 g_log_message := 'Min Order Qty :'
3618 || to_char (l_pull_sequence_rec.minimum_order_quantity);
3619 MRP_UTIL.MRP_LOG (g_log_message);
3620 g_log_message := 'Fixed Lot Multiplier : '
3621 || to_char (l_pull_sequence_rec.fixed_lot_multiplier);
3622 MRP_UTIL.MRP_LOG (g_log_message);
3623 g_log_message := 'Fixed Days Supply :'
3624 || to_char (l_pull_sequence_rec.safety_stock_days);
3625 MRP_UTIL.MRP_LOG (g_log_message);
3626 g_log_message := 'Replenishment Lead Time :'
3627 || to_char (l_pull_sequence_rec.replenishment_lead_time);
3628 MRP_UTIL.MRP_LOG (g_log_message);
3629 g_log_message := 'Calculate Kanban Flag :'
3630 || to_char (l_pull_sequence_rec.calculate_kanban_flag);
3631 MRP_UTIL.MRP_LOG (g_log_message);
3632 g_log_message := 'Kanban Size :'
3633 || to_char (l_pull_sequence_rec.kanban_size);
3634 MRP_UTIL.MRP_LOG (g_log_message);
3635 g_log_message := 'Number of Cards :'
3636 || to_char (l_pull_sequence_rec.number_of_cards);
3637 MRP_UTIL.MRP_LOG (g_log_message);
3638 END IF;
3639
3640 -- specify the version of the API we want to call
3641 l_api_version := 1.0;
3642
3643 MRP_PUB_KANBAN_QTY_CALC.Calculate_Kanban_Quantity (
3644 l_api_version,
3645 l_average_demand,
3646 l_pull_sequence_rec.minimum_order_quantity,
3647 l_pull_sequence_rec.fixed_lot_multiplier,
3648 l_pull_sequence_rec.safety_stock_days,
3649 l_pull_sequence_rec.replenishment_lead_time,
3650 l_pull_sequence_rec.calculate_kanban_flag,
3651 l_pull_sequence_rec.kanban_size,
3652 l_pull_sequence_rec.number_of_cards,
3653 l_return_status );
3654
3655 IF l_return_status <> 'S' THEN
3656 IF g_debug THEN
3657 g_log_message := 'Error in Kanban Quantity Calculation API';
3658 MRP_UTIL.MRP_LOG (g_log_message);
3659 END IF;
3660 RETURN FALSE;
3661 END IF;
3662
3663 IF l_pull_sequence_rec.kanban_size IS NULL OR
3664 l_pull_sequence_rec.number_of_cards IS NULL THEN
3665
3666 IF NOT Kanban_Calculation_Pvt (
3667 l_average_demand,
3668 l_pull_sequence_rec.minimum_order_quantity,
3669 l_pull_sequence_rec.fixed_lot_multiplier,
3670 l_pull_sequence_rec.safety_stock_days,
3671 l_pull_sequence_rec.replenishment_lead_time,
3672 l_pull_sequence_rec.calculate_kanban_flag,
3673 l_pull_sequence_rec.kanban_size,
3674 l_pull_sequence_rec.number_of_cards ) THEN
3675
3676 IF g_debug THEN
3677 g_log_message := 'Error in Kanban Calculation function';
3678 MRP_UTIL.MRP_LOG (g_log_message);
3679 END IF;
3680 RETURN FALSE;
3681
3682 END IF;
3683 END IF;
3684
3685 -- Now go ahead and insert/update into mtl_kanban_pull_sequences table
3686 -- information about this kanban item/location for this kanban plan
3687
3688 SELECT
3689 fnd_global.conc_request_id,
3690 fnd_global.prog_appl_id,
3691 fnd_global.conc_program_id,
3692 sysdate,
3693 sysdate,
3694 fnd_global.user_id,
3695 sysdate,
3696 fnd_global.user_id
3697 INTO
3698 l_pull_sequence_rec.request_id,
3699 l_pull_sequence_rec.program_application_id,
3700 l_pull_sequence_rec.program_id,
3701 l_pull_sequence_rec.program_update_date,
3702 l_pull_sequence_rec.last_update_date,
3703 l_pull_sequence_rec.last_updated_by,
3704 l_pull_sequence_rec.creation_date,
3705 l_pull_sequence_rec.created_by
3706 FROM dual;
3707
3708 l_pull_sequence_rec.organization_id := g_kanban_info_rec.organization_id;
3709 l_pull_sequence_rec.kanban_plan_id := g_kanban_info_rec.kanban_plan_id;
3710 l_pull_sequence_rec.inventory_item_id := l_item_id;
3711 l_pull_sequence_rec.subinventory_name := l_subinventory;
3712 l_pull_sequence_rec.locator_id := l_locator_id;
3713 l_pull_sequence_rec.pull_sequence_id := NULL;
3714
3715 IF g_debug THEN
3716 g_log_message := 'Kanban Size after Calculation : '
3717 || to_char(l_pull_sequence_rec.kanban_size);
3718 MRP_UTIL.MRP_LOG (g_log_message);
3719 g_log_message := 'Kanban Number after Calculation : '
3720 || to_char(l_pull_sequence_rec.number_of_cards);
3721 MRP_UTIL.MRP_LOG (g_log_message);
3722 END IF;
3723
3724 -- call the inventory api for inserting into mtl_pull_sequences
3725 l_return_status := 'S'; -- initialize to success
3726
3727 IF nvl(g_kanban_info_rec.replan_flag,2) = 2 THEN -- not replan
3728 INV_Kanban_PVT.Insert_pull_sequence
3729 (l_return_status,
3730 l_pull_sequence_rec);
3731 ELSIF g_kanban_info_rec.replan_flag = 1 THEN -- replan
3732 INV_Kanban_PVT.Update_pull_sequence
3733 (l_return_status,
3734 l_pull_sequence_rec);
3735 END If;
3736
3737 IF l_return_status <> 'S' THEN
3738 IF g_debug THEN
3739 g_log_message := 'Error in Inventory Insert/Update API';
3740 MRP_UTIL.MRP_LOG (g_log_message);
3741 g_log_message := 'Return Code : ' || l_return_status;
3742 MRP_UTIL.MRP_LOG (g_log_message);
3743 END IF;
3744 RETURN FALSE;
3745 END IF;
3746
3747 END IF;
3748
3749 CLOSE cur_pull_sequence;
3750
3751 END LOOP;
3752
3753 --we are now done and can close the cursor
3754 CLOSE cur_kanban_demand;
3755
3756 RETURN TRUE;
3757
3758 --exception handling
3759 EXCEPTION
3760 WHEN OTHERS THEN
3761 g_log_message := 'CALCULATE_KANBAN_QUANTITY Sql Error ';
3762 MRP_UTIL.MRP_LOG (g_log_message);
3763 g_log_message := sqlerrm;
3764 MRP_UTIL.MRP_LOG (g_log_message);
3765 RETURN FALSE;
3766
3767 END Calculate_Kanban_Quantity;
3768
3769 -- ========================================================================
3770 -- This is the main procedure that controls the flow of the kanban planning
3771 -- process
3772 -- ========================================================================
3773
3774 PROCEDURE PLAN_KANBAN( ERRBUF OUT NOCOPY VARCHAR2,
3775 RETCODE OUT NOCOPY NUMBER,
3776 p_organization_id IN NUMBER,
3777 p_kanban_plan_id IN NUMBER,
3778 p_from_item IN VARCHAR2,
3779 p_to_item IN VARCHAR2,
3780 p_category_set_id IN NUMBER,
3781 p_category_structure_id IN NUMBER,
3782 p_from_category IN VARCHAR2,
3783 p_to_category IN VARCHAR2,
3784 p_bom_effectivity IN VARCHAR2,
3785 p_start_date IN VARCHAR2,
3786 p_cutoff_date IN VARCHAR2,
3787 p_replan_flag IN NUMBER ) IS
3788
3789 -- declare some local variable here
3790 l_llc_rec llc_rec_type;
3791 l_curr_ll_code number;
3792 l_ret_val boolean;
3793 l_total_workdays number;
3794
3795 var_trace boolean;
3796 c integer;
3797 statement varchar2(255);
3798 rows_processed integer;
3799
3800 -- declare exceptions we want to handle here
3801 exc_error_condition exception;
3802
3803 BEGIN
3804
3805 g_debug := FND_PROFILE.VALUE('MRP_DEBUG') = 'Y';
3806
3807 var_trace := fnd_profile.value('MRP_TRACE') = 'Y';
3808 if var_trace then
3809 c := dbms_sql.open_cursor;
3810 statement := 'alter session set sql_trace=true';
3811 dbms_sql.parse(c, statement, dbms_sql.native);
3812 rows_processed := dbms_sql.execute(c);
3813 dbms_sql.close_cursor(c);
3814 end if;
3815
3816 g_stmt_num := 10;
3817 IF g_debug THEN
3818 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
3819 MRP_UTIL.MRP_LOG (g_log_message);
3820 END IF;
3821
3822 -- check for mandatory parameters
3823 -- and issue appropriate error messages
3824 IF g_debug THEN
3825 IF p_organization_id IS NULL THEN
3826 g_log_message := 'Error : Organization Id is null';
3827 ELSIF p_kanban_plan_id IS NULL THEN
3828 g_log_message := 'Error : Kanban Plan Id is null';
3829 ELSIF (p_bom_effectivity IS NULL AND p_replan_flag = 2) THEN
3830 g_log_message := 'Error : BOM effectivity date is null';
3831 ELSIF (p_start_date IS NULL AND p_replan_flag = 2) THEN
3832 g_log_message := 'Error : Start date is null';
3833 ELSIF (p_cutoff_date IS NULL AND p_replan_flag = 2) THEN
3834 g_log_message := 'Error : Cutoff date is null';
3835 END IF;
3836 END IF;
3837
3838 IF p_organization_id IS NULL OR p_kanban_plan_id IS NULL OR
3839 ((p_bom_effectivity IS NULL OR p_cutoff_date IS NULL) AND
3840 p_replan_flag = 2) THEN
3841 MRP_UTIL.MRP_LOG (g_log_message);
3842 raise exc_error_condition;
3843 END IF;
3844
3845 -- get all the parameters passed to this concurrent program into
3846 -- the global record variable
3847 g_kanban_info_rec.organization_id := p_organization_id;
3848 g_kanban_info_rec.kanban_plan_id := p_kanban_plan_id;
3849 g_kanban_info_rec.from_item := p_from_item;
3850 g_kanban_info_rec.to_item := p_to_item;
3851 g_kanban_info_rec.category_set_id := p_category_set_id;
3852 g_kanban_info_rec.category_structure_id := p_category_structure_id;
3853 g_kanban_info_rec.from_category := p_from_category;
3854 g_kanban_info_rec.to_category := p_to_category;
3855 g_kanban_info_rec.bom_effectivity :=
3856 to_date(p_bom_effectivity,'YYYY/MM/DD HH24:MI:SS');
3857 g_kanban_info_rec.start_date :=
3858 to_date(p_start_date,'YYYY/MM/DD HH24:MI:SS');
3859 g_kanban_info_rec.cutoff_date :=
3860 to_date(p_cutoff_date,'YYYY/MM/DD HH24:MI:SS');
3861 g_kanban_info_rec.replan_flag := p_replan_flag;
3862
3863 IF g_debug THEN
3864 g_log_message := 'Parameters passed to the program :';
3865 MRP_UTIL.MRP_LOG (g_log_message);
3866 g_log_message := 'organization_id : ' || p_organization_id;
3867 MRP_UTIL.MRP_LOG (g_log_message);
3868 g_log_message := 'kanban_plan_id : ' || p_kanban_plan_id;
3869 MRP_UTIL.MRP_LOG (g_log_message);
3870 g_log_message := 'from_item_id : ' || p_from_item;
3871 MRP_UTIL.MRP_LOG (g_log_message);
3872 g_log_message := 'to_item_id : ' || p_to_item;
3873 MRP_UTIL.MRP_LOG (g_log_message);
3874 g_log_message := 'category_set_id : ' || p_category_set_id;
3875 MRP_UTIL.MRP_LOG (g_log_message);
3876 g_log_message := 'category_structure_id : ' || p_category_structure_id;
3877 MRP_UTIL.MRP_LOG (g_log_message);
3878 g_log_message := 'from_category_id : ' || p_from_category;
3879 MRP_UTIL.MRP_LOG (g_log_message);
3880 g_log_message := 'to_category_id : ' || p_to_category;
3881 MRP_UTIL.MRP_LOG (g_log_message);
3882 g_log_message := 'bom_effectivity : ' || p_bom_effectivity;
3883 MRP_UTIL.MRP_LOG (g_log_message);
3884 g_log_message := 'start_date : ' || p_start_date;
3885 MRP_UTIL.MRP_LOG (g_log_message);
3886 g_log_message := 'cutoff_date : ' || p_cutoff_date;
3887 MRP_UTIL.MRP_LOG (g_log_message);
3888 g_log_message := 'replan_flag : ' || p_replan_flag;
3889 MRP_UTIL.MRP_LOG (g_log_message);
3890 END IF;
3891
3892 -- call the start_kanban function
3893 IF NOT Start_Kanban_Plan THEN
3894 g_log_message := 'Error in START_KANBAN_PLAN';
3895 MRP_UTIL.MRP_LOG (g_log_message);
3896 raise exc_error_condition;
3897 END IF;
3898
3899 /*
3900 this has been moved to Start_Kanban_Plan procedure
3901 because we now want to commit after the snapshot is over so that
3902 there is less impact on rollback segment
3903
3904 -- call the procedure to snapshot the item/locations and
3905 -- populate mrp_low_level_codes table.
3906 -- Note that we are calculating low level codes
3907 -- only to detect loops and not for planning purposes.
3908 -- We gather demand by looking at the input to the plan
3909 -- and then blow it down to the component item/locations
3910
3911 IF NOT mrp_kanban_snapshot_pk.snapshot_item_locations THEN
3912 g_log_message := 'Error in SNAPSHOT_ITEM_LOCATIONS';
3913 MRP_UTIL.MRP_LOG (g_log_message);
3914 raise exc_error_condition;
3915 END IF;
3916 */
3917 g_stmt_num := 150;
3918 IF g_debug THEN
3919 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
3920 MRP_UTIL.MRP_LOG (g_log_message);
3921 END IF;
3922
3923 -- now call the procedure to retrieve the kanban demand based on
3924 -- the input to the kanban plan and pass it down to the components
3925 -- as in the mrp_low_level_codes table
3926
3927 IF NOT Retrieve_Kanban_Demand THEN
3928 g_log_message := 'Error in RETRIEVE_KANBAN_DEMAND';
3929 MRP_UTIL.MRP_LOG (g_log_message);
3930 raise exc_error_condition;
3931 END IF;
3932
3933 -- We now have all the demand for this plan run stored in the
3934 -- mrp_kanban_demand table. So go ahead and call the procedure
3935 -- to calculate Kanban quantities for the kanban items included
3936 -- in this plan
3937
3938 --first calculate the total number of workdays between start date
3939 --and cutoff date specified
3940 SELECT count(*)
3941 INTO l_total_workdays
3942 FROM bom_calendar_dates bcd,
3943 mtl_parameters mp
3944 WHERE mp.organization_id = g_kanban_info_rec.organization_id
3945 AND bcd.calendar_code = mp.calendar_code
3946 AND bcd.seq_num IS NOT NULL
3947 AND (bcd.calendar_date BETWEEN g_kanban_info_rec.start_date AND
3948 g_kanban_info_rec.cutoff_date );
3949
3950
3951 g_stmt_num := 180;
3952 IF g_debug THEN
3953 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
3954 MRP_UTIL.MRP_LOG (g_log_message);
3955 END IF;
3956
3957 IF NOT (Calculate_Kanban_Quantity (l_total_workdays)) THEN
3958 g_log_message := 'Error in CALCULATE_KANBAN_QUANTITY';
3959 MRP_UTIL.MRP_LOG (g_log_message);
3960 raise exc_error_condition;
3961 END IF;
3962
3963 g_stmt_num := 190;
3964 IF g_debug THEN
3965 g_log_message := 'Debug Statement Number : ' || to_char (g_stmt_num);
3966 MRP_UTIL.MRP_LOG (g_log_message);
3967 END IF;
3968
3969 -- if we come here then we are done with the planning and we can
3970 -- update the plan_completion_date
3971
3972 l_ret_val := End_Kanban_Plan;
3973
3974 IF NOT l_ret_val THEN
3975 g_log_message := 'Error in END_KANBAN_PLAN';
3976 MRP_UTIL.MRP_LOG (g_log_message);
3977 raise exc_error_condition;
3978 END IF;
3979
3980 IF g_raise_warning THEN
3981 ERRBUF := 'Kanban Planning Engine completed with warning';
3982 RETCODE := G_WARNING;
3983 g_raise_warning := FALSE;
3984 ELSE
3985 ERRBUF := 'Kanban Planning Engine completed a successful run';
3986 RETCODE := G_SUCCESS;
3987 END IF;
3988
3989 -- Exception Handling
3990
3991 EXCEPTION
3992
3993 WHEN exc_error_condition THEN
3994 ROLLBACK;
3995 RETCODE := G_ERROR;
3996 ERRBUF := 'Program Completed with Error : ' || sqlerrm;
3997 g_log_message := 'Program encountered Error condition Exception';
3998 MRP_UTIL.MRP_LOG (g_log_message);
3999
4000 WHEN OTHERS THEN
4001 ROLLBACK;
4002 RETCODE := G_ERROR;
4003 ERRBUF := 'Program Completed with Error : ' || sqlerrm;
4004 g_log_message := 'PLAN_KANBAN Sql Error ';
4005 MRP_UTIL.MRP_LOG (g_log_message);
4006 g_log_message := sqlerrm;
4007 MRP_UTIL.MRP_LOG (g_log_message);
4008
4009
4010 END PLAN_KANBAN;
4011
4012 END MRP_KANBAN_PLAN_PK;