DBA Data[Home] [Help]

PACKAGE BODY: APPS.PER_FR_TERMINATION

Source


1 package body per_fr_termination as
2 /* $Header: pefrterm.pkb 120.4 2007/04/30 11:08:36 abhaduri noship $ */
3 --
4 g_package varchar2(30) := 'per_fr_termination';
5 g_person_id number;
6 g_validation number := 0;
7 --
8 /* --------------------------------------------------------------------
9 Local procedure to retrieve the Person ID from the period of service ID
10    -------------------------------------------------------------------- */
11 procedure initiate(p_period_of_service_id number) is
12 --
13 cursor c_get_pds is
14 select person_id
15 from per_periods_of_service
16 where period_of_service_id = p_period_of_service_id;
17 --
18 l_proc varchar2(72) := g_package || '.intiate';
19 begin
20 hr_utility.set_location(l_proc,10);
21   open c_get_pds;
22   fetch c_get_pds into g_person_id;
23   close c_get_pds;
24 end initiate;
25   --
26 /* --------------------------------------------------------------------
27 Local function to determine whether the Leaving Reason has a corresponding
28 value in FR_ENDING_REASON and CONTRACT_END_REASON
29    -------------------------------------------------------------------- */
30 function validate_leaving_reason
31 (p_lookup_type varchar2
32 ,p_lookup_code varchar2) return boolean is
33 --
34 l_dummy varchar2(1);
35 --
36 cursor c_get_lkp is
37 select null
38 from hr_lookups
39 where lookup_type = p_lookup_type
40 and lookup_code = p_lookup_code;
41 --
42 l_proc varchar2(72) := g_package || '.validate_leaving_reason';
43 begin
44 hr_utility.set_location(l_proc,10);
45   open c_get_lkp;
46   fetch c_get_lkp into l_dummy;
47   if c_get_lkp%found then
48      close c_get_lkp;
49      hr_utility.set_location(l_proc,20);
50      return TRUE;
51   else
52      close c_get_lkp;
53      hr_utility.set_location(l_proc,30);
54      return FALSE;
55   end if;
56 end validate_leaving_reason;
57 --
58 /* --------------------------------------------------------------------
59 Local procedure to perform validation of French specific columns.
60    -------------------------------------------------------------------- */
61 procedure validate
62 (p_actual_termination_date date
63 ,p_actual_termination_date_o date
64 ,p_notice_period_start_date date
65 ,p_notice_period_start_date_o date
66 ,p_notice_period_end_date date
67 ,p_notice_period_end_date_o date
68 ,p_last_day_worked varchar2
69 ,p_last_day_worked_o varchar2
70 ,p_final_process_date date -- for  bug#5191942
71 ) is
72 --
73 l_exists varchar2(1);
74 --
75 cursor c_future_contracts is
76 select null
77 from per_contracts_f
78 where person_id = g_person_id
79 and effective_start_date > p_actual_termination_date + 1
80 and substrb(status,1,2) = 'A-';
81 --
82 l_nps_changed boolean :=
83    (p_notice_period_start_date is not null
84    and (p_notice_period_start_date_o is null
85      or (p_notice_period_start_date <> p_notice_period_start_date_o
86      and p_notice_period_start_date_o is not null
87         )));
88 l_npe_changed boolean :=
89    (p_notice_period_end_date is not null
90    and (p_notice_period_end_date_o is null
91      or (p_notice_period_end_date <> p_notice_period_end_date_o
92      and p_notice_period_end_date_o is not null
93         )));
94 l_lwd_changed boolean :=
95    (p_last_day_worked is not null
96    and (p_last_day_worked_o is null
97      or (p_last_day_worked <> p_last_day_worked_o
98      and p_last_day_worked_o is not null
99         )));
100 --
101 l_proc varchar2(72) := g_package || '.validate';
102 begin
103 hr_utility.set_location(l_proc,10);
104 --
105 -- Added for bug#5191942
106 -- if final process date is on or before actual termination date
107 -- then raise an error
108 hr_utility.set_location(l_proc, 10);
109 /*if p_final_process_date is not null
110    and p_actual_termination_date is not null then
111    if p_final_process_date < p_actual_termination_date
112      or p_final_process_date = p_actual_termination_date then
113      --
114      hr_utility.set_message(800, 'PER_75099_FINAL_CLOSE_ATD');
115      hr_utility.raise_error;
116      --
117    end if;
118 end if;*/
119 --
120 -- If either the NPS or NPE have changed and if either is NOT NULL then
121 -- validate that NPS is not after NPE
122 --
123 hr_utility.set_location(l_proc,20);
124    if l_nps_changed or l_npe_changed then
125        if p_notice_period_start_date > p_notice_period_end_date then
126             hr_utility.set_message(800,'PER_75013_NOTICE_PERIOD_DATES');
127             hr_utility.raise_error;
128        end if;
129     end if;
130 --
131 -- If NPS has changed or LWD has changed then ensure that
132 -- Notice period start is not later than LWD
133 --
134 hr_utility.set_location(l_proc,30);
135    if l_nps_changed or l_lwd_changed then
136       if p_notice_period_start_date > p_last_day_worked then
137             hr_utility.set_message(800,'PER_75014_NPS_LWD_DATES');
138             hr_utility.raise_error;
139       end if;
140    end if;
141 --
142 -- If NPE has changed or LWD has changed then ensure that
143 -- Notice period end is not earlier than LWD
144 --
145 hr_utility.set_location(l_proc,40);
146    if l_npe_changed or l_lwd_changed then
147       if p_notice_period_end_date < p_last_day_worked then
148             hr_utility.set_message(800,'PER_75015_NPE_LWD_DATES');
149             hr_utility.raise_error;
150       end if;
151    end if;
152 --
153 -- If NPE is not null then NPS must also be not null
154 --
155 hr_utility.set_location(l_proc,50);
156    if p_notice_period_start_date is null
157    and p_notice_period_end_date is not null then
158             hr_utility.set_message(800,'PER_75016_NPS_NPE_DATES');
159             hr_utility.raise_error;
160    end if;
161 --
162 -- If ATD is not null then it must be on or after NPS and
163 -- on or before NPE
164 --
165 hr_utility.set_location(l_proc,60);
166    if p_actual_termination_date is not null
167    and p_notice_period_start_date is not null
168    and p_notice_period_end_date is not null then
169       if p_notice_period_start_date > p_actual_termination_date
170       or p_notice_period_end_date < p_actual_termination_date then
171             hr_utility.set_message(800,'PER_75017_NPS_ATD_DATES');
172             hr_utility.raise_error;
173       end if;
174    end if;
175 --
176 -- If ATD is not null and LWD is not null then LWD must be on or
177 -- before ATD
178 --
179 hr_utility.set_location(l_proc,70);
180   if p_actual_termination_date is not null
181   and p_last_day_worked is not null then
182       if p_last_day_worked > p_actual_termination_date then
183             hr_utility.set_message(800,'PER_75018_LWD_ATD_DATES');
184             hr_utility.raise_error;
185       end if;
186   end if;
187 --
188 -- If ATD is not null then LWD must be entered
189 --
190 hr_utility.set_location(l_proc,80);
191   if p_actual_termination_date is not null
192   and p_last_day_worked is null then
193             hr_utility.set_message(800,'PER_75019_LWD_ATD_NULL');
194             hr_utility.raise_error;
195   end if;
196 --
197 hr_utility.set_location(l_proc,90);
198 end validate;
199 --
200 /* -------------------------------------------------------------------------
201 Local procedure to delete and create the element entry
202 FR_LAST_DAY_WORKED on LWD.
203 This is called from Terminate and Revers.
204 In the case of Reverse only the delete is performed.
205    ----------------------------------------------------------------------- */
206 procedure last_day_worked_entry
207 (p_last_day_worked date
208 ,p_actual_termination_date date) is
209 --
210 l_assignment_id number;
211 l_effective_date date;
212 l_element_type_id number;
213 l_element_link_id number;
214 l_element_entry_id number;
215 l_effective_start_date date;
216 l_effective_end_date date;
217 l_element_name pay_element_types_f.element_name%Type;
218 l_input_value_id Number;
219 --
220 cursor c_get_asg is
221 select assignment_id
222 from per_all_assignments_f
223 where person_id = g_person_id
224 and   l_effective_date
225       between effective_start_date and effective_end_date
226 and primary_flag = 'Y';
227 --
228 cursor c_element is
229 select element_type_id, element_name
230 from pay_element_types_f
231 where l_effective_date
232    between effective_start_date and effective_end_date
233 and element_name IN ('FR_LAST_DAY_WORKED', 'FR_TERMINATION_INFORMATION')
234 and legislation_code = 'FR';
235 --
236 
237 cursor c_input_value is
238 select input_value_id
239 from pay_input_values_f
240 where l_effective_date
241    between effective_start_date and effective_end_date
242 and legislation_code = 'FR'
243 and element_type_id = l_element_type_id
244 and name = 'Proration';
245 
246 cursor c_entry is
247 select element_entry_id
248 from pay_element_entries_f ee
249 ,    pay_element_links_f l
250 where ee.assignment_id = l_assignment_id
251 and   l.element_type_id = l_element_type_id
252 and   l.element_link_id = ee.element_link_id
253 and p_actual_termination_date
254    between ee.effective_start_date and ee.effective_end_date
255 and p_actual_termination_date
256    between l.effective_start_date and l.effective_end_date;
257 --
258 l_proc varchar2(72) := g_package || '.last_day_worked_entry';
259 begin
260 hr_utility.set_location(l_proc,10);
261 --
262 -- Get the FR_LAST_DAY_WORKED element type ID as of Actual Termination Date
263 --
264   l_effective_date := p_actual_termination_date;
265   open c_element;
266   LOOP
267           fetch c_element into l_element_type_id, l_element_name;
268           EXIT WHEN c_element%NOTFOUND;
269         --
270         -- Get assignment ID of the primary assignment
271         --
272           if l_element_type_id is not null then
273                  open c_get_asg;
274                  fetch c_get_asg into l_assignment_id;
275                  close c_get_asg;
276         --
277         -- Remove any existing element entry effective as of ATD
278         --
279         hr_utility.set_location(l_proc,20);
280                  open c_entry;
281                  fetch c_entry into l_element_entry_id;
282                  if c_entry%found then
283                         hr_entry_api.delete_element_entry
284                         ('ZAP'
285                         ,p_actual_termination_date
286                         ,l_element_entry_id);
287                         close c_entry;
288                  else
289                         close c_entry;
290                  end if;
291         --
292         -- Now, if called from Terminate process, create new element entry
293         -- effective as of LWD
294         --
295         hr_utility.set_location(l_proc,30);
296                  if p_last_day_worked is not null then
297                         l_effective_date := p_last_day_worked;
298                         open c_get_asg;
299                         fetch c_get_asg into l_assignment_id;
300                         close c_get_asg;
301                         --
302                         l_element_link_id :=
303                                 hr_entry_api.get_link(l_assignment_id
304                                                                          ,l_element_type_id
305                                                                          ,p_last_day_worked);
306                         --
307                         l_effective_start_date := p_last_day_worked;
308                         --
309                         if l_element_link_id is not null then
310                            hr_entry_api.insert_element_entry
311                            (p_effective_start_date  => l_effective_start_date
312                            ,p_effective_end_date    => l_effective_end_date
313                            ,p_element_entry_id      => l_element_entry_id
314                            ,p_assignment_id         => l_assignment_id
315                            ,p_element_link_id       => l_element_link_id
316                            ,p_creator_type          => 'F'
317                            ,p_entry_type            => 'E');
318 
319         --
320         -- Force DT change when ever entry is created on day after last day worked.
321         -- A dummy input value is changed so that proration will occur.
322         --
323                            IF l_element_name = 'FR_LAST_DAY_WORKED' THEN
324 
325                 hr_utility.set_location('l_elemen_type_id'||l_element_type_id, 100);
326                 hr_utility.set_location('l_assignment_id'||l_assignment_id, 100);
327                 hr_utility.set_location('l_element_link_id'||l_element_link_id, 100);
328                                 Open c_input_value;
329                                 Fetch c_input_value into l_input_value_id;
330                                 Close c_input_value;
331                 hr_utility.set_location('l_input_value_id'||l_input_value_id, 100);
332                 hr_utility.set_location('LWD'|| p_last_day_worked, 100);
333                 hr_utility.set_location('ATD'|| p_actual_termination_date, 100);
334                                 IF l_input_value_id IS NOT NULL THEN
335                 hr_utility.set_location('DT Updating EE ', 100);
336                                    IF p_last_day_worked < p_actual_termination_date THEN
337                 hr_utility.set_location('Updating EE with LWD date='|| (p_last_day_worked + 1), 100);
338                                      hr_entry_api.update_element_entry
339                                      (p_dt_update_mode       => 'UPDATE'
340                                      ,p_session_date         => p_last_day_worked + 1
341                                      ,p_element_entry_id     => l_element_entry_id
342                                      ,p_comment_id           => Null
343                                      ,p_input_value_id1      => l_input_value_id
344                                      ,p_entry_value1         => '2'
345                                      );
346                                    END IF;
347                                    -- Bug #2884200
348                 hr_utility.set_location('Updating EE with ATD date='||(p_actual_termination_date + 1), 100);
349                 -- Bug#6003309
350                 hr_utility.set_location('Checking if ATD = FPD', 100);
351                                   IF p_actual_termination_date <> l_effective_end_date THEN
352                                      hr_entry_api.update_element_entry
353                                      (p_dt_update_mode       => 'UPDATE'
354                                      ,p_session_date         => p_actual_termination_date + 1
355                                      ,p_element_entry_id     => l_element_entry_id
356                                      ,p_comment_id           => Null
357                                      ,p_input_value_id1      => l_input_value_id
358                                      ,p_entry_value1         => '3'
359                                      );
360                                   END IF;
361                                 END IF; -- Input value id is not null
362                            END IF;      -- element is 'FR_LAST_DAY_WORKED'
363                         end if;
364                  end if; -- if p_last_day_worked is not null
365            end if; -- if l_element_type_id is not null
366         END LOOP;
367         CLOSE c_element;
368 --
369 hr_utility.set_location(l_proc,40);
370 --
371 end last_day_worked_entry;
372 --
373 /* -------------------------------------------------------------------------
374 local procedure to correct the assignment ending on ATD setting the
375 leaving reason to that on the period of service
376    ----------------------------------------------------------------------- */
377 procedure correct_assignment(p_period_of_service_id number
378                             ,p_actual_termination_date date
379                             ,p_leaving_reason varchar2) is
380 --
381 l_proc varchar2(72) := g_package||'.correct_assignment';
382 --
383 l_object_version_number number;
384 l_concatenated_segments varchar2(2000);
385 l_soft_coding_keyflex_id number;
386 l_comment_id  number;
387 l_effective_start_date date;
388 l_effective_end_date date;
389 l_no_managers_warning boolean;
390 l_other_manager_warning boolean;
391 l_effective_date date;
392 l_update_mode varchar2(30);
393 l_exists varchar2(30);
394 l_contract_id number;
395 l_active_contracts number;
396 l_all_contracts number;
397 l_leaving_reason varchar2(30);
398 --
399 cursor c_get_asg is
400 select a.assignment_id
401 ,      a.primary_flag
402 ,      a.object_version_number
403 ,      a.soft_coding_keyflex_id
404 ,      scl.segment4
405 ,      scl.segment2
406 from per_all_assignments_f a
407 ,    hr_soft_coding_keyflex scl
408 ,    per_assignment_status_types ast
409 where a.period_of_service_id = p_period_of_service_id
410 and   p_actual_termination_date = a.effective_end_date
411 and   a.assignment_status_type_id = ast.assignment_status_type_id
412 and   ast.per_system_status <> 'TERM_ASSIGN'
413 and a.soft_coding_keyflex_id = scl.soft_coding_keyflex_id (+);
414 --
415 begin
416 hr_utility.set_location(l_proc,10);
417 --
418 -- Process assignments ending on Actual Termination Date - set End Reason
419 --
420       if p_leaving_reason is null or
421          not validate_leaving_reason('FR_ENDING_REASON',p_leaving_reason) then
422          l_leaving_reason := null;
423       else
424          l_leaving_reason := p_leaving_reason;
425       end if;
426       --
427       for a in c_get_asg loop
428 hr_utility.trace(a.assignment_id);
429 hr_utility.trace(p_period_of_service_id);
430 hr_utility.trace(p_actual_termination_date);
431          l_object_version_number := a.object_version_number;
432          hr_assignment_api.update_emp_asg
433          (P_VALIDATE                     => FALSE
434          ,P_EFFECTIVE_DATE               => p_actual_termination_date
435          ,P_DATETRACK_UPDATE_MODE        => 'CORRECTION'
436          ,P_ASSIGNMENT_ID                => a.assignment_id
437          ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
438          ,P_SEGMENT2                     => a.segment2
439          ,P_SEGMENT4                     => l_leaving_reason
440          ,P_CONCATENATED_SEGMENTS        => l_concatenated_segments
441          ,P_SOFT_CODING_KEYFLEX_ID       => l_soft_coding_keyflex_id
442          ,P_COMMENT_ID                   => l_comment_id
443          ,P_EFFECTIVE_START_DATE         => l_effective_start_date
444          ,P_EFFECTIVE_END_DATE           => l_effective_end_date
445          ,P_NO_MANAGERS_WARNING          => l_no_managers_warning
446          ,P_OTHER_MANAGER_WARNING        => l_other_manager_warning);
447       end loop;
448 --
449 hr_utility.set_location(l_proc,20);
450 end correct_assignment;
451 --
452 
453 --
454 /* -------------------------------------------------------------------------
455 public procedure called from HR_EX_EMPLOYEE_BK1.ACTUAL_TERMINATION_EMP_A hook
456 to process assignments after they have been terminated to set leaving reason on
457 the record ending on ATD
458    ----------------------------------------------------------------------- */
459 procedure actual_termination(p_period_of_service_id number
460                             ,p_actual_termination_date date) is
461 --
462 l_proc varchar2(72) := g_package||'.actual_termination';
463 l_leaving_reason varchar2(30);
464 --
465 cursor c_get_pds is
466 select leaving_reason
467 from per_periods_of_service
468 where period_of_service_id = p_period_of_service_id;
469 --
470 begin
471 
472 --
473 /* Added for GSI Bug 5472781 */
474 IF NOT hr_utility.chk_product_install('Oracle Human Resources', 'FR') THEN
475    hr_utility.set_location('Leaving : '||l_proc , 10);
476    return;
477 END IF;
478 --
479 hr_utility.set_location(l_proc,10);
480 hr_utility.trace('Actually Terminating');
481    open c_get_pds;
482    fetch c_get_pds into l_leaving_reason;
483    close c_get_pds;
484    --
485    correct_assignment(p_period_of_service_id
486                      ,p_actual_termination_date
487                      ,l_leaving_reason);
488 hr_utility.set_location(l_proc,20);
489 end;
490 --
491 /* -------------------------------------------------------------------------
492 External procedure called from Termination API Row Handler After Update
493 hook call for France.
494 N.B. The Termination process as called from the form will call this procedure
495 3 times:
496 1. to update HR attributes
497 2. to maintain ATD
498 3. to maintain FPD
499 
500 In 1. the ATD if changing is not available
501 In 2. the DDF segment changes are not available (both old and new values
502 are the same)
503 In 3. no hook processing is required.
504 
505 Hence it is necessary to detect programatically then termination is happening
506 as opposed to just an update to the HR attributes (i.e DDF, Leaving Reason).
507    ----------------------------------------------------------------------- */
508 procedure termination
509 (p_period_of_service_id number
510 ,p_actual_termination_date date
511 ,p_leaving_reason varchar2
512 ,p_pds_information8 varchar2
513 ,p_pds_information9 varchar2
514 ,p_pds_information10 varchar2
515 ,p_actual_termination_date_o date
516 ,p_leaving_reason_o varchar2
517 ,p_pds_information8_o varchar2
518 ,p_pds_information9_o varchar2
519 ,p_pds_information10_o varchar2
520 ,p_final_process_date date -- for  bug#5191942
521 ) is
522 --
523 l_proc varchar2(72) := g_package||'.termination';
524 --
525 l_notice_period_start_date date :=
526      fnd_date.canonical_to_date(p_pds_information8);
527 l_notice_period_end_date date :=
528      fnd_date.canonical_to_date(p_pds_information9);
529 l_last_day_worked date :=
530      fnd_date.canonical_to_date(p_pds_information10);
531 --
532 l_notice_period_start_date_o date :=
533      fnd_date.canonical_to_date(p_pds_information8_o);
534 l_notice_period_end_date_o date :=
535      fnd_date.canonical_to_date(p_pds_information9_o);
536 l_last_day_worked_o date :=
537      fnd_date.canonical_to_date(p_pds_information10_o);
538 --
539 l_object_version_number number;
540 l_concatenated_segments varchar2(2000);
541 l_soft_coding_keyflex_id number;
542 l_comment_id  number;
543 l_effective_start_date date;
544 l_effective_end_date date;
545 l_no_managers_warning boolean;
546 l_other_manager_warning boolean;
547 l_effective_date date;
548 l_update_mode varchar2(30);
549 l_exists varchar2(30);
550 l_contract_id number;
551 l_active_contracts number;
552 l_all_contracts number;
553 l_leaving_reason varchar2(30);
554 --
555 cursor c_get_asg is
556 select a.assignment_id
557 ,      a.primary_flag
558 ,      a.object_version_number
559 ,      a.soft_coding_keyflex_id
560 ,      scl.segment4
561 ,      scl.segment2
562 from per_all_assignments_f a
563 ,    hr_soft_coding_keyflex scl
564 where a.period_of_service_id = p_period_of_service_id
565 and   p_actual_termination_date = a.effective_end_date
566 and a.soft_coding_keyflex_id = scl.soft_coding_keyflex_id (+);
567 --
568 cursor c_get_ctr is
569 select contract_id
570 ,      person_id
571 ,      object_version_number
572 ,      reference
573 ,      type
574 ,      status
575 ,effective_start_date
576 ,effective_end_date
577 from    per_contracts_f c
578 where  person_id = g_person_id
579 and l_effective_date between effective_start_date and effective_end_date
580 and substrb(status,1,2) = 'A-';
581 --
582 l_atd_changed boolean :=
583     (p_actual_termination_date is not null and
584      p_actual_termination_date_o is null);
585 l_leaving_reason_changed boolean :=
586     (p_leaving_reason is not null and
587      p_leaving_reason_o is not null and
588      p_leaving_reason <> p_leaving_reason_o)
589     or
590     (p_leaving_reason is null and
591      p_leaving_reason_o is not null)
592     or
593     (p_leaving_reason_o is null and
594      p_leaving_reason is not null);
595 l_lwd_changed boolean :=
596    (l_last_day_worked is not null
597    and (l_last_day_worked_o is null
598      or (l_last_day_worked <> l_last_day_worked_o
599      and l_last_day_worked_o is not null
600         )));
601 
602 begin
603 --
604 /* Added for GSI Bug 5472781 */
605 IF NOT hr_utility.chk_product_install('Oracle Human Resources', 'FR') THEN
606    hr_utility.set_location('Leaving : '||l_proc , 10);
607    return;
608 END IF;
609 --
610 hr_utility.set_location(l_proc,10);
611 --
612 -- Initiate Person ID package variable
613 --
614   initiate(p_period_of_service_id);
615 --
616 -- Perform validation of DDF segments
617 --
618   validate(p_actual_termination_date
619           ,p_actual_termination_date_o
620           ,l_notice_period_start_date
621           ,l_notice_period_start_date_o
622           ,l_notice_period_end_date
623           ,l_notice_period_end_date_o
624           ,l_last_day_worked
625           ,l_last_day_worked_o
626           ,p_final_process_date);
627 --
628 -- If Terminating (ATD not null and ATD_Old is null)
629 -- then change contract to change status to Inactive on day after
630 -- ATD
631 --
632 -- This needs to take into account future changes to contract
633 --
634 hr_utility.set_location(l_proc,20);
635    if l_atd_changed then
636       l_effective_date := p_actual_termination_date + 1;
637       for c in c_get_ctr loop
638           l_object_version_number := c.object_version_number;
639           --
640           if c.effective_start_date = l_effective_date then
641              l_update_mode := 'CORRECTION';
642           elsif c.effective_end_date < hr_general.end_of_time then
643                 l_update_mode := 'UPDATE_CHANGE_INSERT';
644           else
645                 l_update_mode := 'UPDATE';
646           end if;
647 --
648 -- Create or update contract on day after ATD
649 --
650 hr_utility.trace(c.contract_id||' '||l_update_mode);
651           hr_contract_api.update_contract
652           (P_VALIDATE                     => FALSE
653           ,P_CONTRACT_ID                  => c.contract_id
654           ,P_EFFECTIVE_START_DATE         => l_effective_start_date
655           ,P_EFFECTIVE_END_DATE           => l_effective_end_date
656           ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
657           ,P_PERSON_ID                    => c.person_id
658           ,P_REFERENCE                    => c.reference
659           ,P_TYPE                         => c.type
660           ,P_STATUS                       => 'T-TERMINATION'
661           ,P_EFFECTIVE_DATE               => p_actual_termination_date+1
662           ,P_DATETRACK_MODE               => l_update_mode);
663   --
664       end loop;
665    end if; -- if l_atd_changed
666 --
667 -- Now handle changes of Leaving Reason
668 --
669 -- If the Leaving Reason changes and ATD is not changing
670 -- the Leaving Reason is not null then default the Leaving Reason onto
671 -- the Assignment (SCL.SEGMENT4)
672 --
673 -- The record that will be updated will be the one that ends on ATD.
674 --
675 -- For this to be possible there must be the same lookup code as the Leaving
676 -- Reason in FR_ENDING_REASON
677 --
678 -- If such values do not exist then a NULL will be copied onto the SCL
679 --
680 -- N.B. This processing occurs only when ATD is set (i.e. a change of leaving
681 -- reason after termination )
682 -- It is therefore safe to assume that there will be  Assignment
683 -- records ending on the ATD. These records will have a datetrack CORRECTION.
684 --
685 hr_utility.set_location(l_proc,30);
686    if p_actual_termination_date is not null and
687    (not l_atd_changed) and l_leaving_reason_changed then
688 --
689       correct_assignment(p_period_of_service_id
690                         ,p_actual_termination_date
691                         ,p_leaving_reason);
692    end if;
693 --
694 -- Process contracts ending on Actual Termination Date - set End Reason
695 --
696 -- If the Leaving Reason changes or ATD changes and
697 -- the Leaving Reason is not null then default the Leaving Reason onto
698 -- the Contract (END_REASON)
699 --
700 -- The record that will be updated will be the one that ends on ATD.
701 --
702 -- For this to be possible there must be the same lookup code as the Leaving
703 -- Reason in CONTRACT_END_REASON
704 --
705 -- If such values do not exist then a NULL will be copied onto the contract
706 --
707 -- N.B. This processing occurs only when ATD is set (i.e. a change of leaving
708 -- reason after termination )
709 -- It is therefore safe to assume that there will be  Contract
710 -- records ending on the ATD. These records will have a datetrack CORRECTION.
711 --
712    if p_actual_termination_date is not null and
713    ((l_atd_changed and p_leaving_reason is not null) or
714     (l_leaving_reason_changed )) then
715 hr_utility.set_location(l_proc,40);
716       if p_leaving_reason is null or
717        not validate_leaving_reason('CONTRACT_END_REASON',p_leaving_reason) then
718          l_leaving_reason := null;
719       else
720          l_leaving_reason := p_leaving_reason;
721       end if;
722       --
723       l_effective_date := p_actual_termination_date;
724       for c in c_get_ctr loop
725          if p_actual_termination_date = c.effective_end_date then
726 hr_utility.trace(c.contract_id);
727             l_object_version_number := c.object_version_number;
728             hr_contract_api.update_contract
729             (P_VALIDATE                     => FALSE
730             ,P_CONTRACT_ID                  => c.contract_id
731             ,P_EFFECTIVE_START_DATE         => l_effective_start_date
732             ,P_EFFECTIVE_END_DATE           => l_effective_end_date
733             ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
734             ,P_PERSON_ID                    => c.person_id
735             ,P_REFERENCE                    => c.reference
736             ,P_TYPE                         => c.type
737             ,P_STATUS                       => c.status
738             ,P_END_REASON                   => l_leaving_reason
739             ,P_EFFECTIVE_DATE               => p_actual_termination_date
740             ,P_DATETRACK_MODE               => 'CORRECTION');
741          end if; -- p_actual_termination_date = c.effective_end_date
742       end loop;
743    end if; -- if p_actual_termination_date is not null
744 --
745 -- Now handle creation of Last Day Worked Element Entry
746 -- The element should be created if ATD is not null and LWD is not null
747 -- and either LWD has been updated or termination is taking place.
748 --
749 hr_utility.set_location(l_proc,50);
750   if p_actual_termination_date is not null
751   and l_last_day_worked is not null
752   and (l_lwd_changed or l_atd_changed) then
753            last_day_worked_entry(l_last_day_worked
754                                 ,p_actual_termination_date);
755   end if; -- if p_actual_termination_date is not null
756 --
757 hr_utility.set_location(l_proc,60);
758 end termination;
759 --
760 procedure reverse
761 (p_period_of_service_id number
762 ,p_actual_termination_date date
763 ,p_leaving_reason varchar2) is
764 --
765 l_proc varchar2(72) := g_package||'.reverse';
766 --
767 l_object_version_number number;
768 l_concatenated_segments varchar2(2000);
769 l_soft_coding_keyflex_id number;
770 l_comment_id  number;
771 l_effective_start_date date;
772 l_effective_end_date date;
773 l_no_managers_warning boolean;
774 l_other_manager_warning boolean;
775 l_status varchar2(30);
776 --
777 l_effective_date date;
778 --
779 cursor c_get_asg is
780 select a.object_version_number
781 ,      a.assignment_id
782 ,      a.soft_coding_keyflex_id
783 ,      scl.segment2
784 ,      decode(effective_end_date
785              ,p_actual_termination_date,p_actual_termination_date
786              ,p_actual_termination_date+1) effective_date
787 from per_all_assignments_f a
788 ,    hr_soft_coding_keyflex scl
789 where period_of_service_id = p_period_of_service_id
790 and   (effective_end_date = p_actual_termination_date
791    or  effective_start_date = p_actual_termination_date+1
792    or   (p_actual_termination_date >= effective_start_date and
793          effective_end_date = to_date('47121231','YYYYMMDD'))
794       )
795 and   a.soft_coding_keyflex_id = scl.soft_coding_keyflex_id;
796 --
797 cursor c_get_ctr1 is
798 select contract_id
799 ,      person_id
800 ,      object_version_number
801 ,      reference
802 ,      type
803 ,      status
804 ,effective_start_date
805 ,effective_end_date
806 from    per_contracts_f c
807 where  person_id =
808 (select person_id
809  from per_periods_of_service
810  where period_of_service_id = p_period_of_service_id)
811 and p_actual_termination_date = effective_end_date;
812 --
813 cursor c_get_ctr2 (p_contract_id number
814                    ,p_effective_date date) is
815 select contract_id
816 ,      person_id
817 ,      object_version_number
818 ,      reference
819 ,      type
820 ,      status
821 ,effective_start_date
822 ,effective_end_date
823 from    per_contracts_f c
824 where contract_id = p_contract_id
825 and   effective_start_date = p_effective_date;
826 --
827 ctr2 c_get_ctr2%rowtype;
828 --
829 begin
830 hr_utility.set_location(l_proc,10);
831    initiate(p_period_of_service_id);
832 --
833 -- On reversing a terination update the assignment record that ended
834 -- at ATD to set the ending reason to NULL
835 --
836    for a in c_get_asg loop
837       l_object_version_number := a.object_version_number;
838       hr_assignment_api.update_emp_asg
839      (P_VALIDATE                     => FALSE
840      ,P_EFFECTIVE_DATE               => a.effective_date
841      ,P_DATETRACK_UPDATE_MODE        => 'CORRECTION'
842      ,P_ASSIGNMENT_ID                => a.assignment_id
843      ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
844      ,P_SEGMENT2                     => a.segment2
845      ,P_SEGMENT4                     => null
846      ,P_CONCATENATED_SEGMENTS        => l_concatenated_segments
847      ,P_SOFT_CODING_KEYFLEX_ID       => l_soft_coding_keyflex_id
848      ,P_COMMENT_ID                   => l_comment_id
849      ,P_EFFECTIVE_START_DATE         => l_effective_start_date
850      ,P_EFFECTIVE_END_DATE           => l_effective_end_date
851      ,P_NO_MANAGERS_WARNING          => l_no_managers_warning
852      ,P_OTHER_MANAGER_WARNING        => l_other_manager_warning);
853    end loop;
854 hr_utility.set_location(l_proc,20);
855 /*
856 --
857 -- On reversing a terination update the contract record that started
858 -- on the day after ATD, set status back to Active
859 --
860    l_effective_date := p_actual_termination_date + 1;
861    for c in c_get_ctr loop
862       l_object_version_number := c.object_version_number;
863       if c.effective_start_date = l_effective_date then
864 --
865 -- Find the status of the previous contract, if found set it on the
866 -- contract record starting on ATD+1
867 --
868          open c_get_status(c.contract_id,c.effective_start_date-1);
869          fetch c_get_status into l_status;
870          if c_get_status%found then
871             close c_get_status;
872             --
873             hr_contract_api.update_contract
874             (P_VALIDATE                     => FALSE
875             ,P_CONTRACT_ID                  => c.contract_id
876             ,P_EFFECTIVE_START_DATE         => l_effective_start_date
877             ,P_EFFECTIVE_END_DATE           => l_effective_end_date
878             ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
879             ,P_PERSON_ID                    => c.person_id
880             ,P_REFERENCE                    => c.reference
881             ,P_TYPE                         => c.type
882             ,P_STATUS                       => l_status
883             ,P_END_REASON                   => null
884             ,P_EFFECTIVE_DATE               => l_effective_date
885             ,P_DATETRACK_MODE               => 'CORRECTION');
886         else
887             close c_get_status;
888         end if;
889       end if; -- if c.effective_start_date = l_effective_date
890    end loop;
891 hr_utility.set_location(l_proc,30);
892 */
893 --
894 --
895 -- On reversing a terination update the contract record that ended
896 -- at ATD to set the ending reason to NULL
897 --
898    for c in c_get_ctr1 loop
899       l_object_version_number := c.object_version_number;
900       hr_contract_api.update_contract
901       (P_VALIDATE                     => FALSE
902       ,P_CONTRACT_ID                  => c.contract_id
903       ,P_EFFECTIVE_START_DATE         => l_effective_start_date
904       ,P_EFFECTIVE_END_DATE           => l_effective_end_date
905       ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
906       ,P_PERSON_ID                    => c.person_id
907       ,P_REFERENCE                    => c.reference
908       ,P_TYPE                         => c.type
909       ,P_STATUS                       => c.status
910       ,P_END_REASON                   => null
911       ,P_EFFECTIVE_DATE               => p_actual_termination_date
912       ,P_DATETRACK_MODE               => 'CORRECTION');
913       --
914       l_status := c.status;
915       --
916 --
917 -- On reversing a terination update the contract record that started
918 -- on the day after ATD, set status back to Active
919 --
920       open c_get_ctr2(c.contract_id,p_actual_termination_date+1);
921       fetch c_get_ctr2 into ctr2;
922       if c_get_ctr2%found then
923          close c_get_ctr2;
924          --
925          l_object_version_number := ctr2.object_version_number;
926          hr_contract_api.update_contract
927          (P_VALIDATE                     => FALSE
928          ,P_CONTRACT_ID                  => ctr2.contract_id
929          ,P_EFFECTIVE_START_DATE         => l_effective_start_date
930          ,P_EFFECTIVE_END_DATE           => l_effective_end_date
931          ,P_OBJECT_VERSION_NUMBER        => l_object_version_number
932          ,P_PERSON_ID                    => ctr2.person_id
933          ,P_REFERENCE                    => ctr2.reference
934          ,P_TYPE                         => ctr2.type
935          ,P_STATUS                       => c.status
936          ,P_END_REASON                   => null
937          ,P_EFFECTIVE_DATE               => p_actual_termination_date+1
938          ,P_DATETRACK_MODE               => 'CORRECTION');
939       else
940          close c_get_ctr2;
941       end if;
942    end loop;
943 hr_utility.set_location(l_proc,40);
944 --
945 -- Delete the FR_LAST_DAY_WORKED element entry that exists on ATD
946 --
947    last_day_worked_entry(null
948                         ,p_actual_termination_date);
949 
950 hr_utility.set_location(l_proc,50);
951 end reverse;
952 --
953 
954 FUNCTION npil_earnings_base_12months (p_assignment_id in Number,
955                                                 p_last_day_worked in Date) Return Number
956 IS
957 l_bal_date_to Date;
958 l_bal_date_from Date;
959 l_rolling_balance Number;
960 BEGIN
961      -- Get the last day of the month prior to last working day
962      l_bal_date_to := LAST_DAY(ADD_MONTHS(p_last_day_worked,-1)) ;
963      -- function calculates over last 12 months
964      -- 1st day of 12 calendar months prior to above date
965      l_bal_date_from := TRUNC(ADD_MONTHS(l_bal_date_to+1,-12), 'MONTH');
966      -- Get rolling balances
967      l_rolling_balance := PAY_FR_GENERAL.FR_ROLLING_BALANCE
968                                             (p_assignment_id,
969                                              'FR_NOTICE_PERIOD_IN_LIEU_EARNINGS_BASE',
970                                              l_bal_date_from,
971                                              l_bal_date_to);
972 
973      RETURN l_rolling_balance;
974 END;
975 
976 end per_fr_termination;