DBA Data[Home] [Help]

PACKAGE BODY: APPS.ENG_ECO_COST

Source


1 PACKAGE BODY Eng_Eco_Cost AS
2 /* $Header: ENGCOSTB.pls 120.1 2006/01/16 03:34:54 rnarveka noship $ */
3 
4 	TYPE cost_record_type IS RECORD (
5                         revised_item_id NUMBER,
6                         item_cost       NUMBER );
7 
8 	TYPE repetative_record_type IS RECORD (
9 			item_cost	NUMBER,
10 			demand_quantity	NUMBER,
11 			period_name_year VARCHAR2(8)
12 			);
13 
14         TYPE eco_cost_table IS TABLE OF cost_record_type
15                  INDEX BY BINARY_INTEGER;
16 
17 	TYPE Rep_Table_Type IS TABLE OF repetative_record_type
18 		INDEX BY BINARY_INTEGER;
19 
20 	l_repetative_cost_table Rep_Table_Type;
21 	l_eco_cost_table 	Eco_Cost_Table;
22 
23 	/* Function: Calc_Cost_Of_Items_On_Eco
24 
25 	   Description:
26 	   Function will calculate the material cost of the items that exist on the Eco and
27 	   will return this cost as the cost of the items as they exist in production.
28 
29 	   Parameters: 	change_notice varchar2(10)
30 			org_id number;
31 
32 	   Return value: Number
33 
34 	*/
35 
36 	FUNCTION Calc_Cost_Of_Items_On_Eco ( p_change_notice IN varchar2,
37 					     p_org_id 	     IN number )
38 		 RETURN NUMBER
39 	IS
40 	l_items_cost number;
41 	BEGIN
42 
43 		SELECT sum(cic.material_cost)
44 		  INTO l_items_cost
45 		  FROM cst_item_costs cic,
46 		       eng_revised_items eri
47 		 WHERE eri.change_notice = p_change_notice
48 		   AND eri.organization_id = p_org_id
49 		   AND cic.inventory_item_id = eri.revised_item_id
50 		   AND cic.organization_id = eri.organization_id
51 		   AND cic.cost_type_id = 1;
52 
53 		-- if no exception is raised, then return the value of l_items_cost
54 		RETURN l_items_cost;
55 
56 		EXCEPTION
57 			WHEN OTHERS THEN
58 				return 0;
59 	END Calc_Cost_Of_Items_On_Eco;
60 
61 
62 	/* Procedure: Calc_Cost_Of_Changes
63 
64            Description:
65 	   Procedure will calculate the changes that their cost, sum it all together to
66 	   give the cost of changes on the ECO.
67 	   If there is a change operation and the existing quantity is changed from 6 to 2
68 	   then the final change in cost is -4 * cost of that item. If this cost is added to
69 	   the cost of the assembly as it exists in production it will give the cost of the
70 	   the item after the ECO is eimplemented. Similary when an item is added on a bill
71 	   the cost of that item will be added to the original bill and if an item is being
72 	   deleted, then the cost will be deducted from the cost of the assembly.
73 	   Cost of an item will be ( planning % of Quantity ) * material cost of that item.
74 
75            Parameters:  change_notice varchar2(10)
76                         org_id number;
77 
78            Return value: None, but will create a pl/sql table .
79 
80         */
81 
82 	PROCEDURE Calc_Cost_Of_Changes ( p_change_notice 	IN varchar2,
83 				        p_org_id		IN number)
84 	IS
85 		CURSOR cost_of_change IS
86 		SELECT eri.revised_item_id,
87 		       sum (cic.material_cost * (
88                              ( DECODE( (bic1.planning_factor - bic2.planning_factor), 0,
89                                        bic1.planning_factor,
90                                        (bic1.planning_factor - bic2.planning_factor)
91                                       ) *
92                                       ( decode( bic1.acd_type,
96                                                )
93                                                 1, -bic1.component_quantity,
94                                                 2, (bic2.component_quantity - bic1.component_quantity),
95                                                 3, bic2.component_quantity
97                                        )
98                                ) /100
99                             )
100        			) item_cost
101 		    from bom_inventory_components bic1,
102 			 bom_inventory_components bic2,
103 			 eng_revised_items eri,
104 			 mtl_system_items msi,
105 			 cst_item_costs cic
106 		   where eri.change_notice = p_change_notice
107 		     and eri.organization_id = p_org_id
108 		     and bic1.bill_sequence_id = eri.bill_sequence_id
109 		     and bic1.revised_item_sequence_id = eri.revised_item_sequence_id
110 		     and bic1.change_notice = eri.change_notice
111 		     and bic1.implementation_date is null
112 		     and bic2.bill_sequence_id = eri.bill_sequence_id
113 		     and ( ( bic1.acd_type in (2,3) and
114         		     bic2.component_sequence_id = bic1.old_component_sequence_id
115        			    )
116        			    or
117        			    bic1.acd_type = 1 and
118        			    bic2.component_sequence_id = bic1.component_sequence_id
119      			  )
120 		     and msi.inventory_item_id = bic1.component_item_id
121 		     and msi.organization_id   = eri.organization_id
122 		     and cic.inventory_item_id = bic1.component_item_id
123 		     and cic.organization_id   = eri.organization_id
124 		     and cic.cost_type_id      = 1
125 		    group by eri.revised_item_id;
126 
127 		    idx	NUMBER;
128 	BEGIN
129 
130 		--dbms_output.put_line('Executing calc_cost_of_changes . . .');
131 
132 		-- Loop thru the cursor and calculate and store the cost of
133 		-- change for each of the revised items.
134 		-- Store the result in the pl/sql table l_eco_cost_table
135 		idx := 1;
136 		FOR c_cost_of_change in cost_of_change LOOP
137 			l_eco_cost_table(idx).revised_item_id := c_cost_of_change.revised_item_id;
138 			l_eco_cost_table(idx).item_cost := c_cost_of_change.item_cost;
139 
140 			--dbms_output.put_line('Revised Item: ' || to_char(l_eco_cost_table(idx).revised_item_id) ||
141 			--		     ' Cost of Change: ' || to_Char(l_eco_cost_table(idx).item_cost));
142 
143 			idx := idx + 1;
144 		END LOOP; -- Cost of change loop ends
145 	END Calc_Cost_Of_Changes;
146 
147 
148 	/* Function: get_cost_of_item
149 
150 	   Description:
151 	   Will search the eco_cost_table and return the cost of the matching item
152 
153 	   Return: NUMBER
154 
155 	*/
156 	FUNCTION Get_Cost_Of_Item( p_revised_item_id	IN NUMBER )
157 		 RETURN NUMBER
158 	IS
159 		idx	NUMBER;
160 	BEGIN
161 		FOR idx IN 1 .. l_eco_cost_table.count LOOP
162 			IF l_eco_cost_table(idx).revised_item_id = p_revised_item_id THEN
163 				RETURN l_eco_cost_table(idx).item_cost;
164 			END IF;
165 		END LOOP;
166 	END Get_Cost_Of_Item;
167 
168 
169 	/* Procedure: Get_Cost_Quantity
170 
171 	   Description:
172 	   Will return the item cost and the demand quantity for a period. This is the cost and
173 	   quantity for a item with repetitive demand.
174 
175 	   Return: None, but set two o/p parameters x_item_cost and x_demand_quantity
176 
177 	*/
178 
179 	PROCEDURE Get_Cost_Quantity ( p_period_name_year IN VARCHAR2,
180 				      x_demand_quantity  OUT NOCOPY NUMBER,
181 				      x_item_cost	 OUT NOCOPY NUMBER
182 				    )
183 	IS
184 		idx 	NUMBER;
185 	BEGIN
186 		idx := 0;
187 
188 		FOR idx IN 1 .. l_repetative_cost_table.count LOOP
189 			IF l_repetative_cost_table(idx).period_name_year = p_period_name_year THEN
190 				x_demand_quantity := l_repetative_cost_table(idx).demand_quantity;
191 				x_item_cost	  := l_repetative_cost_table(idx).item_cost;
192 
193 				exit;
194 			END IF;
195 		END LOOP;
196 
197 		IF idx <> 0 THEN
198 			l_repetative_cost_table.DELETE(idx);
199 		ELSE
200 			-- If procedure executes till this point i.e. no period record is found
201 			-- then set return values to 0
202 			x_demand_quantity := 0;
203 			x_item_cost := 0;
204 		END IF;
205 
206 	END Get_Cost_Quantity;
207 
208 
209 	/* Procedure: Insert_Into_Temp_Table
210 
211 	   Description:
212 	   Will insert the passed data into the ENG_BIS_ECO_COST_TEMP table.
213 
214 	   Return: None
215 
216 	*/
217 
218 	PROCEDURE Insert_Into_Temp_Table (p_eco_cost	      IN NUMBER,
219 					  p_total_cost_saving IN NUMBER,
220                                           p_demand_quantity   IN NUMBER,
221                                           p_period_name_year  IN VARCHAR2,
222                                           p_period_start_date IN DATE,
223                                           p_change_notice     IN VARCHAR2,
224                                           p_org_id            IN NUMBER ,
225 					  p_query_id	      IN NUMBER
226                                           )
227 	IS
228 	BEGIN
229 
230                         INSERT INTO BOM_FORM_QUERY
231                                     ( number1,
232                                       number2,
233 				      number4,
234                                       char1,
235                                       date1,
236                                       char2,
237                                       number3,
238 				      query_id,
239 				      last_update_date,
240                                       last_updated_by,
241                                       creation_date,
242                                       created_by
243                                      )
247 				 p_period_name_year,
244                         VALUES ( p_eco_cost,
245 				 p_demand_quantity,
246 				 p_total_cost_saving,
248 				 p_period_start_date,
249 				 p_change_notice,
250 				 p_org_id,
251 			         p_query_id,
252                                  sysdate,
253                                  1,
254                                  sysdate,
255                                  1
256 				);
257 
258 	END Insert_Into_Temp_Table;
259 
260 	/* Procedure: Calc_Repetitive_Demand
261 
262 	   Description:
263 	   When a rate based demand exists, which spans across multiple periods, then
264 	   the demand needs to be split in the appropriate calendar periods with the
265 	   appropriate quantity.
266 
267 	   Returns: None.
268 	*/
269          PROCEDURE Calc_Repetitive_Demand( p_demand_date IN DATE,
270                                  	   p_comp_date   IN DATE,
271                                  	   p_req_qty	 IN NUMBER,
272 					   p_daily_rate	 IN NUMBER,
273 					   p_org_id	 IN NUMBER,
274 					   p_est_cost	 IN NUMBER,
275 					   p_cost_change IN NUMBER
276 					  )
277 	IS
278 		l_required_quantity	NUMBER;
279 		l_start_date		DATE;
280 		--
281 		-- Cursor will select periods between the demand_date and demand completion date
282 		-- This will then be used to spread the rate based demand.
283 		--
284 		CURSOR cal_periods IS
285 		SELECT period_start_date, next_date, period_name
286 		  FROM bom_org_cal_periods_view
287 		 WHERE organization_id = p_org_id
288 		   AND next_date > p_demand_date
289 		   AND period_start_date <= p_comp_date;
290 
291 		idx	NUMBER;
292 	BEGIN
293 		l_required_quantity := p_req_qty;
294 		l_start_date	    := p_demand_date;
295 
296 		--dbms_output.put_line('Calculate repetative demand . . .');
297 
298 		idx := nvl(l_repetative_cost_table.count, 0) + 1;
299 
300 		FOR c_cal_periods IN cal_periods LOOP
301 			IF p_comp_date > c_cal_periods.next_date THEN
302 				l_required_quantity := l_required_quantity -
303 						       (c_cal_periods.next_date - l_start_date) *
304 							p_daily_rate;
305 				l_start_date := c_cal_periods.next_date;
306 
307 			ELSIF p_comp_date < c_cal_periods.next_date and
308 			      p_comp_date > c_cal_periods.period_start_date
309 			 THEN
310 				l_required_quantity := (c_cal_periods.period_start_date - p_comp_date) *
311 							p_daily_rate;
312 			END IF;
313 
314 			-- Create a record in the pl/sql table and store the
315 			-- demand quantity and the cost for that period.
316 
317 			l_repetative_cost_table(idx).demand_quantity := l_required_quantity;
318 			l_repetative_cost_table(idx).item_cost := p_cost_change * l_required_quantity;
319 			l_repetative_cost_table(idx).period_name_year := c_cal_periods.period_name || '/' ||
320                                                                          to_char(c_cal_periods.period_start_date,
321                                                                          'YYYY');
322 			idx := idx + 1;
323 
324 		END LOOP;
325 
326 	END Calc_Repetitive_Demand;
327 
328 
329 
330 	PROCEDURE Eco_Cost_Calculate ( p_change_notice IN varchar2,
331 				       p_org_id        IN number,
332 				       p_plan_name     IN varchar2,
333 				       p_start_date    IN DATE,
334 				       p_end_date      IN DATE,
335 				       p_query_id      IN number)
336 	IS
337 
338 		l_cost_of_eco 		number;
339 		l_cost_of_changes 	number;
340 		l_estimated_cost 	number;
341 		l_required_quantity 	number;
342 		l_mfg_exists 		boolean;
343 		l_eng_exists 		boolean;
344 		l_temp_qty		number;
345 		l_temp_cost		number;
346 
347 		--
348 		-- Cursor to check which type of items exist on the ECO
349 		--  and decide whether to use mfg_cost or eng_cost
350 		--
351 		CURSOR check_assembly_type IS
352 		SELECT nvl(eco.estimated_mfg_cost, 0) mfg_cost,
353 		       nvl(eco.estimated_eng_cost, 0) eng_cost,
354 		       bom.assembly_type
355 		 FROM eng_engineering_changes eco,
356 		      eng_revised_items eri,
357 		      bom_bill_of_materials bom
358 		WHERE eco.change_notice = p_change_notice
359 		  AND eco.organization_id = p_org_id
360 		  AND eri.change_notice = eco.change_notice
361 		  AND eri.organization_id = eco.organization_id
362 		  AND bom.bill_sequence_id = eri.bill_sequence_id;
363 
364 		--
365 		-- Cursor to get the calendar periods that lie between the
366 		-- given start and end dates
367 		--
368 		CURSOR calendar_periods IS
369 		SELECT period_start_date, next_date, period_name
370 		  FROM bom_org_cal_periods_view
371 		 WHERE organization_id = p_org_id
372 		   AND next_date >= p_start_date
373 		   AND period_start_date <= p_end_date;
374 
375 		--
376 		-- Cursor to get the demand for all items that are planned using the
377 		-- plan_name and those that lie on the ECO only.
378 		--
379 		CURSOR item_demand (cp_start_date 	DATE,
380 				    cp_end_date   	DATE,
381 			            cp_change_notice	varchar2,
382 				    cp_org_id		number,
383 				    cp_plan_name	varchar2) IS
384 		SELECT	using_requirements_quantity,
385 		       	using_assembly_demand_date,
386 		      	assembly_demand_comp_date,
387 			daily_demand_rate,
388 			revised_item_id
389 		  FROM  eng_revised_items eri,
390 			mrp_gross_requirements mgr
391 		 WHERE  eri.change_notice = cp_change_notice
392 		   AND  eri.organization_id = cp_org_id
393 		   AND  mgr.compile_designator = cp_plan_name
394 		   AND  mgr.organization_id = eri.organization_id
395 		   AND  mgr.inventory_item_id = eri.revised_item_id
396 		   AND  mgr.using_assembly_demand_date >= cp_start_date
400 
397 		   AND  mgr.using_assembly_demand_date  < cp_end_date;
398 
399 	BEGIN
401 		 /*
402 		   This calculation is no longer required.
403 
404 			l_cost_of_eco := Calc_Cost_Of_Items_On_Eco(p_change_notice => p_change_notice,
405 							   p_org_id	   => p_org_id);
406 		*/
407 
408 		Calc_Cost_Of_Changes(p_change_notice => p_change_notice,
409 				     p_org_id	     => p_org_id);
410 
411 
412 
413 		-- If the ECO has both manufacturing and engineering items, then sum both the
414 		-- estimated_mfg_cost and the estimated_eng_cost
415 		-- If the ECO has only Engineering items, then only use the estimated_eng_cost
416 		-- If the ECO has only Manufacturing items, then only use the estimated_mfg_cost
417 		l_mfg_exists := FALSE;
418 		l_eng_exists := FALSE;
419 
420 
421 		FOR c_assembly_type IN check_assembly_type LOOP
422 
423 			IF c_assembly_type.assembly_type = 1 THEN
424 				l_mfg_exists := TRUE;
425 			ELSIF c_assembly_type.assembly_type = 2 THEN
426 				l_eng_exists := TRUE;
427 			END IF;
428 
429 			IF l_mfg_exists = TRUE AND
430 			   l_eng_exists = TRUE THEN
431 
432 			   l_estimated_cost := c_assembly_type.mfg_cost + c_assembly_type.eng_cost;
433 
434 			   -- If both the values are found, then no need to continue any further
435 			      EXIT;
436 
437 			ELSIF l_mfg_exists = TRUE AND
438 			      l_eng_exists = FALSE THEN
439 
440 			   l_estimated_cost := c_assembly_type.mfg_cost;
441 
442 			ELSE
443 			   l_estimated_cost := c_assembly_type.eng_cost;
444 			END IF;
445 
446 		END LOOP;
447 
448 		-- At this point you have the cost of the assemblies as they exist in production
449 		-- , changed cost of the ECO after the changes would be implemented
450 		-- estimated cost to be used depending on the type of items that exist on the ECO
451 		--
452 		-- Now calculate the demand based on the plan_name and aggregate the demand based on the
453 		-- Calendar periods.
454 
455 		-- Store the implementation cost in the global variable so that the
456 		-- report can read it.
457 		ENG_ECO_COST.g_estimated_Cost := l_estimated_Cost;
458 
459 		l_estimated_Cost := -l_estimated_Cost;
460 		FOR c_calendar_periods IN calendar_periods LOOP
461 
462 			-- For every period initialize l_required_quantity and l_cost_of_changes before proceeding
463 			-- with any calculations.
464 
465 			l_required_quantity := 0;
466 			l_cost_of_changes := 0;
467 
468 			--dbms_output.put_line('Period: ' || c_calendar_periods.period_name ||
469 			--		     ' Estimated Cost: ' || to_char(l_estimated_Cost));
470 
471 			FOR c_item_demand IN item_demand(cp_start_date => c_calendar_periods.period_start_date,
472 							 cp_end_date   => c_calendar_periods.next_date,
473 							 cp_change_notice => p_change_notice,
474 							 cp_org_id     => p_org_id,
475 							 cp_plan_name  => p_plan_name)
476 			LOOP
477 
478 				--dbms_output.put_line('Getting demand for ' || c_calendar_periods.period_name);
479 
480 				--
481 				-- If the demand for any item is repetitive or rate based, then
482 				-- calculate the quantity of the demand based on the daily_demand_rate
483 				--
484 
485 				IF NVL(c_item_demand.daily_demand_rate,0) <> 0 THEN
486 
487 					-- If the demand completion date span across multiple
488 					-- periods, then create records with appropriate
489 					-- quantity in the ENG_ECO_COSTS_TEMP table.
490 
491 					Calc_Repetitive_Demand(
492 							p_demand_date	=> c_item_demand.using_assembly_demand_date,
493 							p_comp_date	=> c_item_demand.assembly_demand_comp_date,
494 							p_req_qty	=> c_item_demand.using_requirements_quantity,
495 							p_org_id	=> p_org_id,
496 							p_daily_rate	=> c_item_demand.daily_demand_rate,
497 							p_est_cost	=> l_estimated_cost,
498 							p_cost_change	=> Get_Cost_Of_Item(p_revised_item_id =>
499 									     c_item_demand.revised_item_id)
500 							);
501 				ELSE
502 					l_required_quantity := l_required_quantity +
503 							       c_item_demand.using_requirements_quantity;
504 
505 					l_cost_of_changes := l_cost_of_changes +
506 							     c_item_demand.using_requirements_quantity *
507 							     Get_Cost_Of_Item(p_revised_item_id =>
508 										c_item_demand.revised_item_id);
509 				END IF;
510 
511                         END LOOP;  -- Item demand Loop Ends
512 
513 
514 			--
515 			-- Check if there is any demand generated for this period by any of the
516 			-- repetative demand items
517 			--
518 			--dbms_output.put_line('Getting cost and quantity . . .');
519 
520 			Get_Cost_Quantity(p_period_name_year => (c_calendar_periods.period_name) || '/' ||
521                                                                  to_char(c_calendar_periods.period_start_date,'YYYY'),
522 					  x_demand_quantity  => l_temp_qty,
523 					  x_item_cost	     => l_temp_cost
524 					 );
525 			--
526 			-- Cost and Quantity is found, then
527 			--
528 			IF l_temp_qty <> 0 and l_temp_cost <> 0 THEN
529 				l_required_quantity := l_required_quantity + l_temp_qty;
530 				l_cost_of_changes := l_cost_of_changes + l_temp_cost;
531 			END IF;
532 			--
533                         -- quantities for all the items in a given period are calculated, then
534                         -- insert records into the ENG_ECO_COSTS_TEMP table
535 
536 		        IF l_required_quantity <> 0 THEN
537 				--dbms_output.put_line('Inserting data . . .');
538 
539 			Insert_Into_Temp_Table(p_eco_cost		=> l_cost_of_changes,
540 					       p_total_cost_saving	=> (l_estimated_cost + l_cost_of_changes),
541 					       p_demand_quantity	=> l_required_quantity,
542 					       p_period_name_year	=> (c_calendar_periods.period_name) || '/' ||
543                                      				   	   to_char(c_calendar_periods.period_start_date,
544 									   'YYYY'),
545 					       p_period_start_date	=> c_calendar_periods.period_start_date,
546 					       p_change_notice		=> p_change_notice,
547 					       p_org_id			=> p_org_id,
548 					       p_query_id		=> p_query_id
549 					      );
550 			END IF;
551 
552 			l_estimated_cost := l_estimated_cost + l_cost_of_changes;
553 
554 		END LOOP;  -- Calendar periods Loop Ends
555 
556 	END Eco_Cost_Calculate;
557 
558 	/* Function	: g_estimated_cost
559 
560 	   Return	: number
561 
562 	   Description
563 	   Will simply return the estimated cost to the client
564 	*/
565 
566 	FUNCTION get_estimated_Cost RETURN NUMBER
567 	IS
568 	BEGIN
569 		return ENG_ECO_COST.g_estimated_cost;
570 	END;
571 
572 END Eng_Eco_Cost;