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