1 PACKAGE BODY WIP_WS_LABOR_METRIC_PUB AS
2 /* $Header: wipwslmb.pls 120.9 2008/06/12 11:24:27 sisankar noship $ */
3
4 /* To Get Calendar Code for an organization */
5 function get_calendar_code(p_organization_id number)
6 return varchar2 is
7 l_calendar_code varchar2(100) := null;
8 begin
9 select mp.calendar_code
10 into l_calendar_code
11 from mtl_parameters mp
12 where mp.organization_id = p_organization_id;
13 return l_calendar_code;
14 exception
15 when others then return null;
16 end get_calendar_code;
17
18 /* To validate whether the UOM is time based */
19 function is_time_uom(p_uom_code in varchar2)
20 return number is
21 l_uom_class varchar2(10);
22 l_time_based_uom_flag number;
23
24 cursor time_based_uom_cursor is
25 select distinct muc1.uom_class
26 from mtl_uom_conversions muc1,
27 mtl_uom_conversions muc2
28 where (muc1.uom_class = muc2.uom_class
29 and nvl(muc1.disable_date, sysdate + 1) > sysdate)
30 and nvl(muc2.disable_date, sysdate + 1) > sysdate
31 and muc1.uom_code = fnd_profile.value('BOM:HOUR_UOM_CODE')
32 and muc2.uom_code = p_uom_code;
33 begin
34 open time_based_uom_cursor;
35 fetch time_based_uom_cursor into l_uom_class;
36 if time_based_uom_cursor%notfound then
37 l_time_based_uom_flag := 2;
38 else
39 l_time_based_uom_flag := 1;
40 end if;
41 close time_based_uom_cursor;
42 return l_time_based_uom_flag;
43 end is_time_uom;
44
45 /* To obtain end of the time window for metrics calculation */
46 function get_period_end(p_calendar_code in varchar2,
47 p_date in date)
48 return date is
49 l_end_time Date := null;
50 l_temp_time Date;
51 begin
52
53 l_temp_time := p_date;
54 select
55 max(bsd.shift_date + st.to_time/(60*60*24))
56 into l_end_time
57 from
58 bom_shift_dates bsd,
59 (select bst.shift_num,
60 min(bst.from_time) from_time,
61 max(decode(sign(bst.to_time - bst.from_time), -1, 24*60*60, 0) + bst.to_time) to_time
62 from bom_shift_times bst
63 where bst.calendar_code = p_calendar_code
64 group by bst.shift_num) st
65 where bsd.calendar_code = p_calendar_code
66 and bsd.shift_num = st.shift_num
67 and bsd.exception_set_id = -1
68 and bsd.seq_num is not null
69 and bsd.shift_date = trunc(p_date)
70 and bsd.shift_date + st.to_time/(60*60*24) <= l_temp_time
71 and bsd.shift_date + st.from_time/(60*60*24) < l_temp_time;
72
73 while l_end_time is null loop
74
75 l_temp_time := l_temp_time-1;
76
77 select
78 max(bsd.shift_date + st.to_time/(60*60*24))
79 into l_end_time
80 from
81 bom_shift_dates bsd,
82 (select bst.shift_num,
83 max(decode(sign(bst.to_time - bst.from_time), -1, 24*60*60, 0) + bst.to_time) to_time
84 from bom_shift_times bst
85 where bst.calendar_code = p_calendar_code
86 group by bst.shift_num) st
87 where bsd.calendar_code = p_calendar_code
88 and bsd.shift_num = st.shift_num
89 and bsd.exception_set_id = -1
90 and bsd.seq_num is not null
91 and bsd.shift_date = trunc(l_temp_time);
92
93 end loop;
94
95 return l_end_time;
96
97 end get_period_end;
98
99 /* To obtain start of the time window for metrics calculation */
100 function get_period_start(p_org_id in number,
101 p_date in date)
102 return date
103 is
104 l_start_time Date;
105 begin
106 l_start_time := trunc(p_date)-6;
107 /* Commented this code since calculation is for last 7 calendar days and not last 7 working days.
108 for i in 1..6 loop
109 l_start_time := mrp_calendar.PREV_WORK_DAY(p_org_id,1,l_start_time-1);
110 end loop;*/
111 return l_start_time;
112 end get_period_start;
113
114 /* To obtain date for a given seq_num and shift_num (Used in Charts only) */
115 function get_date_for_seq(p_org_id in number,
116 p_seq_num in number,
117 p_shift_num in number)
118 return date
119 is
120 l_eff_date Date;
121 l_converted_date date;
122 l_calendar_code varchar2(50);
123 l_timezone_enabled boolean := ( fnd_profile.value('ENABLE_TIMEZONE_CONVERSIONS') = 'Y' AND
124 fnd_profile.value('CLIENT_TIMEZONE_ID') IS NOT NULL AND
125 fnd_profile.value('SERVER_TIMEZONE_ID') IS NOT NULL AND
126 fnd_profile.value('CLIENT_TIMEZONE_ID') <>
127 fnd_profile.value('SERVER_TIMEZONE_ID'));
128 l_client_id number := fnd_profile.value('CLIENT_TIMEZONE_ID');
129 l_server_id number := fnd_profile.value('SERVER_TIMEZONE_ID');
130 begin
131 l_calendar_code := get_calendar_code(p_org_id);
132 begin
133 select shift_date
134 into l_eff_date
135 from bom_shift_dates
136 where calendar_code = l_calendar_code
137 and exception_set_id = -1
138 and seq_num = p_seq_num
139 and shift_num =p_shift_num;
140 exception
141 when no_data_found
142 then l_eff_date := null;
143 end;
144
145 if l_timezone_enabled and l_eff_date is not null then
146 l_converted_date := hz_timezone_pub.convert_datetime(l_server_id,
147 l_client_id,
148 l_eff_date);
149 else
150 l_converted_date := l_eff_date;
151 end if;
152
153 return l_converted_date;
154 end get_date_for_seq;
155
156 /* To obtain date for a given seq_num and shift_num */
157 function get_date(p_org_id in number,
158 p_seq_num in number,
159 p_shift_num in number)
160 return date
161 is
162 l_eff_date Date;
163 l_calendar_code varchar2(50);
164 begin
165 l_calendar_code := get_calendar_code(p_org_id);
166 begin
167 select shift_date
168 into l_eff_date
169 from bom_shift_dates
170 where calendar_code = l_calendar_code
171 and exception_set_id = -1
172 and seq_num = p_seq_num
173 and shift_num =p_shift_num;
174 return l_eff_date;
175 exception
176 when no_data_found then return null;
177 end;
178 end get_date;
179
180 function get_index_for_date(p_date in date,
181 p_organization_id in number,
182 p_dept_id in number,
183 p_resource_id in number)
184 return varchar2
185 is
186 l_date_seq number;
187 l_shift_num number;
188 l_shift_start_date date;
189 l_shift_end_date date;
190 l_calendar_code varchar2(100);
191 begin
192
193 l_calendar_code := get_calendar_code(p_organization_id);
194 wip_ws_dl_util.get_first_dept_resource_shift
195 (p_cal_code =>l_calendar_code,
196 p_dept_id =>p_dept_id,
197 p_resource_id =>p_resource_id,
198 p_date =>p_date,
199 x_shift_seq =>l_date_seq,
200 x_shift_num =>l_shift_num,
201 x_shift_start_date =>l_shift_start_date,
202 x_shift_end_date =>l_shift_end_date);
203
204 return to_char(l_date_seq||':'||l_shift_num);
205 end get_index_for_date;
206
207 procedure handle_error(p_error_msg in varchar2,
208 p_stmt_num in number,
209 p_proc_name in varchar2)
210 is
211 begin
212 fnd_file.put_line(fnd_file.log,'Error in '||p_proc_name||'( stmt_num: '||p_stmt_num||') '||p_error_msg);
213 fnd_file.new_line(fnd_file.log, 3);
214 end handle_error;
215
216 /* To calculate metrics for the required period */
217 procedure calculate_metrics(retcode out nocopy number,
218 errbuf out nocopy varchar2,
219 p_organization_id in number)
220 is
221
222 /* Record type for storing metrics data for a particular employee */
223 type rec_emp_perf_temp IS record(
224 actual_date_seq number,
225 shift_num number,
226 shift_start date,
227 shift_end date,
228 shift_duration number,
229 act_att_hrs number,
230 dir_lab_hrs number,
231 sch_avl_hrs number,
232 earned_hrs number);
233
234 /* PL/SQL table for storing metrics data for a particular employee */
235 type t_emp_perf_temp is table of rec_emp_perf_temp index by varchar2(25);
236 v_emp_perf_temp t_emp_perf_temp;
237
238 type t_wip_lab_perf_rate is table of wip_labor_performance_rates%rowtype index by binary_integer;
239 v_wip_lab_perf_rate t_wip_lab_perf_rate;
240
241 type t_date_sequence is table of wip_labor_performance_rates.date_sequence%type index by binary_integer;
242 type t_shift_num is table of wip_labor_performance_rates.shift_num%type index by binary_integer;
243 type t_m1_att1 is table of wip_labor_performance_rates.metric1_attribute1%type index by binary_integer;
244 type t_m1_att2 is table of wip_labor_performance_rates.metric1_attribute2%type index by binary_integer;
245 type t_m2_att1 is table of wip_labor_performance_rates.metric2_attribute1%type index by binary_integer;
246 type t_m2_att2 is table of wip_labor_performance_rates.metric2_attribute2%type index by binary_integer;
247 type t_m3_att1 is table of wip_labor_performance_rates.metric3_attribute1%type index by binary_integer;
248 type t_m3_att2 is table of wip_labor_performance_rates.metric3_attribute2%type index by binary_integer;
249
250 v_date_sequence t_date_sequence;
251 v_shift_num t_shift_num;
252 v_m1_att1 t_m1_att1;
253 v_m1_att2 t_m1_att2;
254 v_m2_att1 t_m2_att1;
255 v_m2_att2 t_m2_att2;
256 v_m3_att1 t_m3_att1;
257 v_m3_att2 t_m3_att2;
258
259 /* cursor to get all employees for a particular organization */
260 cursor employees(org_id number) is
261 select bre.organization_id,
262 bdri.department_id,
263 bdri.resource_id,
264 bdri.instance_id,
265 bre.person_id
266 from per_all_people_f papf,
267 bom_resource_employees bre,
268 bom_dept_res_instances bdri,
269 bom_department_resources bdr,
270 bom_resources br
271 where papf.person_id = bre.person_id
272 and bre.instance_id = bdri.instance_id
273 and sysdate between papf.effective_start_date and nvl(papf.effective_end_date,sysdate+1)
274 and bre.resource_id = bdri.resource_id
275 and bdri.department_id = bdr.department_id
276 and bdri.resource_id = bdr.resource_id
277 and bdr.resource_id = br.resource_id
278 and bdr.available_24_hours_flag = 2
279 and wip_ws_labor_metric_pub.is_time_uom(br.unit_of_measure) = 1
280 and bre.organization_id = org_id
281 order by bdri.department_id,
282 bdri.resource_id;
283
284 /* cursor to get all preferences value for a particular organization */
285 cursor get_preferences(org_id number) is
286 select attribute_name,
287 substr(attribute_name,2,1) as identifier,
288 attribute_value_code
289 from wip_preference_values
290 where preference_id = 35
291 and level_id = 1
292 and sequence_number = (select sequence_number
293 from wip_preference_values
294 where preference_id = 35
295 and level_id = 1
296 and attribute_name = 'Org'
297 and attribute_value_code = to_char(org_id))
298 order by 1 desc;
299
300 /* This Cursor will get the information of all shifts for a department resource in the required period. */
301 -- Modified Date conversion logic for Bug 6972082.
302 cursor emp_shifts(p_calendar_code varchar2,
303 start_period date,
304 end_period date,
305 dept_id number,
306 res_id number) is
307 select trunc(bsd.seq_num) shift_date_seq,
308 bsd.shift_num shift_num,
309 bsd.shift_date + st.from_time/(60*60*24) shift_start_time,
310 bsd.shift_date + st.to_time/(60*60*24) shift_end_time,
311 (bsd.shift_date + st.to_time/(60*60))-(bsd.shift_date + st.from_time/(60*60)) shift_duration
312 from bom_shift_dates bsd,
313 (select bst.shift_num,
314 min(bst.from_time) from_time,
315 max(bst.to_time + decode(sign(bst.to_time - bst.from_time), -1, (24*60*60), 0)) to_time
316 from bom_shift_times bst
317 where bst.calendar_code = p_calendar_code
318 group by bst.shift_num) st,
319 bom_calendar_shifts bcs,
320 bom_resource_shifts brs
321 where bsd.calendar_code = p_calendar_code
322 and bsd.exception_set_id = -1
323 and bsd.shift_date between trunc(start_period) and trunc(end_period)
324 and bsd.shift_num = st.shift_num
325 and bsd.seq_num is not null
326 and bsd.calendar_code = bcs.calendar_code
327 and bsd.shift_num = bcs.shift_num
328 and fnd_date.canonical_to_date(to_char((bsd.shift_date + st.to_time/(60*60*24)),WIP_CONSTANTS.DATETIME_FMT)) < end_period
329 and brs.shift_num= bcs.shift_num
330 and brs.department_id = dept_id
331 and brs.resource_id = res_id;
332
333 /* cursor to get records from wip_resource_actual_times for calculating AAH */
334 cursor aah_records(org_id number,
335 emp_id number,
336 start_time date,
337 end_time date) is
338 select start_date as actual_date,
339 decode(action_flag,2,-duration,duration) as duration,
340 uom_code
341 from wip_resource_actual_times
342 where organization_id = org_id
343 and employee_id = emp_id
344 and wip_entity_id is null
345 and time_entry_mode in (6,8)
346 and start_date between start_time and end_time
347 and duration is not null;
348
349 /* cursor to get records from wip_resource_actual_times for calculating SAH */
350 cursor sah_records(org_id number,
351 emp_id number,
352 start_time date,
353 end_time date) is
354 select start_date as actual_date,
355 decode(action_flag,2,-duration,duration) as duration,
356 uom_code
357 from wip_resource_actual_times
358 where organization_id = org_id
359 and employee_id = emp_id
360 and wip_entity_id is null
361 and time_entry_mode =7
362 and start_date between start_time and end_time
363 and duration is not null;
364
365 /* cursor to get all records from wip_resource_actual_times for calculating DLH */
366 -- Lot based jobs also uses wip_resource_actual_times. So added condition on entity_type.
367 cursor dlh_records(org_id number,
368 dept_id number,
369 res_id number,
370 emp_id number,
371 start_time date,
372 end_time date) is
373 select wrat.start_date as actual_date,
374 decode(wrat.action_flag,2,-wrat.duration,wrat.duration) as duration,
375 wrat.uom_code
376 from wip_resource_actual_times wrat,
377 wip_operations wo,
378 wip_entities we
379 where wrat.organization_id = org_id
380 and wrat.organization_id= wo.organization_id
381 and wrat.wip_entity_id = wo.wip_entity_id
382 and we.organization_id = wo.organization_id
383 and we.wip_entity_id = wo.wip_entity_id
384 and we.entity_type=1
385 and wrat.operation_seq_num = wo.operation_seq_num
386 and wo.department_id = dept_id
387 and wrat.resource_id = res_id
388 and wrat.employee_id = emp_id
389 and wrat.wip_entity_id is not null
390 and wrat.duration is not null
391 and wrat.start_date between start_time and end_time;
392
393 /* Bug 7010115: cursor to get all Job-Ops from Clock-In records for calculating earned hours */
394 cursor clock_in_records(org_id number,
395 dept_id number,
396 res_id number,
397 emp_id number,
398 start_time date,
399 end_time date) is
400 select distinct wrat.wip_entity_id as wip_entity_id,
401 wrat.operation_seq_num as operation_seq_num,
402 get_index_for_date(wrat.start_date,wrat.organization_id,wo.department_id,res_id) as emp_index
403 from wip_resource_actual_times wrat,
404 wip_operations wo,
405 wip_entities we
406 where wrat.organization_id = org_id
407 and wrat.organization_id= wo.organization_id
408 and wrat.wip_entity_id = wo.wip_entity_id
409 and we.organization_id = wo.organization_id
410 and we.wip_entity_id = wo.wip_entity_id
411 and we.entity_type=1
412 and wrat.operation_seq_num = wo.operation_seq_num
413 and wo.department_id = dept_id
414 and wrat.resource_id = res_id
415 and wrat.employee_id = emp_id
416 and wrat.wip_entity_id is not null
417 and wrat.duration is not null
418 and wrat.start_date between start_time and end_time;
419
420 /* cursor to get all records from wip_move_transactions, wip_operations for obtaining completed quantity */
421 /* Modified for Bug 7010115. */
422 -- Lot based jobs should not be considered for earned hours. So added condition on entity_type.
423 cursor eh_records(org_id number,
424 start_time date,
425 end_time date,
426 wip_id number,
427 op_seq number,
428 res_id number,
429 indx varchar2)
430 is
431 select sum(nvl(t.move_qty,0)) as moved_qty
432 from
433 (select
434 wo.wip_entity_id as job,
435 wo.operation_seq_num as op,
436 fm_operation_seq_num as fm_op,
437 fm_intraoperation_step_type as fm_step,
438 to_operation_seq_num as to_op,
439 to_intraoperation_step_type as to_step,
440 decode(wmt.to_intraoperation_step_type,
441 1, (case when ((wmt.to_operation_seq_num > wo.operation_seq_num)) then wmt.primary_quantity
442 when ((wmt.to_operation_seq_num < wo.operation_seq_num)) then -1 * wmt.primary_quantity
443 when (wmt.to_operation_seq_num <= wmt.fm_operation_seq_num
444 and wmt.to_operation_seq_num = wo.operation_seq_num
445 and wmt.fm_intraoperation_step_type not in (4,5)) then -1 * wmt.primary_quantity
446 else 0 end),
447 2, (case when ((wmt.to_operation_seq_num > wo.operation_seq_num)) then wmt.primary_quantity
448 when ((wmt.to_operation_seq_num < wo.operation_seq_num)) then -1 * wmt.primary_quantity
449 when (wmt.to_operation_seq_num <= wmt.fm_operation_seq_num
450 and wmt.to_operation_seq_num = wo.operation_seq_num
451 and wmt.fm_intraoperation_step_type not in (4,5)) then -1 * wmt.primary_quantity
452 else 0 end),
453 3, (case when (wmt.to_operation_seq_num >= wo.operation_seq_num) then wmt.primary_quantity
454 when (wmt.to_operation_seq_num < wo.operation_seq_num
455 and (wmt.fm_intraoperation_step_type not in (4,5)
456 or wmt.fm_operation_seq_num <> wo.operation_seq_num)) then -1 * wmt.primary_quantity
457 else 0 end),
458 5, (case when wmt.to_operation_seq_num > wo.operation_seq_num then wmt.primary_quantity
459 when wmt.to_operation_seq_num < wo.operation_seq_num then -1 * wmt.primary_quantity
460 when wmt.to_operation_seq_num = wo.operation_seq_num then 0
461 else 0 end),
462 4, (case when wmt.to_operation_seq_num > wo.operation_seq_num then wmt.primary_quantity
463 when wmt.to_operation_seq_num < wo.operation_seq_num then -1 * wmt.primary_quantity
464 when wmt.to_operation_seq_num = wo.operation_seq_num then 0
465 else 0 end),
466 0) as move_qty,
467 get_index_for_date(wmt.transaction_date,wmt.organization_id,wo.department_id,res_id) as emp_index
468 from
469 wip_move_transactions wmt,
470 wip_operations wo,
471 wip_entities we
472 where
473 wo.organization_id = org_id
474 and wo.organization_id = wmt.organization_id
475 and wo.organization_id = we.organization_id
476 and wo.wip_entity_id = we.wip_entity_id
477 and we.entity_type=1
478 and wo.wip_entity_id = wmt.wip_entity_id
479 and wo.operation_seq_num = op_seq
480 and wo.wip_entity_id = wip_id
481 and wo.repetitive_schedule_id is null
482 and wmt.transaction_date between start_time and end_time
483 and ((wo.operation_seq_num >= wmt.fm_operation_seq_num + decode(sign(wmt.fm_intraoperation_step_type - 2),1,1,0)
484 and wo.operation_seq_num < wmt.to_operation_seq_num + decode(sign(wmt.to_intraoperation_step_type - 2),1,1,0)
485 and (wmt.to_operation_seq_num > wmt.fm_operation_seq_num
486 or (wmt.to_operation_seq_num = wmt.fm_operation_seq_num
487 and wmt.fm_intraoperation_step_type <= 2
488 and wmt.to_intraoperation_step_type > 2)))
489 or (wo.operation_seq_num < wmt.fm_operation_seq_num + decode(sign(wmt.fm_intraoperation_step_type-2),1,1,0)
490 and wo.operation_seq_num >= wmt.to_operation_seq_num + decode(sign(wmt.to_intraoperation_step_type-2),1,1,0)
491 and (wmt.fm_operation_seq_num > wmt.to_operation_seq_num
492 or (wmt.fm_operation_seq_num = wmt.to_operation_seq_num
493 and wmt.to_intraoperation_step_type <= 2
494 and wmt.fm_intraoperation_step_type > 2)))
495 or (wmt.fm_intraoperation_step_type in (4,5)
496 and wo.operation_seq_num = wmt.fm_operation_seq_num))) t
497 where
498 t.emp_index = indx;
499
500 cursor ear_hours_calc(org_id number,
501 we_ent_id number,
502 op_seq_num number,
503 res_id number,
504 move_qty number)
505 is
506 select usage_rate_or_amount *decode(sign(move_qty),-1,0,move_qty) usage_rate,uom_code,basis_type
507 from wip_operation_resources
508 where organization_id= org_id
509 and wip_entity_id= we_ent_id
510 and operation_seq_num= op_seq_num
511 and resource_id = res_id;
512
513 /* local variables */
514 l_prev_department_id number :=null;
515 l_prev_resource_id number :=null;
516 l_calendar_code varchar2(100) := null;
517 l_bom_uom_code varchar2(3) :=null;
518 l_time_uom_flag number :=null;
519 l_uom_code varchar2(3);
520 l_current_date date := null;
521 window_end_time date :=null;
522 window_start_time date :=null;
523
524 l_act_avl_hrs_required boolean := false;
525 l_dir_lab_hrs_required boolean := false;
526 l_sch_avl_hrs_required boolean := false;
527 l_earned_hrs_required boolean := false;
528
529 /* variables for preferences */
530 l_metric1_required boolean := false;
531 l_metric2_required boolean := false;
532 l_metric3_required boolean := false;
533 l_metric1_attribute1 number :=0;
534 l_metric1_attribute2 number :=0;
535 l_metric2_attribute1 number :=0;
536 l_metric2_attribute2 number :=0;
537 l_metric3_attribute1 number :=0;
538 l_metric3_attribute2 number :=0;
539
540 log_metric1 varchar2(30):= 'Disabled';
541 log_metric2 varchar2(30):= 'Disabled';
542 log_metric3 varchar2(30):= 'Disabled';
543 log_act_avl_hrs varchar2(30):= 'Not Required';
544 log_dir_lab_hrs varchar2(30):= 'Not Required';
545 log_sch_avl_hrs varchar2(30):= 'Not Required';
546 log_earned_hrs varchar2(30):= 'Not Required';
547
548 l_act_att_hrs number :=0;
549 l_dir_lab_hrs number :=0;
550 l_sch_avl_hrs number :=0;
551 l_earned_hrs number :=0;
552
553 g_user_id number;
554 g_user_login_id number;
555 g_program_appl_id number;
556 g_request_id number;
557 g_program_id number;
558 g_logLevel number;
559
560 l_date_seq number := null;
561 l_shift_num number := null;
562 l_shift_start_date date := null;
563 l_shift_end_date date := null;
564
565 l_stmt_num number := null;
566 l_proc_name varchar2(50) := 'WIP_WS_LABOR_METRIC_PUB.CALCULATE_METRICS';
567
568 l_org_code varchar2(3);
569 l_pgm_count number :=0;
570
571 emp_index varchar2(25) := null;
572 idx varchar2(25) := null;
573 new_index number;
574
575 x_error_msg varchar2(2000);
576 l_error_count number:=0;
577 l_conc_status boolean;
578
579 e_null_org_id exception;
580
581 is_aah_record_valid boolean;
582 is_sah_record_valid boolean;
583 is_dlh_record_valid boolean;
584 is_eh_record_valid boolean;
585
586 begin
587
588 l_stmt_num :=10;
589 g_user_id := fnd_global.user_id;
590 g_user_login_id := fnd_global.login_id;
591 g_program_appl_id := fnd_global.prog_appl_id;
592 g_request_id := fnd_global.conc_request_id;
593 g_program_id := fnd_global.conc_program_id;
594
595 g_logLevel := FND_LOG.g_current_runtime_level;
596
597 if p_organization_id is null then
598 raise e_null_org_id;
599 end if;
600
601 select organization_code
602 into l_org_code
603 from mtl_parameters
604 where organization_id = p_organization_id;
605
606 wip_ws_util.trace_log('Launching Labor Metrics Calculation for Organization: '||l_org_code);
607
608 l_stmt_num :=20;
609
610 /* If the calculation program is running for this org already, then error out.
611 Bug 6891668. Modified Logic for Checking Concurrency */
612
613 select count(1)
614 into l_pgm_count
615 from fnd_concurrent_requests
616 where program_application_id = g_program_appl_id
617 and concurrent_program_id = g_program_id
618 and upper(phase_code) = 'R'
619 and argument1 = to_char(p_organization_id);
620
621 if (l_pgm_count > 1) then
622 fnd_message.set_name('WIP','WIP_RUNNING_LABOR_PRG');
623 fnd_message.set_token('ORG', to_char(l_org_code));
624 x_error_msg := fnd_message.get;
625 wip_ws_util.trace_log('Error in '||l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
626 wip_ws_util.trace_log('Unable to run calculation program for this organization. Please try after some time.');
627 retcode := 2;
628 l_conc_status := FND_CONCURRENT.SET_COMPLETION_STATUS('ERROR',
629 'Errors encountered in calculation program, please check the log file.');
630 return;
631 end if;
632
633 /* Get window_end_time and window_start_time to determine the
634 Time window for metrics calculation. */
635
636 select sysdate
637 into l_current_date
638 from dual;
639
640 l_stmt_num :=30;
641
642 l_bom_uom_code := fnd_profile.value('BOM:HOUR_UOM_CODE');
643 l_calendar_code := get_calendar_code(p_organization_id);
644 window_end_time := get_period_end(l_calendar_code,l_current_date);
645 window_start_time := get_period_start(p_organization_id,window_end_time);
646
647 if (g_logLevel <= wip_constants.trace_logging) then
648 wip_ws_util.trace_log('Calendar: '||l_calendar_code);
649 wip_ws_util.trace_log('Start Time: '||to_char(window_start_time,WIP_CONSTANTS.DATETIME_FMT));
650 wip_ws_util.trace_log('End Time: '||to_char(window_end_time,WIP_CONSTANTS.DATETIME_FMT));
651 wip_ws_util.trace_log('Base Time UOM: '||l_bom_uom_code);
652 end if;
653
654 l_stmt_num :=40;
655 /* Check for the metrics preferences and its requirement: Start */
656
657 for preferences in get_preferences(p_organization_id) loop
658 if preferences.identifier = '1' then
659 if l_metric1_required then
660 if preferences.attribute_value_code ='1' then /* 1-AAH,2-SAH,3-DLH,4-EH */
661 l_act_avl_hrs_required := true;
662 log_act_avl_hrs := 'Required';
663 if preferences.attribute_name = 'M1Attribute1' then
664 l_metric1_attribute1 :=1;
665 else
666 l_metric1_attribute2 :=1;
667 end if;
668 elsif preferences.attribute_value_code ='2' then
669 l_sch_avl_hrs_required := true;
670 log_sch_avl_hrs :='Required';
671 if preferences.attribute_name = 'M1Attribute1' then
672 l_metric1_attribute1 :=2;
673 else
674 l_metric1_attribute2 :=2;
675 end if;
676 elsif preferences.attribute_value_code ='3' then
677 l_dir_lab_hrs_required := true;
678 log_dir_lab_hrs := 'Required';
679 if preferences.attribute_name = 'M1Attribute1' then
680 l_metric1_attribute1 :=3;
681 else
682 l_metric1_attribute2 :=3;
683 end if;
684 else
685 l_earned_hrs_required := true;
686 log_earned_hrs := 'Required';
687 if preferences.attribute_name = 'M1Attribute1' then
688 l_metric1_attribute1 :=4;
689 else
690 l_metric1_attribute2 :=4;
691 end if;
692 end if;
693 end if;
694 if preferences.attribute_name = 'M1Enabled' and preferences.attribute_value_code ='1' then
695 l_metric1_required := true;
696 log_metric1 := 'Enabled';
697 end if;
698 elsif preferences.identifier = '2' then
699 if l_metric2_required then
700 if preferences.attribute_value_code ='1' then /* 1-AAH,2-SAH,3-DLH,4-EH */
701 l_act_avl_hrs_required := true;
702 log_act_avl_hrs := 'Required';
703 if preferences.attribute_name = 'M2Attribute1' then
704 l_metric2_attribute1 :=1;
705 else
706 l_metric2_attribute2 :=1;
707 end if;
708 elsif preferences.attribute_value_code ='2' then
709 l_sch_avl_hrs_required := true;
710 log_sch_avl_hrs :='Required';
711 if preferences.attribute_name = 'M2Attribute1' then
712 l_metric2_attribute1 :=2;
713 else
714 l_metric2_attribute2 :=2;
715 end if;
716 elsif preferences.attribute_value_code ='3' then
717 l_dir_lab_hrs_required := true;
718 log_dir_lab_hrs := 'Required';
719 if preferences.attribute_name = 'M2Attribute1' then
720 l_metric2_attribute1 :=3;
721 else
722 l_metric2_attribute2 :=3;
723 end if;
724 else
725 l_earned_hrs_required := true;
726 log_earned_hrs := 'Required';
727 if preferences.attribute_name = 'M2Attribute1' then
728 l_metric2_attribute1 :=4;
729 else
730 l_metric2_attribute2 :=4;
731 end if;
732 end if;
733 end if;
734 if preferences.attribute_name = 'M2Enabled' and preferences.attribute_value_code ='1' then
735 l_metric2_required := true;
736 log_metric2 := 'Enabled';
737 end if;
738 elsif preferences.identifier = '3' then
739 if l_metric3_required then
740 if preferences.attribute_value_code ='1' then /* 1-AAH,2-SAH,3-DLH,4-EH */
741 l_act_avl_hrs_required := true;
742 log_act_avl_hrs := 'Required';
743 if preferences.attribute_name = 'M3Attribute1' then
744 l_metric3_attribute1 :=1;
745 else
746 l_metric3_attribute2 :=1;
747 end if;
748 elsif preferences.attribute_value_code ='2' then
749 l_sch_avl_hrs_required := true;
750 log_sch_avl_hrs :='Required';
751 if preferences.attribute_name = 'M3Attribute1' then
752 l_metric3_attribute1 :=2;
753 else
754 l_metric3_attribute2 :=2;
755 end if;
756 elsif preferences.attribute_value_code ='3' then
757 l_dir_lab_hrs_required := true;
758 log_dir_lab_hrs := 'Required';
759 if preferences.attribute_name = 'M3Attribute1' then
760 l_metric3_attribute1 :=3;
761 else
762 l_metric3_attribute2 :=3;
763 end if;
764 else
765 l_earned_hrs_required := true;
766 log_earned_hrs := 'Required';
767 if preferences.attribute_name = 'M3Attribute1' then
768 l_metric3_attribute1 :=4;
769 else
770 l_metric3_attribute2 :=4;
771 end if;
772 end if;
773 end if;
774 if preferences.attribute_name = 'M3Enabled' and preferences.attribute_value_code ='1' then
775 l_metric3_required := true;
776 log_metric3 := 'Enabled';
777 end if;
778 end if;
779 end loop;
780
781 l_stmt_num :=50;
782
783 if (g_logLevel <= wip_constants.trace_logging) then
784
785 wip_ws_util.trace_log('Metric 1: '||log_metric1);
786 wip_ws_util.trace_log('Metric 2: '||log_metric2);
787 wip_ws_util.trace_log('Metric 3: '||log_metric3);
788
789 wip_ws_util.trace_log('Actual Attendance Hours: '||log_act_avl_hrs);
790 wip_ws_util.trace_log('Scheduled Available Hours: '||log_sch_avl_hrs);
791 wip_ws_util.trace_log('Direct Labor Hours: '||log_dir_lab_hrs);
792 wip_ws_util.trace_log('Earned Hours: '||log_earned_hrs);
793
794 end if;
795
796 /* Check for the metrics preferences and its requirement: End */
797
798 if l_metric1_required or l_metric2_required or l_metric3_required then
799 /* Delete existing records in wip_labor_performance_rates table for the org.*/
800
801 delete from wip_labor_performance_rates
802 where organization_id= p_organization_id;
803
804 l_stmt_num :=60;
805
806 if (g_logLevel <= wip_constants.trace_logging) then
807 wip_ws_util.trace_log('Deleted Existing records for this Organization.');
808 end if;
809 /* calculate the metrics for every employee associated to any of
810 the department for this organization. */
811 new_index :=0;
812 for employee in employees(p_organization_id) Loop
813
814 if (g_logLevel <= wip_constants.trace_logging) then
815 wip_ws_util.trace_log('Calculation for Emp with Dep_Id: '||to_char(employee.department_id)
816 ||' Res_Id: '||to_char(employee.resource_id)
817 ||' Pers_Id: '||to_char(employee.person_id));
818 end if;
819
820 if ( l_prev_department_id is null or
821 l_prev_resource_id is null or
822 employee.department_id <> l_prev_department_id or
823 employee.resource_id <> l_prev_resource_id)
824 then
825 l_stmt_num :=70;
826 v_emp_perf_temp.delete;
827 for emp_shift in emp_shifts(l_calendar_code,
828 window_start_time,
829 window_end_time,
830 employee.department_id,
831 employee.resource_id)
832 loop
833 l_stmt_num :=80;
834 emp_index := to_char(emp_shift.shift_date_seq||':'||emp_shift.shift_num);
835 v_emp_perf_temp(emp_index).actual_date_seq :=emp_shift.shift_date_seq;
836 v_emp_perf_temp(emp_index).shift_num :=emp_shift.shift_num;
837 v_emp_perf_temp(emp_index).shift_start :=emp_shift.shift_start_time;
838 v_emp_perf_temp(emp_index).shift_end :=emp_shift.shift_end_time;
839 v_emp_perf_temp(emp_index).shift_duration :=emp_shift.shift_duration;
840 v_emp_perf_temp(emp_index).act_att_hrs :=0;
841 v_emp_perf_temp(emp_index).dir_lab_hrs :=0;
842 v_emp_perf_temp(emp_index).sch_avl_hrs :=0;
843 v_emp_perf_temp(emp_index).earned_hrs :=0;
844 if (g_logLevel <= wip_constants.trace_logging) then
845 wip_ws_util.trace_log('Employee Shift Info: '||emp_index);
846 end if;
847 end loop;
848 if (g_logLevel <= wip_constants.trace_logging) then
849 wip_ws_util.trace_log('Re-Creating Shift Information for Employee');
850 end if;
851 else
852 l_stmt_num :=90;
853 emp_index := v_emp_perf_temp.first;
854 while emp_index <= v_emp_perf_temp.last loop
855 v_emp_perf_temp(emp_index).act_att_hrs :=0;
856 v_emp_perf_temp(emp_index).dir_lab_hrs :=0;
857 v_emp_perf_temp(emp_index).sch_avl_hrs :=0;
858 v_emp_perf_temp(emp_index).earned_hrs :=0;
859 emp_index := v_emp_perf_temp.next(emp_index);
860 end loop;
861
862 if (g_logLevel <= wip_constants.trace_logging) then
863 wip_ws_util.trace_log('Re-Using Shift Information for Employee');
864 end if;
865 end if;
866
867 if l_act_avl_hrs_required then /* Calculate actual available hours here. */
868 l_stmt_num :=100;
869 for emp_act_avl_hrs in aah_records(p_organization_id,
870 employee.person_id,
871 window_start_time,
872 window_end_time)
873 loop
874 l_stmt_num :=110;
875 is_aah_record_valid := true;
876 wip_ws_dl_util.get_first_dept_resource_shift
877 (p_cal_code =>l_calendar_code,
878 p_dept_id =>employee.department_id,
879 p_resource_id =>employee.resource_id,
880 p_date =>emp_act_avl_hrs.actual_date,
881 x_shift_seq =>l_date_seq,
882 x_shift_num =>l_shift_num,
883 x_shift_start_date =>l_shift_start_date,
884 x_shift_end_date =>l_shift_end_date);
885
886 /* UOM validations and conversions */
887 l_time_uom_flag := is_time_uom(emp_act_avl_hrs.uom_code);
888 l_stmt_num :=120;
889 -- Modified for bug 6972129.
890 if l_time_uom_flag = 2 then
891 if (g_logLevel <= wip_constants.trace_logging) then
892 fnd_message.set_name('WIP','WIP_LM_TIME_UOM');
893 fnd_message.set_token('EMP', to_char(employee.person_id));
894 x_error_msg := fnd_message.get;
895 wip_ws_util.trace_log(l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
896 --l_error_count := l_error_count + 1;
897 end if;
898 is_aah_record_valid := false;
899 end if;
900 if is_aah_record_valid then
901 if emp_act_avl_hrs.duration is not null and emp_act_avl_hrs.uom_code <> l_bom_uom_code then
902 l_stmt_num :=130;
903 l_act_att_hrs := inv_convert.inv_um_convert(item_id => -1,
904 precision => 38,
905 from_quantity => emp_act_avl_hrs.duration,
906 from_unit => emp_act_avl_hrs.uom_code,
907 to_unit => l_bom_uom_code,
908 from_name => null,
909 to_name => null);
910 else
911 l_act_att_hrs := emp_act_avl_hrs.duration;
912 end if;
913 l_stmt_num :=140;
914 -- Modified for Bug 7150089. Added this condition to avoid calculation if a shift
915 -- exists across multiple days and record is present for first day in that shift.
916 if v_emp_perf_temp.exists(to_char(l_date_seq||':'||l_shift_num)) then
917 v_emp_perf_temp(to_char(l_date_seq||':'||l_shift_num)).act_att_hrs :=
918 v_emp_perf_temp(to_char(l_date_seq||':'||l_shift_num)).act_att_hrs+l_act_att_hrs;
919
920 if (g_logLevel <= wip_constants.trace_logging) then
921 wip_ws_util.trace_log('Dep: '||to_char(employee.department_id)||
922 ' Res: '||to_char(employee.resource_id)||
923 ' Pers: '||to_char(employee.person_id)||
924 ' Date: '||to_char(emp_act_avl_hrs.actual_date,WIP_CONSTANTS.DATETIME_FMT)||
925 ' Shift Seq: '||to_char(l_date_seq)||
926 ' Shift Num: '||to_char(l_shift_num)||
927 ' AAH Value: '||to_char(l_act_att_hrs));
928 end if;
929 end if;
930 end if;
931 end loop;
932 end if; /* if l_act_avl_hrs_required then */
933
934 if l_sch_avl_hrs_required then /* Calculate scheduled available hours here. */
935 l_stmt_num :=150;
936 /* Add Code for capacity changes and exceptions and factor it on the shift duration. */
937 emp_index := v_emp_perf_temp.first;
938 while emp_index <= v_emp_perf_temp.last loop
939 v_emp_perf_temp(emp_index).sch_avl_hrs := v_emp_perf_temp(emp_index).shift_duration;
940 emp_index := v_emp_perf_temp.next(emp_index);
941 end loop;
942 l_stmt_num :=160;
943 for emp_sch_avl_hrs in sah_records(p_organization_id,
944 employee.person_id,
945 window_start_time,
946 window_end_time)
947 loop
948 l_stmt_num :=170;
949 is_sah_record_valid :=true;
950 wip_ws_dl_util.get_first_dept_resource_shift
951 (p_cal_code =>l_calendar_code,
952 p_dept_id =>employee.department_id,
953 p_resource_id =>employee.resource_id,
954 p_date =>emp_sch_avl_hrs.actual_date,
955 x_shift_seq =>l_date_seq,
956 x_shift_num =>l_shift_num,
957 x_shift_start_date =>l_shift_start_date,
958 x_shift_end_date =>l_shift_end_date);
959
960 /* UOM validations and conversions */
961 l_time_uom_flag := is_time_uom(emp_sch_avl_hrs.uom_code);
962 l_stmt_num :=180;
963 -- Modified for bug 6972129.
964 if l_time_uom_flag = 2 then
965 if (g_logLevel <= wip_constants.trace_logging) then
966 fnd_message.set_name('WIP','WIP_LM_TIME_UOM');
967 fnd_message.set_token('EMP', to_char(employee.person_id));
968 x_error_msg := fnd_message.get;
969 wip_ws_util.trace_log(l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
970 --l_error_count := l_error_count + 1;
971 end if;
972 is_sah_record_valid :=false;
973 end if;
974 if is_sah_record_valid then
975 if emp_sch_avl_hrs.duration is not null and emp_sch_avl_hrs.uom_code <> l_bom_uom_code then
976 l_stmt_num :=190;
977 l_sch_avl_hrs := inv_convert.inv_um_convert(item_id => -1,
978 precision => 38,
979 from_quantity => emp_sch_avl_hrs.duration,
980 from_unit => emp_sch_avl_hrs.uom_code,
981 to_unit => l_bom_uom_code,
982 from_name => null,
983 to_name => null);
984 else
985 l_sch_avl_hrs := emp_sch_avl_hrs.duration;
986 end if;
987 l_stmt_num :=200;
988 -- Modified for Bug 7150089. Added this condition to avoid calculation if a shift
989 -- exists across multiple days and record is present for first day in that shift.
990 if v_emp_perf_temp.exists(to_char(l_date_seq||':'||l_shift_num)) then
991 v_emp_perf_temp(to_char(l_date_seq||':'||l_shift_num)).sch_avl_hrs :=
992 v_emp_perf_temp(to_char(l_date_seq||':'||l_shift_num)).sch_avl_hrs+l_sch_avl_hrs;
993
994 if (g_logLevel <= wip_constants.trace_logging) then
995 wip_ws_util.trace_log('Dep: '||to_char(employee.department_id)||
996 ' Res: '||to_char(employee.resource_id)||
997 ' Pers: '||to_char(employee.person_id)||
998 ' Date: '||to_char(emp_sch_avl_hrs.actual_date,WIP_CONSTANTS.DATETIME_FMT)||
999 ' Shift Seq: '||to_char(l_date_seq)||
1000 ' Shift Num: '||to_char(l_shift_num)||
1001 ' SAH Value: '||to_char(l_sch_avl_hrs));
1002 end if;
1003 end if;
1004 end if;
1005 end loop;
1006 end if; /* if l_sch_avl_hrs_required then */
1007
1008 if l_dir_lab_hrs_required then /* Calculate direct labor hours here. */
1009 l_stmt_num :=210;
1010 for emp_dir_lab_hrs in dlh_records(p_organization_id,
1011 employee.department_id,
1012 employee.resource_id,
1013 employee.person_id,
1014 window_start_time,
1015 window_end_time)
1016 loop
1017 l_stmt_num :=220;
1018 is_dlh_record_valid :=true;
1019 wip_ws_dl_util.get_first_dept_resource_shift
1020 (p_cal_code =>l_calendar_code,
1021 p_dept_id =>employee.department_id,
1022 p_resource_id =>employee.resource_id,
1023 p_date =>emp_dir_lab_hrs.actual_date,
1024 x_shift_seq =>l_date_seq,
1025 x_shift_num =>l_shift_num,
1026 x_shift_start_date =>l_shift_start_date,
1027 x_shift_end_date =>l_shift_end_date);
1028
1029 /* UOM validations and conversions */
1030 l_time_uom_flag := is_time_uom(emp_dir_lab_hrs.uom_code);
1031 l_stmt_num :=230;
1032 -- Modified for bug 6972129.
1033 if l_time_uom_flag = 2 then
1034 if (g_logLevel <= wip_constants.trace_logging) then
1035 fnd_message.set_name('WIP','WIP_LM_TIME_UOM');
1036 fnd_message.set_token('EMP', to_char(employee.person_id));
1037 x_error_msg := fnd_message.get;
1038 wip_ws_util.trace_log(l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
1039 --l_error_count := l_error_count + 1;
1040 end if;
1041 is_dlh_record_valid :=false;
1042 end if;
1043 if is_dlh_record_valid then
1044 if emp_dir_lab_hrs.duration is not null and emp_dir_lab_hrs.uom_code <> l_bom_uom_code then
1045 l_stmt_num :=240;
1046 l_dir_lab_hrs := inv_convert.inv_um_convert(item_id => -1,
1047 precision => 38,
1048 from_quantity => emp_dir_lab_hrs.duration,
1049 from_unit => emp_dir_lab_hrs.uom_code,
1050 to_unit => l_bom_uom_code,
1051 from_name => null,
1052 to_name => null);
1053 else
1054 l_dir_lab_hrs := emp_dir_lab_hrs.duration;
1055 end if;
1056 l_stmt_num :=250;
1057 idx := to_char(l_date_seq||':'||l_shift_num);
1058 l_stmt_num :=260;
1059 -- Modified for Bug 7150089. Added this condition to avoid calculation if a shift
1060 -- exists across multiple days and record is present for first day in that shift.
1061 if v_emp_perf_temp.exists(to_char(l_date_seq||':'||l_shift_num)) then
1062 v_emp_perf_temp(to_char(l_date_seq||':'||l_shift_num)).dir_lab_hrs :=
1063 v_emp_perf_temp(to_char(l_date_seq||':'||l_shift_num)).dir_lab_hrs+l_dir_lab_hrs;
1064
1065 if (g_logLevel <= wip_constants.trace_logging) then
1066 wip_ws_util.trace_log('Dep: '||to_char(employee.department_id)||
1067 ' Res: '||to_char(employee.resource_id)||
1068 ' Pers: '||to_char(employee.person_id)||
1069 ' Date: '||to_char(emp_dir_lab_hrs.actual_date,WIP_CONSTANTS.DATETIME_FMT)||
1070 ' Shift Seq: '||to_char(l_date_seq)||
1071 ' Shift Num: '||to_char(l_shift_num)||
1072 ' DLH Value: '||to_char(l_dir_lab_hrs));
1073 end if;
1074 end if;
1075 end if;
1076 l_stmt_num :=270;
1077 end loop;
1078 end if; /* l_dir_lab_hrs_required */
1079 l_stmt_num :=280;
1080 if l_earned_hrs_required then /* Calculate earned hours here. */
1081 l_stmt_num :=290;
1082 /* Modified for Bug 7010115. */
1083 for emp_clock_rec in clock_in_records(p_organization_id,
1084 employee.department_id,
1085 employee.resource_id,
1086 employee.person_id,
1087 window_start_time,
1088 window_end_time)
1089 loop
1090 for emp_earned_hrs in eh_records(p_organization_id,
1091 window_start_time,
1092 window_end_time,
1093 emp_clock_rec.wip_entity_id,
1094 emp_clock_rec.operation_seq_num,
1095 employee.resource_id,
1096 emp_clock_rec.emp_index)
1097 loop
1098 for earned_hrs_rates in ear_hours_calc(p_organization_id,
1099 emp_clock_rec.wip_entity_id,
1100 emp_clock_rec.operation_seq_num,
1101 employee.resource_id,
1102 emp_earned_hrs.moved_qty)
1103 loop
1104 is_eh_record_valid := true;
1105 l_earned_hrs := earned_hrs_rates.usage_rate;
1106 l_uom_code := earned_hrs_rates.uom_code ;
1107 l_time_uom_flag := is_time_uom(l_uom_code);
1108 l_stmt_num :=310;
1109 -- Modified for bug 6972129.
1110 if l_time_uom_flag = 2 then
1111 if (g_logLevel <= wip_constants.trace_logging) then
1112 fnd_message.set_name('WIP','WIP_LM_TIME_UOM');
1113 fnd_message.set_token('EMP', to_char(employee.person_id));
1114 x_error_msg := fnd_message.get;
1115 wip_ws_util.trace_log(l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
1116 --l_error_count := l_error_count + 1;
1117 end if;
1118 is_eh_record_valid := false;
1119 end if;
1120 if earned_hrs_rates.basis_type = 2 then
1121 if (g_logLevel <= wip_constants.trace_logging) then
1122 fnd_message.set_name('WIP','WIP_LM_LOT_BASED_RES');
1123 fnd_message.set_token('EMP', to_char(employee.person_id));
1124 x_error_msg := fnd_message.get;
1125 wip_ws_util.trace_log(l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
1126 --l_error_count := l_error_count + 1;
1127 end if;
1128 is_eh_record_valid := false;
1129 end if;
1130 if is_eh_record_valid then
1131 if l_earned_hrs is not null and l_uom_code <> l_bom_uom_code then
1132 l_stmt_num :=320;
1133 l_earned_hrs := inv_convert.inv_um_convert(item_id => -1,
1134 precision => 38,
1135 from_quantity => l_earned_hrs,
1136 from_unit => l_uom_code,
1137 to_unit => l_bom_uom_code,
1138 from_name => null,
1139 to_name => null);
1140 end if;
1141 l_stmt_num :=330;
1142 -- Modified for Bug 7150089. Added this condition to avoid calculation if a shift
1143 -- exists across multiple days and record is present for first day in that shift.
1144 if v_emp_perf_temp.exists(emp_clock_rec.emp_index) then
1145 v_emp_perf_temp(emp_clock_rec.emp_index).earned_hrs :=
1146 v_emp_perf_temp(emp_clock_rec.emp_index).earned_hrs+l_earned_hrs;
1147
1148 if (g_logLevel <= wip_constants.trace_logging) then
1149 wip_ws_util.trace_log('Dep: '||to_char(employee.department_id)||
1150 ' Res: '||to_char(employee.resource_id)||
1151 ' Pers: '||to_char(employee.person_id)||
1152 ' Index: '||to_char(emp_clock_rec.emp_index)||
1153 ' Move Qty: '||to_char(emp_earned_hrs.moved_qty)||
1154 ' EH Value: '||to_char(l_earned_hrs));
1155 end if;
1156 end if;
1157 end if;
1158 l_stmt_num :=340;
1159 end loop;
1160 end loop;
1161 end loop;
1162 end if; /* if l_earned_hrs_required then */
1163 l_stmt_num :=350;
1164
1165 /* transfer data from collection indexed by varchar2 to a collection
1166 indexed by binary_integer so that we can bulk insert in the table.
1167 Also initialize the new collection always. */
1168 emp_index := v_emp_perf_temp.first;
1169 while emp_index <= v_emp_perf_temp.last loop
1170 if emp_index <> ':' or emp_index is not null then
1171 new_index := new_index+1;
1172 v_wip_lab_perf_rate(new_index).Organization_id := p_organization_id;
1173 v_wip_lab_perf_rate(new_index).Department_id := employee.department_id;
1174 v_wip_lab_perf_rate(new_index).Resource_id := employee.resource_id;
1175 v_wip_lab_perf_rate(new_index).Employee_id := employee.person_id;
1176 v_wip_lab_perf_rate(new_index).date_sequence := v_emp_perf_temp(emp_index).actual_date_seq;
1177 v_wip_lab_perf_rate(new_index).Shift_num := v_emp_perf_temp(emp_index).shift_num;
1178 case l_metric1_attribute1 when 1 then v_wip_lab_perf_rate(new_index).Metric1_attribute1 := v_emp_perf_temp(emp_index).act_att_hrs;
1179 when 2 then v_wip_lab_perf_rate(new_index).Metric1_attribute1 := v_emp_perf_temp(emp_index).sch_avl_hrs;
1180 when 3 then v_wip_lab_perf_rate(new_index).Metric1_attribute1 := v_emp_perf_temp(emp_index).dir_lab_hrs;
1181 when 4 then v_wip_lab_perf_rate(new_index).Metric1_attribute1 := v_emp_perf_temp(emp_index).earned_hrs;
1182 else v_wip_lab_perf_rate(new_index).Metric1_attribute1 :=0;
1183 end case;
1184 case l_metric1_attribute2 when 1 then v_wip_lab_perf_rate(new_index).Metric1_attribute2 := v_emp_perf_temp(emp_index).act_att_hrs;
1185 when 2 then v_wip_lab_perf_rate(new_index).Metric1_attribute2 := v_emp_perf_temp(emp_index).sch_avl_hrs;
1186 when 3 then v_wip_lab_perf_rate(new_index).Metric1_attribute2 := v_emp_perf_temp(emp_index).dir_lab_hrs;
1187 when 4 then v_wip_lab_perf_rate(new_index).Metric1_attribute2 := v_emp_perf_temp(emp_index).earned_hrs;
1188 else v_wip_lab_perf_rate(new_index).Metric1_attribute2 :=0;
1189 end case;
1190 case l_metric2_attribute1 when 1 then v_wip_lab_perf_rate(new_index).Metric2_attribute1 := v_emp_perf_temp(emp_index).act_att_hrs;
1191 when 2 then v_wip_lab_perf_rate(new_index).Metric2_attribute1 := v_emp_perf_temp(emp_index).sch_avl_hrs;
1192 when 3 then v_wip_lab_perf_rate(new_index).Metric2_attribute1 := v_emp_perf_temp(emp_index).dir_lab_hrs;
1193 when 4 then v_wip_lab_perf_rate(new_index).Metric2_attribute1 := v_emp_perf_temp(emp_index).earned_hrs;
1194 else v_wip_lab_perf_rate(new_index).Metric2_attribute1 :=0;
1195 end case;
1196 case l_metric2_attribute2 when 1 then v_wip_lab_perf_rate(new_index).Metric2_attribute2 := v_emp_perf_temp(emp_index).act_att_hrs;
1197 when 2 then v_wip_lab_perf_rate(new_index).Metric2_attribute2 := v_emp_perf_temp(emp_index).sch_avl_hrs;
1198 when 3 then v_wip_lab_perf_rate(new_index).Metric2_attribute2 := v_emp_perf_temp(emp_index).dir_lab_hrs;
1199 when 4 then v_wip_lab_perf_rate(new_index).Metric2_attribute2 := v_emp_perf_temp(emp_index).earned_hrs;
1200 else v_wip_lab_perf_rate(new_index).Metric2_attribute2 :=0;
1201 end case;
1202 case l_metric3_attribute1 when 1 then v_wip_lab_perf_rate(new_index).Metric3_attribute1 := v_emp_perf_temp(emp_index).act_att_hrs;
1203 when 2 then v_wip_lab_perf_rate(new_index).Metric3_attribute1 := v_emp_perf_temp(emp_index).sch_avl_hrs;
1204 when 3 then v_wip_lab_perf_rate(new_index).Metric3_attribute1 := v_emp_perf_temp(emp_index).dir_lab_hrs;
1205 when 4 then v_wip_lab_perf_rate(new_index).Metric3_attribute1 := v_emp_perf_temp(emp_index).earned_hrs;
1206 else v_wip_lab_perf_rate(new_index).Metric3_attribute1 :=0;
1207 end case;
1208 case l_metric3_attribute2 when 1 then v_wip_lab_perf_rate(new_index).Metric3_attribute2 := v_emp_perf_temp(emp_index).act_att_hrs;
1209 when 2 then v_wip_lab_perf_rate(new_index).Metric3_attribute2 := v_emp_perf_temp(emp_index).sch_avl_hrs;
1210 when 3 then v_wip_lab_perf_rate(new_index).Metric3_attribute2 := v_emp_perf_temp(emp_index).dir_lab_hrs;
1211 when 4 then v_wip_lab_perf_rate(new_index).Metric3_attribute2 := v_emp_perf_temp(emp_index).earned_hrs;
1212 else v_wip_lab_perf_rate(new_index).Metric3_attribute2 :=0;
1213 end case;
1214 v_wip_lab_perf_rate(new_index).Created_by := g_user_id;
1215 v_wip_lab_perf_rate(new_index).Creation_date := sysdate;
1216 v_wip_lab_perf_rate(new_index).Last_updated_by := g_user_id;
1217 v_wip_lab_perf_rate(new_index).Last_update_date := sysdate;
1218 v_wip_lab_perf_rate(new_index).Last_update_login := g_user_login_id;
1219 v_wip_lab_perf_rate(new_index).Object_version_number := 1;
1220 v_wip_lab_perf_rate(new_index).Request_id := g_request_id;
1221 v_wip_lab_perf_rate(new_index).Program_id := g_program_id;
1222 v_wip_lab_perf_rate(new_index).Program_application_id := g_program_appl_id;
1223 v_wip_lab_perf_rate(new_index).Program_update_date := sysdate;
1224 end if;
1225 emp_index := v_emp_perf_temp.next(emp_index);
1226 end loop;
1227 l_stmt_num :=360;
1228
1229 if (g_logLevel <= wip_constants.trace_logging) then
1230 wip_ws_util.trace_log(' Calculation Completed for employee Dep: '||to_char(employee.department_id)||
1231 ' Res: '||to_char(employee.resource_id)||
1232 ' Pers: '||to_char(employee.person_id));
1233 end if;
1234 l_stmt_num :=370;
1235
1236 l_prev_department_id := employee.department_id ;
1237 l_prev_resource_id := employee.resource_id ;
1238
1239 end loop; /* for employee in employees(p_organization_id) */
1240
1241 l_stmt_num :=380;
1242
1243 /* Bulk Insert Records into Metrics Table */
1244 forall cntr in v_wip_lab_perf_rate.first..v_wip_lab_perf_rate.last
1245 INSERT into WIP_LABOR_PERFORMANCE_RATES values v_wip_lab_perf_rate(cntr);
1246
1247 l_stmt_num :=390;
1248 if (g_logLevel <= wip_constants.trace_logging) then
1249 wip_ws_util.trace_log('Insertion of all calculated records is successful.');
1250 end if;
1251
1252 /* Since attendance hours is entered for an employee at org level and distributed across all departments
1253 if the employee is associated to multiple departments. So org level attendance hours will be over shooted
1254 when summing the value in the dashboard. So we compute the org level summary and insert into metrics table.*/
1255 select t.date_sequence,
1256 t.shift_num,
1257 sum(t.m1_att1),
1258 sum(t.m1_att2),
1259 sum(t.m2_att1),
1260 sum(t.m2_att2),
1261 sum(t.m3_att1),
1262 sum(t.m3_att2)
1263 bulk collect into
1264 v_date_sequence,
1265 v_shift_num,
1266 v_m1_att1,
1267 v_m1_att2,
1268 v_m2_att1,
1269 v_m2_att2,
1270 v_m3_att1,
1271 v_m3_att2
1272 from (
1273 select date_sequence,
1274 shift_num,
1275 decode(l_metric1_attribute1,1,max(metric1_attribute1),sum(metric1_attribute1)) m1_att1,
1276 decode(l_metric1_attribute2,1,max(metric1_attribute2),sum(metric1_attribute2)) m1_att2,
1277 decode(l_metric2_attribute1,1,max(metric2_attribute1),sum(metric2_attribute1)) m2_att1,
1278 decode(l_metric2_attribute2,1,max(metric2_attribute2),sum(metric2_attribute2)) m2_att2,
1279 decode(l_metric3_attribute1,1,max(metric3_attribute1),sum(metric3_attribute1)) m3_att1,
1280 decode(l_metric3_attribute2,1,max(metric3_attribute2),sum(metric3_attribute2)) m3_att2
1281 from wip_labor_performance_rates
1282 where organization_id = p_organization_id
1283 group by
1284 date_sequence,
1285 shift_num,
1286 employee_id
1287 )t
1288 group by
1289 t.date_sequence,
1290 t.shift_num;
1291
1292 l_stmt_num :=400;
1293 if (g_logLevel <= wip_constants.trace_logging) then
1294 wip_ws_util.trace_log('Computed Org Level Summary Data.');
1295 end if;
1296
1297 /* Insert into Metrics Table the org level summary data. Use -1 for dept,res and employee */
1298 forall org_index in v_shift_num.first..v_shift_num.last
1299 insert into wip_labor_performance_rates
1300 (
1301 ORGANIZATION_ID,
1302 DEPARTMENT_ID,
1303 RESOURCE_ID,
1304 EMPLOYEE_ID,
1305 DATE_SEQUENCE,
1306 SHIFT_NUM,
1307 METRIC1_ATTRIBUTE1,
1308 METRIC1_ATTRIBUTE2,
1309 METRIC2_ATTRIBUTE1,
1310 METRIC2_ATTRIBUTE2,
1311 METRIC3_ATTRIBUTE1,
1312 METRIC3_ATTRIBUTE2,
1313 CREATED_BY,
1314 CREATION_DATE,
1315 LAST_UPDATED_BY,
1316 LAST_UPDATE_DATE,
1317 LAST_UPDATE_LOGIN,
1318 PROGRAM_APPLICATION_ID,
1319 PROGRAM_UPDATE_DATE,
1320 PROGRAM_ID,
1321 REQUEST_ID,
1322 OBJECT_VERSION_NUMBER
1323 )
1324 values
1325 (
1326 p_organization_id,
1327 -1,
1328 -1,
1329 -1,
1330 v_date_sequence(org_index),
1331 v_shift_num(org_index),
1332 v_m1_att1(org_index),
1333 v_m1_att2(org_index),
1334 v_m2_att1(org_index),
1335 v_m2_att2(org_index),
1336 v_m3_att1(org_index),
1337 v_m3_att2(org_index),
1338 g_user_id,
1339 sysdate,
1340 g_user_id,
1341 sysdate,
1342 g_user_login_id,
1343 g_program_appl_id,
1344 sysdate,
1345 g_program_id,
1346 g_request_id,
1347 1);
1348
1349 l_stmt_num :=400;
1350 if (g_logLevel <= wip_constants.trace_logging) then
1351 wip_ws_util.trace_log('Insertion of Org Level Summary Data is successful.');
1352 end if;
1353
1354 end if; /* l_metric1_required or l_metric2_required or l_metric3_required */
1355
1356 l_stmt_num :=410;
1357 wip_ws_util.trace_log('Labor Metrics Calculation completed.');
1358
1359 commit;
1360
1361 if l_error_count=0 then
1362 l_conc_status := true;
1363 retcode:=0;
1364 else
1365 retcode := 1;
1366 errbuf := 'Calculation program encountered invalid records. Invalid records will be ignored during calculation.';
1367 fnd_file.put_line(fnd_file.log,errbuf);
1368 l_conc_status := FND_CONCURRENT.SET_COMPLETION_STATUS('WARNING',errbuf);
1369 end if;
1370
1371 exception
1372 when e_null_org_id then
1373 retcode := 2;
1374 errbuf := 'Organization parameter cannot be null';
1375 fnd_file.put_line(fnd_file.log,errbuf);
1376 l_conc_status := FND_CONCURRENT.SET_COMPLETION_STATUS('ERROR',errbuf);
1377 when others then
1378 fnd_message.set_name('WIP','WIP_LAB_UNEXPECTED_ERROR');
1379 x_error_msg := fnd_message.get;
1380 wip_ws_util.trace_log('Error in '||l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
1381 x_error_msg := sqlerrm(sqlcode);
1382 wip_ws_util.trace_log('Error in '||l_proc_name||'( stmt_num: '||l_stmt_num||') '||x_error_msg);
1383 rollback;
1384 retcode := 2;
1385 errbuf := 'Errors encountered in calculation program, please check the log file.';
1386 l_conc_status := FND_CONCURRENT.SET_COMPLETION_STATUS('ERROR',errbuf);
1387
1388 end calculate_metrics;
1389
1390 /* To obtain Client Date for a given Server Date (Used in Charts only) */
1391 function get_client_date(p_date in Date)
1392 return date
1393 is
1394 l_converted_date date;
1395 l_timezone_enabled boolean := ( fnd_profile.value('ENABLE_TIMEZONE_CONVERSIONS') = 'Y' AND
1396 fnd_profile.value('CLIENT_TIMEZONE_ID') IS NOT NULL AND
1397 fnd_profile.value('SERVER_TIMEZONE_ID') IS NOT NULL AND
1398 fnd_profile.value('CLIENT_TIMEZONE_ID') <>
1399 fnd_profile.value('SERVER_TIMEZONE_ID'));
1400 l_client_id number := fnd_profile.value('CLIENT_TIMEZONE_ID');
1401 l_server_id number := fnd_profile.value('SERVER_TIMEZONE_ID');
1402 begin
1403
1404 if l_timezone_enabled and p_date is not null then
1405 l_converted_date := hz_timezone_pub.convert_datetime(l_server_id,
1406 l_client_id,
1407 p_date);
1408 else
1409 l_converted_date := p_date;
1410 end if;
1411
1412 return l_converted_date;
1413 end get_client_date;
1414
1415 END WIP_WS_LABOR_METRIC_PUB;