DBA Data[Home] [Help]

PACKAGE BODY: APPS.PY_ROLLBACK_PKG

Source


1 package body py_rollback_pkg AS
2 /* $Header: pyrolbak.pkb 120.27.12010000.3 2008/11/26 06:59:46 priupadh ship $ */
3 /*------------- Payroll and Assignment Action Details ----------------*/
4 type rollback_rec is record
5 (
6    -- Payroll Action Level Details.
7    pact_id                  pay_payroll_actions.payroll_action_id%type,
8    action_name              hr_lookups.meaning%type,
9    action_type              pay_payroll_actions.action_type%type,
10    action_status            pay_payroll_actions.action_status%type,
11    sequenced_flag           boolean,
12    action_date              date,
13    action_start_date        date,
14    current_date             date,  -- holds sysdate.
15    payroll_name             pay_all_payrolls_f.payroll_name%type,
16    bg_name                  hr_organization_units.name%type,
17    bg_id                    hr_organization_units.business_group_id%type,
18    independent_periods_flag pay_legislation_rules.rule_mode%type,
19    date_earned              date,
20    purge_phase              pay_payroll_actions.purge_phase%type,
21    object_type              pay_assignment_actions.object_type%type,
22    retro_definition_id      pay_payroll_actions.retro_definition_id%type,
23    batch_id                 pay_payroll_actions.batch_id%type,
24 --
25    -- Assignment Action Level Details.
26    assact_id                pay_assignment_actions.assignment_action_id%type,
27    assignment_id            per_all_assignments_f.assignment_id%type,
28    full_name                per_all_people_f.full_name%type,
29    assignment_number        per_all_assignments_f.assignment_number%type,
30    payroll_id               pay_all_payrolls_f.payroll_id%type,
31 --
32    -- Other information.
33    legislation_code         varchar2(2),
34    rollback_mode            varchar2(20),   -- 'ROLLBACK', 'RETRY', 'BACKPAY'.
35    rollback_level           varchar2(1),    -- 'A' (assact) or 'P' (pact).
36    leave_row                boolean,        -- i.e. leave_base_table_row.
37    all_or_nothing           boolean,
38    multi_thread             boolean,
39    grp_multi_thread         boolean,
40    dml_mode                 varchar2(10),   -- 'NONE', 'PARTIAL, 'FULL'.
41    max_errors_allowed       number,
42    max_single_undo          number,
43    limit_dml                boolean,
44    retro_purge              pay_action_parameters.parameter_value%type,
45    single_bal_table         pay_action_parameters.parameter_value%type,
46    set_date_earned          pay_action_parameters.parameter_value%type,
47    sub_ledger_acc           pay_action_parameters.parameter_value%type
48 );
49 --
50 --  Data structure to hold information on next range.
51 type range_rec is record
52 (
53    chunk_number    number,
54    starting_person number,
55    ending_person   number
56 );
57 --
58 g_error_count  number;
59 g_debug boolean := hr_utility.debug_enabled;
60 --
61 -- cache variables
62 mtgl_mode pay_action_parameters.parameter_value%type;
63 mtgl_mode_cached boolean := false;
64 --
65 -- The End of Time.
66 c_eot constant date := to_date('31/12/4712', 'DD/MM/YYYY');
67 --
68 --
69 /*
70  *  Get the value of the specified legislation_rule.
71  *  If no value is set on the database, it obtains
72  *  the relevant default value.
73  */
74 function legislation_rule(p_leg_code in varchar2,
75                           p_rule_name in varchar2)
76 return varchar2 is
77 l_rule_value pay_legislation_rules.rule_mode%type;
78 begin
79 --
80    begin
81 --
82      select rule_mode
83        into l_rule_value
84        from pay_legislation_rules
85       where legislation_code = p_leg_code
86         and rule_type = p_rule_name;
87 --
88    exception
89       when no_data_found then
90 --
91         if (p_rule_name = 'RETRO_DELETE') then
92            l_rule_value := 'Y';
93         else
94            l_rule_value := null;
95         end if;
96    end;
97 --
98    return l_rule_value;
99 --
100 end legislation_rule;
101 --
102 /*
103  *  Get the value of the specified action parameter.
104  *  If no value is set on the database, it obtains
105  *  the relevant default value.
106  */
107 function action_parameter(p_param_name in varchar2)
108 return varchar2 is
109    l_name      pay_action_parameters.parameter_name%type;
110    param_value pay_action_parameters.parameter_value%type;
111    c_indent constant varchar2(40) := 'py_rollback_pkg.action_parameter';
112    l_found boolean;
113 begin
114       --  Attempt to find value of the parameter
115       --  in the action parameter table.
116   pay_core_utils.get_action_parameter(p_param_name, param_value, l_found   );
117 
118   if l_found=FALSE then
119       if(replace(p_param_name,' ','_') = 'CHUNK_SIZE') then
120          param_value := 20;
121       elsif(replace(p_param_name,' ','_') = 'MAX_SINGLE_UNDO') then
122          param_value := 50;
123       elsif(replace(p_param_name,' ','_') = 'MAX_ERRORS_ALLOWED') then
124          --  If we can't get the max errors allowed, we
125          --  default to chunk_size - make recursive call
126          --  to get this value.
127          param_value := action_parameter('CHUNK_SIZE');
128       elsif(replace(p_param_name,' ','_') = 'SET_DATE_EARNED') then
129          param_value := 'N';
130       end if;
131   end if;
132 --
133   return(param_value);
134 --
135 end action_parameter;
136 --
137 procedure remove_pact_payment(p_pactid in number)
138 is
139 cursor get_payment(p_pact in number)
140 is
141 select pre_payment_id
142   from pay_pre_payments
143  where payroll_action_id = p_pact;
144 begin
145 --
146    for payrec in get_payment(p_pactid) loop
147 --
148     update pay_contributing_payments
149        set pre_payment_id = null
150      where pre_payment_id = payrec.pre_payment_id;
151     delete from pay_pre_payments
152      where pre_payment_id = payrec.pre_payment_id;
153 --
154    end loop;
155 --
156 end remove_pact_payment;
157 --
158 procedure remove_action_information(
159                          p_action_context_id   in number,
160                          p_action_context_type in varchar2 default 'AAP')
161 is
162    c_indent constant varchar2(100) := 'py_rollback_pkg.remove_action_information';
163 --
164    cursor actionitems (cp_action_context_id   in number,
165                        cp_action_context_type in varchar2) is
166    select action_information_id
167      from pay_action_information
168     where action_context_id = cp_action_context_id
169       and action_context_type = cp_action_context_type;
170 --
171 begin
172      for actionrec in actionitems(p_action_context_id,
173                                   p_action_context_type) loop
174 
175          /* delete Action Information */
176          delete from pay_action_information
177           where action_information_id = actionrec.action_information_id;
178 
179      end loop;
180 end remove_action_information;
181 
182 
183 procedure remove_archive_items(p_info      in rollback_rec,
184                                p_source_id in number,
185                                p_archive_type in varchar2 default 'AAP')
186 is
187    c_indent constant varchar2(40) := 'py_rollback_pkg.remove_archive_items';
188 --
189    cursor architems (p_source number, p_archive_type varchar2) is
190    select archive_item_id
191      from ff_archive_items
192     where context1 = p_source
193       and nvl(archive_type, 'AAP') = p_archive_type;
194 --
195 begin
196 --
197    for arcrec in architems(p_source_id, p_archive_type) loop
198 --
199 --    delete archive item contexts.
200       delete from ff_archive_item_contexts
201       where archive_item_id = arcrec.archive_item_id;
202 --
203 --    delete the archive items.
204       delete from ff_archive_items
205       where archive_item_id = arcrec.archive_item_id;
206    end loop;
207 end;
208 --
209 procedure remove_file_details(p_info      in rollback_rec,
210                               p_source_id in number,
211                               p_source_type in varchar2 default 'PAA')
212 is
213    c_indent constant varchar2(40) := 'py_rollback_pkg.remove_file_details';
214 --
215 begin
216 --
217    delete from pay_file_details
218     where source_id = p_source_id
219       and source_type = p_source_type;
220 --
221 end;
222 --
223 /*
224  *  Procedure to remove all retropay elements and element
225  *  values for the specified assignment action.
226  */
227 procedure remove_retro_ee(p_assact_id in number) is
228    c_indent varchar2(40);
229    cursor ceev is
230    select pee.element_entry_id
231      from pay_element_entries_f pee,
232           pay_assignment_actions paa
233     where paa.assignment_action_id = p_assact_id
234       and pee.assignment_id        = paa.assignment_id
235       and pee.creator_id           = paa.assignment_action_id
236       and pee.creator_type         = 'P';
237 begin
238    if g_debug then
239       c_indent := 'py_rollback_pkg.remove_retro_ee';
240       hr_utility.set_location(c_indent,10);
241    end if;
242    --
243    /* Delete the entry values before the element entry */
244    for ceevrec in ceev loop
245        delete from pay_element_entry_values_f pev
246        where element_entry_id = ceevrec.element_entry_id;
247        --
248        delete from pay_element_entries_f
249        where creator_id   = p_assact_id
250        and   creator_type = 'P'
251        and element_entry_id = ceevrec.element_entry_id;
252    end loop;
253    --
254    if g_debug then
255       hr_utility.set_location(c_indent,20);
256    end if;
257 end remove_retro_ee;
258 --
259 /*
260  *  Procedure to remove all Advance pay elements and element
261  *  values for the specified assignment action.
262  */
263 procedure remove_adv_ee(p_assact_id in number) is
264    c_indent varchar2(40);
265    cursor aeev is
266    select pee.element_entry_id
267      from pay_element_entries_f pee,
268           pay_assignment_actions paa
269     where paa.assignment_action_id = p_assact_id
270       and pee.assignment_id        = paa.assignment_id
271       and pee.creator_id           = paa.assignment_action_id
272       and pee.creator_type         = 'D';
273 begin
274    if g_debug then
275       c_indent := 'py_rollback_pkg.remove_adv_ee';
276       hr_utility.set_location(c_indent,10);
277    end if;
278    --
279    /* Delete the entry values before the element entry */
280    for aeevrec in aeev loop
281        delete from pay_element_entry_values_f pev
282        where element_entry_id = aeevrec.element_entry_id;
283        --
284        delete from pay_element_entries_f
285        where creator_id   = p_assact_id
286        and   creator_type = 'D'
287        and element_entry_id = aeevrec.element_entry_id;
288    end loop;
289    --
290    if g_debug then
291       hr_utility.set_location(c_indent,20);
292    end if;
293 end remove_adv_ee;
294 --
295 -- Procedure to remove advance pay by element entries.
296 --
297 procedure remove_advpayele_ee(p_assact_id in number) is
298    c_indent varchar2(40);
299    cursor aeev is
300    select pee.element_entry_id
301      from pay_element_entries_f pee,
302           pay_assignment_actions paa
303     where paa.assignment_action_id = p_assact_id
304       and pee.assignment_id        = paa.assignment_id
305       and pee.creator_id           = paa.assignment_action_id
306       and pee.creator_type         in ('AD', 'AE','D');
307 begin
308    if g_debug then
309       c_indent := 'py_rollback_pkg.remove_advpayele_ee';
310       hr_utility.set_location(c_indent,10);
311    end if;
312    --
313    /* Delete the entry values before the element entry */
314    for aeevrec in aeev loop
315        delete from pay_element_entry_values_f pev
316        where element_entry_id = aeevrec.element_entry_id;
317        --
318        delete from pay_element_entries_f
319        where creator_id   = p_assact_id
320        and   creator_type in ('AD', 'AE','D')
321        and   element_entry_id = aeevrec.element_entry_id;
322    end loop;
323    --
324    if g_debug then
325       hr_utility.set_location(c_indent,20);
326    end if;
327 end remove_advpayele_ee;
328 --
329 -- Procedure to remove retropay by action entries.
330 procedure remove_retroact_ee(p_assact_id in number) is
331    c_indent varchar2(40);
332    cursor raeev is
333    select pee.element_entry_id
334      from pay_element_entries_f pee,
335           pay_assignment_actions paa
336     where paa.assignment_action_id = p_assact_id
337       and pee.assignment_id        = paa.assignment_id
338       and pee.creator_id           = paa.assignment_action_id
339       and pee.creator_type         = 'R';
340 begin
341    if g_debug then
342       c_indent := 'py_rollback_pkg.remove_retroact_ee';
343       hr_utility.set_location(c_indent,10);
344    end if;
345    --
346    /* Delete the entry values before the element entry */
347    for raeevrec in raeev loop
348        delete from pay_element_entry_values_f pev
349        where element_entry_id = raeevrec.element_entry_id;
350        --
351        delete from pay_element_entries_f
352        where creator_id   = p_assact_id
353        and   creator_type = 'R'
354        and element_entry_id = raeevrec.element_entry_id;
355    end loop;
356    --
357    if g_debug then
358       hr_utility.set_location(c_indent,20);
359    end if;
360 end remove_retroact_ee;
361 --
362 -- Procedure to remove retropay by element_entries.
363 procedure remove_retroele_ee(p_assact_id in number,
364                              p_rollback_mode in varchar2) is
365    c_indent varchar2(40);
366    cursor remove_eev is
367    select pee.element_entry_id
368      from pay_element_entries_f pee,
369           pay_assignment_actions paa
370     where paa.assignment_action_id = p_assact_id
371       and pee.creator_id           = paa.assignment_action_id
372       and pee.creator_type         in ('RR', 'EE', 'NR', 'PR') ;
373 --
374    l_reprocess_date  date;
375 --
376   cursor min_reprocess_date is
377   select min(pre.reprocess_date)
378     from pay_retro_entries pre,
379          pay_retro_assignments pra
380    where pre.retro_assignment_id = pra.retro_assignment_id
381      and pra.retro_assignment_action_id = p_assact_id;
382 --
383 begin
384    if g_debug then
385       c_indent := 'py_rollback_pkg.remove_retroele_ee';
386       hr_utility.set_location(c_indent,10);
387    end if;
388    --
389    /* Delete the entry values before the element entry */
390    for eev_rec in remove_eev loop
391        delete from pay_element_entry_values_f pev
392        where element_entry_id = eev_rec.element_entry_id;
393        --
394        delete from pay_entry_process_details
395        where  element_entry_id = eev_rec.element_entry_id;
396        --
397        delete from pay_element_entries_f
398        where creator_id   = p_assact_id
399        and   creator_type in ('RR', 'EE', 'NR', 'PR')
400        and element_entry_id = eev_rec.element_entry_id;
401    end loop;
402 --
403    hr_utility.set_location(c_indent,20);
404    -- Finally reset the pay_retro_assignment_table if needed
405    if (p_rollback_mode <> 'RETRY') then
406 --
407    pay_retro_pkg.merge_retro_assignments(p_assact_id);
408 --
409    hr_utility.set_location(c_indent,30);
410    -- Remove or reset row on pay_recorded_requests
411    --
412    hr_utility.set_location(c_indent,40);
413    pay_retro_pkg.reset_recorded_request(p_assact_id);
414    hr_utility.set_location(c_indent,50);
415    --
416    -- Remove the asg act id, and in case merge has new earlier entries
417    -- also change the reprocess_date
418    open min_reprocess_date;
419    fetch min_reprocess_date into l_reprocess_date;
420    close min_reprocess_date;
421    --
422    update pay_retro_assignments  ra
423       set ra.retro_assignment_action_id = null,
424           ra.reprocess_date = nvl(l_reprocess_date,ra.reprocess_date)
425     where ra.retro_assignment_action_id = p_assact_id;
426 
427    end if;
428 --
429    if g_debug then
430       hr_utility.set_location(c_indent,20);
431    end if;
432 --
433 end remove_retroele_ee;
434 --
435 /*
436  *  Procedure to delete entries from gl_interface tables.
437  */
438 procedure remove_gl_entries(p_info in rollback_rec) is
439    c_indent varchar2(40);
440    l_source_name gl_interface.user_je_source_name%type;
441 --
442 begin
443    if g_debug then
444       c_indent := 'py_rollback_pkg.remove_gl_entries';
445       hr_utility.set_location(c_indent, 10);
446    end if;
447    --
448    if mtgl_mode_cached = FALSE then
449        if g_debug then
450           hr_utility.set_location(c_indent, 20);
451        end if;
452        begin
453           select upper(parameter_value)
454           into mtgl_mode
455           from pay_action_parameters
456           where parameter_name = 'TRANSGL_THREAD';
457        exception
458            when others then
459               mtgl_mode := 'Y';
460        end;
461    --
462        if g_debug then
463           hr_utility.set_location(c_indent, 30);
464        end if;
465        -- Remove transfer table rows once only
466        -- first of all get source_name
467        select user_je_source_name
468        into l_source_name
469        from gl_je_sources
470        where je_source_name = 'Payroll';
471 --
472        if g_debug then
473           hr_utility.set_location(c_indent, 35);
474        end if;
475        delete from gl_interface gl
476        where  gl.reference21 = to_char(p_info.pact_id)
477        and    gl.user_je_source_name = l_source_name;
478 --
479        mtgl_mode_cached := TRUE;
480     end if;
481 --
482     if mtgl_mode <> 'N' then
483        -- Remove intermediate transfer table rows
484        -- for multi-threaded transfer to GL only
485        if g_debug then
486           hr_utility.set_location(c_indent, 40);
487        end if;
488        delete from pay_gl_interface pgl
489        where  pgl.assignment_action_id = p_info.assact_id;
490     end if;
491 --
492 end remove_gl_entries;
493 --
494 /*
495  *  Procedure to reset the prenote date for magnetic tape
496  *  rollback.
497  */
498 procedure reset_prenote(p_assact_id in number) is
499   cursor get_accnts_to_reset(asgact in number) is
500    select pea.external_account_id
501      from pay_external_accounts          pea,
502           pay_payment_types              ppt,
503           pay_personal_payment_methods_f ppm,
504           pay_org_payment_methods_f      opm,
505           pay_pre_payments               ppp,
506           pay_payroll_actions            ppa,
507           pay_assignment_actions         paa
508     where paa.assignment_action_id       = asgact
509     and   paa.payroll_action_id          = ppa.payroll_action_id
510     and   paa.pre_payment_id             = ppp.pre_payment_id
511     and   ppp.org_payment_method_id      = opm.org_payment_method_id
512     and   ppp.personal_payment_method_id = ppm.personal_payment_method_id
513     and   opm.payment_type_id            = ppt.payment_type_id
514     and   ppt.pre_validation_required    = 'Y'
515     and   ppt.validation_value           = ppp.value
516     and   ppm.external_account_id        = pea.external_account_id
517     and   ppa.effective_date between ppm.effective_start_date
518                                  and ppm.effective_end_date
519     and   ppa.effective_date between opm.effective_start_date
520                                  and opm.effective_end_date;
521 begin
522    for eacrec in get_accnts_to_reset(p_assact_id) loop
523       update pay_external_accounts
524          set prenote_date = null
525        where external_account_id = eacrec.external_account_id
526        and   prenote_date is not null;
527    end loop;
528 end reset_prenote;
529 --
530 /*
531  *  Procedure to remove all run results and run result
532  *  values for the specified assignment action.
533  */
534 procedure remove_run_results(p_info in rollback_rec) is
535    c_indent varchar2(40);
536    purge_rr boolean;
537    cursor crrv is
538    select prr.run_result_id
539    from   pay_run_results       prr
540    where  prr.assignment_action_id = p_info.assact_id;
541 begin
542    -- Delete any run results and values created by
543    -- this action. There is no cascade trigger on
544    -- run results, so we are forced to do both.
545    -- We use a cursor loop here to avoid a full table
546    -- scan that occurs when you attempt to use a single
547    -- delete statement.
548    -- Tight loop, so the set_location call set outside it.
549    if g_debug then
550       c_indent := 'py_rollback_pkg.remove_run_results';
551       hr_utility.set_location(c_indent,10);
552    end if;
553 --
554    purge_rr := TRUE;
555    if (p_info.rollback_mode = 'BACKPAY'
556      and p_info.retro_purge = 'N') then
557 --
558      purge_rr := FALSE;
559 --
560    end if;
561 --
562    if (purge_rr = TRUE) then
563      for crrvrec in crrv loop
564         delete from pay_run_result_values rrv
565         where  rrv.run_result_id = crrvrec.run_result_id;
566      end loop;
567 --
568      if g_debug then
569         hr_utility.set_location(c_indent,30);
570      end if;
571      delete from pay_run_results RR
572      where  RR.assignment_action_id = p_info.assact_id;
573 --
574    else
575 --
576      if g_debug then
577         hr_utility.set_location(c_indent,40);
578      end if;
579      -- It must be a backpay.
580      update pay_run_results RR
581         set RR.status = 'B'
582       where RR.assignment_action_id = p_info.assact_id;
583    end if;
584 end remove_run_results;
585 --
586 /*
587  *  Procedure to remove all action contexts.
588  */
589 procedure remove_action_contexts(p_assact_id in number) is
590    c_indent varchar2(40);
591 begin
592    if g_debug then
593       c_indent := 'py_rollback_pkg.remove_action_contexts';
594       hr_utility.set_location(c_indent,10);
595    end if;
596 --
597    delete from pay_action_contexts
598     where assignment_action_id = p_assact_id;
599 --
600    if g_debug then
601       hr_utility.set_location(c_indent,30);
602    end if;
603 end remove_action_contexts;
604 --
605 /*
606  *  Deletes all latest balances and associated balance
607  *  context values for the specified assignment action id.
608  *  balances are only removed if a prev balance does not exist,
609  *  other wise the prev blance is assigned to the latest balance
610  *
611  *  Deletes all latest balances if the action before rolled back is a
612  *  balance adjustment or a balance initialisation.  This is because as
613  *  these are 'special' types of sequenced actions, their results may
614  *  have fed the balances without the latest balances being owned by them.
615  */
616 
617 procedure remove_balances(p_info in rollback_rec) is
618    c_indent varchar2(40);
619    cursor baplb(l_person_id number) is
620 --
621    select /*+ INDEX(plb PAY_PERSON_LATEST_BALANCES_N3)*/
622           plb.latest_balance_id,
623           plb.prev_balance_value,
624           plb.prev_assignment_action_id,
625           plb.expired_value,
626           plb.expired_assignment_action_id,
627           plb.assignment_action_id
628    from   pay_person_latest_balances plb,
629           pay_defined_balances  pdb,
630           pay_balance_feeds_f   pbf,
631           pay_run_result_values rrv,
632           pay_run_results       prr
633    where prr.assignment_action_id = p_info.assact_id
634    and   rrv.run_result_id        = prr.run_result_id
635    and   rrv.result_value is not null
636    and   pbf.input_value_id       = rrv.input_value_id
637    and   pdb.balance_type_id      = pbf.balance_type_id
638    and   plb.defined_balance_id   = pdb.defined_balance_id
639    and   plb.person_id            = l_person_id
640    and   p_info.action_date between pbf.effective_start_date
641                                 and pbf.effective_end_date;
642 --
643    cursor baalb is
644    select /*+ INDEX(alb PAY_ASSIGNMENT_LATEST_BALA_N3)*/
645           alb.latest_balance_id,
646           alb.prev_balance_value,
647           alb.prev_assignment_action_id,
648           alb.expired_value,
649           alb.expired_assignment_action_id,
650           alb.assignment_action_id
651    from   pay_assignment_latest_balances alb,
652           pay_defined_balances  pdb,
653           pay_balance_feeds_f   pbf,
654           pay_run_result_values rrv,
655           pay_run_results       prr
656    where prr.assignment_action_id = p_info.assact_id
657    and   rrv.run_result_id        = prr.run_result_id
658    and   rrv.result_value is not null
659    and   pbf.input_value_id       = rrv.input_value_id
660    and   pdb.balance_type_id      = pbf.balance_type_id
661    and   alb.defined_balance_id   = pdb.defined_balance_id
662    and   alb.assignment_id        = p_info.assignment_id
663    and   p_info.action_date between pbf.effective_start_date
664                                 and pbf.effective_end_date;
665 --
666    cursor balb (l_person_id number)is
667    select
668           lb.latest_balance_id,
669           lb.prev_balance_value,
670           lb.prev_assignment_action_id,
671           lb.prev_expiry_date,
672           lb.expired_value,
673           lb.expired_assignment_action_id,
674           lb.assignment_action_id
675    from   pay_latest_balances   lb,
676           pay_defined_balances  pdb,
677           pay_balance_feeds_f   pbf,
678           pay_run_result_values rrv,
679           pay_run_results       prr
680    where prr.assignment_action_id = p_info.assact_id
681    and   rrv.run_result_id        = prr.run_result_id
682    and   rrv.result_value is not null
683    and   pbf.input_value_id       = rrv.input_value_id
684    and   pdb.balance_type_id      = pbf.balance_type_id
685    and   lb.defined_balance_id    = pdb.defined_balance_id
686    and   lb.person_id             = l_person_id
687    and    (   lb.assignment_id         = p_info.assignment_id
688            or lb.assignment_id is null)
689    and    (   lb.process_group_id   = (select distinct pog.parent_object_group_id
690                                          from pay_object_groups pog
691                                         where pog.source_id = p_info.assignment_id
692                                           and pog.source_type = 'PAF')
693            or lb.process_group_id is null)
694    and   p_info.action_date between pbf.effective_start_date
695                                 and pbf.effective_end_date;
696 --
697    cursor cplb is
698    select plb.latest_balance_id,
699           plb.prev_balance_value,
700           plb.prev_assignment_action_id,
701           plb.expired_value,
702           plb.expired_assignment_action_id
703    from   pay_person_latest_balances plb
704    where  plb.assignment_action_id = p_info.assact_id;
705 --
706    cursor calb is
707    select alb.latest_balance_id,
708           alb.prev_balance_value,
709           alb.prev_assignment_action_id,
710           alb.expired_value,
711           alb.expired_assignment_action_id
712    from   pay_assignment_latest_balances alb
713    where  alb.assignment_action_id = p_info.assact_id;
714 --
715    cursor clb is
716    select lb.latest_balance_id,
717           lb.prev_balance_value,
718           lb.prev_assignment_action_id,
719           lb.prev_expiry_date,
720           lb.expired_value,
721           lb.expired_assignment_action_id
722    from   pay_latest_balances lb
723    where  lb.assignment_action_id = p_info.assact_id;
724 --
725    l_person_id          per_all_assignments_f.person_id%TYPE;
726 
727 begin
728     -- Remove latest balances and associated context values.
729     -- Delete cascade not used because a) efficiency and
730     -- b) must delete for both rollback and mark for retry.
731     -- Cursor loops used to avoid full table access of
732     -- the balance context table.
733 
734     if g_debug then
735        c_indent := 'py_rollback_pkg.remove_balances';
736        hr_utility.set_location(c_indent,10);
737     end if;
738     if (p_info.action_type in ('B', 'I', 'V')) then
739        -- treat balance adjustment as a special case : we should
740        -- delete all latest balances for an assignment if its having
741        -- a balance adjustment being rolled back (because its very
742        -- difficult to work out which if any of the latest, previous
743        -- or expired balances were fed by the balance adjustment)
744        -- And Reversals now too!
745 
746        select person_id
747        into l_person_id
748        from per_all_assignments_f
749        where assignment_id = p_info.assignment_id
750        and   p_info.action_date between
751              effective_start_date and effective_end_date;
752 
753        if g_debug then
754           hr_utility.set_location(c_indent,15);
755        end if;
756 
757        if (p_info.single_bal_table <> 'Y') then
758 
759          for bplbrec in baplb(l_person_id) loop
760             if bplbrec.assignment_action_id = p_info.assact_id then
761                if bplbrec.prev_balance_value=-9999
762                or bplbrec.prev_balance_value is NULL
763                or bplbrec.prev_assignment_action_id is NULL
764                then
765                   delete from pay_balance_context_values bcv
766                   where  bcv.latest_balance_id = bplbrec.latest_balance_id;
767 
768                   delete from pay_person_latest_balances plb
769                   where plb.latest_balance_id = bplbrec.latest_balance_id;
770                else
771                   if bplbrec.prev_assignment_action_id = bplbrec.expired_assignment_action_id
772                   then
773                      update pay_person_latest_balances
774                      set expired_assignment_action_id = -9999,
775                          expired_value = -9999
776                      where pay_person_latest_balances.latest_balance_id =
777                                           bplbrec.latest_balance_id;
778                   end if;
779                   update pay_person_latest_balances
780                   set assignment_action_id = bplbrec.prev_assignment_action_id,
781                       value = bplbrec.prev_balance_value,
782                       prev_assignment_action_id = -9999,
783                       prev_balance_value = -9999
784                   where pay_person_latest_balances.latest_balance_id =
785                                           bplbrec.latest_balance_id;
786                end if;
787             else
788                delete from pay_balance_context_values bcv
789                where  bcv.latest_balance_id = bplbrec.latest_balance_id;
790 
791                delete from pay_person_latest_balances plb
792                where plb.latest_balance_id = bplbrec.latest_balance_id;
793             end if;
794          end loop;
795 
796          for balbrec in baalb loop
797             if balbrec.assignment_action_id = p_info.assact_id then
798                if balbrec.prev_balance_value=-9999
799                or balbrec.prev_balance_value is NULL
800                or balbrec.prev_assignment_action_id is NULL
801                then
802                   delete from pay_balance_context_values bcv
803                   where  bcv.latest_balance_id = balbrec.latest_balance_id;
804 
805                   delete from pay_assignment_latest_balances alb
806                   where alb.latest_balance_id = balbrec.latest_balance_id;
807                else
808                   if balbrec.prev_assignment_action_id = balbrec.expired_assignment_action_id
809                   then
810                      update pay_assignment_latest_balances
811                      set expired_assignment_action_id = -9999,
812                          expired_value = -9999
813                      where pay_assignment_latest_balances.latest_balance_id =
814                                           balbrec.latest_balance_id;
815                   end if;
816                   update pay_assignment_latest_balances
817                   set assignment_action_id = balbrec.prev_assignment_action_id,
818                       value = balbrec.prev_balance_value,
819                       prev_assignment_action_id = -9999,
820                       prev_balance_value = -9999
821                   where pay_assignment_latest_balances.latest_balance_id =
822                                           balbrec.latest_balance_id;
823                end if;
824             else
825                delete from pay_balance_context_values bcv
826                where  bcv.latest_balance_id = balbrec.latest_balance_id;
827 
828                delete from pay_assignment_latest_balances alb
829                where alb.latest_balance_id = balbrec.latest_balance_id;
830             end if;
831          end loop;
832 
833        else /* single_bal_table */
834 
835          for blbrec in balb(l_person_id) loop
836             if blbrec.assignment_action_id = p_info.assact_id then
837                if blbrec.prev_balance_value=-9999
838                or blbrec.prev_balance_value is NULL
839                or blbrec.prev_assignment_action_id is NULL
840                then
841                   delete from pay_latest_balances lb
842                   where lb.latest_balance_id = blbrec.latest_balance_id;
843                else
844                   if blbrec.prev_assignment_action_id = blbrec.expired_assignment_action_id
845                   then
846                      update pay_latest_balances
847                      set expired_assignment_action_id = -9999,
848                          expired_value = -9999,
849                          expired_date = null
850                      where pay_latest_balances.latest_balance_id =
851                                           blbrec.latest_balance_id;
852                   end if;
853                   update pay_latest_balances
854                   set assignment_action_id = blbrec.prev_assignment_action_id,
855                       value = blbrec.prev_balance_value,
856                       expiry_date = blbrec.prev_expiry_date,
857                       prev_assignment_action_id = -9999,
858                       prev_balance_value = -9999,
859                       prev_expiry_date = null
860                   where pay_latest_balances.latest_balance_id =
861                                           blbrec.latest_balance_id;
862                end if;
863             else
864                delete from pay_latest_balances alb
865                where alb.latest_balance_id = blbrec.latest_balance_id;
866             end if;
867          end loop;
868 
869        end if; /* single_bal_table */
870 
871     else
872        if g_debug then
873           hr_utility.set_location(c_indent,90);
874        end if;
875 
876        if (p_info.single_bal_table <> 'Y') then
877 
878          for calbrec in calb loop
879            if (calbrec.prev_balance_value=-9999
880                or calbrec.prev_balance_value is NULL
881                or calbrec.prev_assignment_action_id is NULL)
882            then
883            begin
884              delete from pay_balance_context_values bcv
885              where  bcv.latest_balance_id = calbrec.latest_balance_id;
886              delete from pay_assignment_latest_balances alb
887              where alb.latest_balance_id=calbrec.latest_balance_id;
888            end;
889            else
890            begin
891             if calbrec.prev_assignment_action_id=calbrec.expired_assignment_action_id
892             then
893               update pay_assignment_latest_balances
894               set expired_assignment_action_id=-9999,
895                   expired_value=-9999
896               where  pay_assignment_latest_balances.latest_balance_id =
897                                           calbrec.latest_balance_id;
898             end if;
899             update pay_assignment_latest_balances
900             set assignment_action_id=calbrec.prev_assignment_action_id,
901                 value=calbrec.prev_balance_value,
902                 prev_assignment_action_id=-9999,
903                 prev_balance_value=-9999
904           where  pay_assignment_latest_balances.latest_balance_id =
905                                           calbrec.latest_balance_id;
906            end;
907            end if;
908          end loop;
909 
910 
911          if g_debug then
912             hr_utility.set_location(c_indent,100);
913          end if;
914          for cplbrec in cplb loop
915            if (cplbrec.prev_balance_value=-9999 or
916                cplbrec.prev_balance_value is NULL or
917                cplbrec.prev_assignment_action_id is NULL)
918            then
919            begin
920              delete from pay_balance_context_values bcv
921              where  bcv.latest_balance_id = cplbrec.latest_balance_id;
922              delete from pay_person_latest_balances plb
923              where plb.latest_balance_id=cplbrec.latest_balance_id;
924            end;
925            else
926            begin
927             if cplbrec.prev_assignment_action_id=cplbrec.expired_assignment_action_id
928             then
929               update pay_person_latest_balances
930               set expired_assignment_action_id=-9999,
931                   expired_value=-9999
932               where  pay_person_latest_balances.latest_balance_id =
933                                           cplbrec.latest_balance_id;
934             end if;
935             update pay_person_latest_balances
936             set assignment_action_id=cplbrec.prev_assignment_action_id,
937                 value=cplbrec.prev_balance_value,
938                 prev_assignment_action_id=-9999,
939                  prev_balance_value=-9999
940             where  pay_person_latest_balances.latest_balance_id =
941                                        cplbrec.latest_balance_id;
942            end;
943            end if;
944          end loop;
945 
946        else /* single_bal_table */
947 
948           for clbrec in clb loop
949             if (clbrec.prev_balance_value=-9999
950                 or clbrec.prev_balance_value is NULL
951                 or clbrec.prev_assignment_action_id is NULL)
952             then
953             begin
954               delete from pay_latest_balances lb
955               where lb.latest_balance_id=clbrec.latest_balance_id;
956             end;
957             else
958             begin
959              if clbrec.prev_assignment_action_id=clbrec.expired_assignment_action_id
960              then
961                update pay_latest_balances
962                set expired_assignment_action_id=-9999,
963                    expired_value=-9999,
964                    expired_date = null
965                where  pay_latest_balances.latest_balance_id =
966                                            clbrec.latest_balance_id;
967              end if;
968              update pay_latest_balances
969              set assignment_action_id=clbrec.prev_assignment_action_id,
970                  value=clbrec.prev_balance_value,
971                  expiry_date = clbrec.prev_expiry_date,
972                  prev_assignment_action_id=-9999,
973                  prev_balance_value=-9999,
974                  prev_expiry_date = null
975            where  pay_latest_balances.latest_balance_id =
976                                            clbrec.latest_balance_id;
977             end;
978             end if;
979           end loop;
980 
981        end if; /* single_bal_table */
982     end if;
983 
984 end remove_balances;
985 --
986 /*
987  *  Delete all entries and entry values that were inserted
988  *  by a balance adjustment.
989  *  It is only called for a balance adjustment action.
990  */
991 procedure undo_bal_adjust(p_action_date in date, p_assact_id in number) is
992    -- Batch balance adjustment can have many adjustments
993    -- for an assignment action.
994    cursor c1 is
995    select pee.element_entry_id
996    from   pay_element_entries_f  pee,
997           pay_assignment_actions paa
998    where  paa.assignment_action_id = p_assact_id
999    and    pee.assignment_id        = paa.assignment_id
1000    and    pee.creator_id           = paa.assignment_action_id
1001    and    pee.creator_type         = 'B'  -- (B)alance Adjustment
1002    and    p_action_date between
1003           pee.effective_start_date and pee.effective_end_date;
1004 begin
1005    if g_debug then
1006       hr_utility.set_location('undo_bal_adjust', 60);
1007    end if;
1008    for c1rec in c1 loop
1009       -- Now, we attempt to delete the entry values.
1010       delete from pay_element_entry_values_f pev
1011       where  pev.element_entry_id = c1rec.element_entry_id
1012       and    p_action_date between
1013              pev.effective_start_date and pev.effective_end_date;
1014 --
1015       -- Now we attempt to delete the element entry row.
1016       -- Note, if this procedure is called from the balance
1017       -- adjustment form, the form may be attempting to delete
1018       -- this row. However, this could be called from the
1019       -- actions form, in which case we do need to do the delete.
1020       delete from pay_element_entries_f pee
1021       where  pee.element_entry_id = c1rec.element_entry_id
1022       and    p_action_date between
1023              pee.effective_start_date and pee.effective_end_date;
1024    end loop;
1025    if g_debug then
1026       hr_utility.set_location('undo_bal_adjust', 70);
1027    end if;
1028 --
1029 end undo_bal_adjust;
1030 --
1031 /*
1032  *  Delete all messages (from pay_message_lines) as specified
1033  *  by the source_type. in other words:
1034  *  P : payroll_action_id
1035  *  A : assignment_action_id
1036  */
1037 procedure remove_messages(p_info in rollback_rec, p_source_type in varchar2) is
1038 begin
1039    delete from pay_message_lines pml
1040    where  pml.source_type = p_source_type
1041    and    pml.source_id   =
1042        decode(p_source_type,
1043                 'P', p_info.pact_id,
1044                 'A', p_info.assact_id);
1045 end remove_messages;
1046 --
1047 /*
1048  *  Procedure to get information about the payroll action
1049  *  this information is required for both payroll action
1050  *  and assignment action rollback.
1051  *  Note - it does perform a couple of validation
1052  *  checks at the payroll action level and so might fail.
1053  */
1054 procedure get_pact_info(p_info in out nocopy rollback_rec)
1055 is
1056    c_indent varchar2(40);
1057 begin
1058 --
1059    --  get payroll action level information
1060    if g_debug then
1061       c_indent := 'py_rollback_pkg.get_pact_info';
1062       hr_utility.set_location(c_indent, 10);
1063    end if;
1064    select pac.business_group_id,
1065           pac.effective_date,
1066           pac.start_date,
1067           hrl.meaning,
1068           pac.action_type,
1069           pac.action_status,
1070           trunc(sysdate),
1071           pay.payroll_name,
1072           grp.name,
1073           grp.legislation_code,
1074           pac.date_earned,
1075           pac.purge_phase,
1076           pac.retro_definition_id,
1077           pac.batch_id,
1078           decode(pac.action_type, 'T',
1079                                    nvl(pay_core_utils.get_parameter('SLA_MODE',
1080                                                       pac.legislative_parameters),
1081                                        'N'),
1082                                   'N')
1083    into   p_info.bg_id,
1084           p_info.action_date,
1085           p_info.action_start_date,
1086           p_info.action_name,
1087           p_info.action_type,
1088           p_info.action_status,
1089           p_info.current_date,
1090           p_info.payroll_name,
1091           p_info.bg_name,
1092           p_info.legislation_code,
1093           p_info.date_earned,
1094           p_info.purge_phase,
1095           p_info.retro_definition_id,
1096           p_info.batch_id,
1097           p_info.sub_ledger_acc
1098    from   pay_payroll_actions      pac,
1099           pay_all_payrolls_f       pay,
1100           per_business_groups_perf grp,
1101           hr_lookups               hrl
1102    where  pac.payroll_action_id     = p_info.pact_id
1103    and    hrl.lookup_code           = pac.action_type
1104    and    hrl.lookup_type           = 'ACTION_TYPE'
1105    and    grp.business_group_id     = pac.business_group_id + 0
1106    and    pay.payroll_id (+)        = pac.payroll_id
1107    and    pac.effective_date between
1108           pay.effective_start_date (+) and pay.effective_end_date (+);
1109    if g_debug then
1110       hr_utility.trace('action type is ' || p_info.action_type );
1111    end if;
1112 --
1113 --
1114 --  legislation information.
1115    p_info.independent_periods_flag := upper( hr_leg_rule.get_independent_periods(p_info.bg_id));
1116 
1117 --
1118 -- Treat Retropays as special case as always Time Independent if not Group level
1119 --
1120    if (p_info.action_type in ('G', 'L', 'O') and
1121        p_info.independent_periods_flag = 'N') then
1122       p_info.independent_periods_flag := 'Y';
1123    end if;
1124 --
1125    --  see if this type of action is sequenced or not
1126    declare
1127       dummy number;
1128    begin
1129       p_info.sequenced_flag := TRUE;
1130 --
1131       select null
1132       into   dummy
1133       from   pay_action_classifications CLASS
1134       where  CLASS.action_type         = p_info.action_type
1135       and    CLASS.classification_name = 'SEQUENCED';
1136       if g_debug then
1137          hr_utility.trace('this action type IS sequenced');
1138       end if;
1139    exception
1140       when no_data_found then
1141          p_info.sequenced_flag := FALSE;
1142          if g_debug then
1143             hr_utility.trace('this action type NOT sequenced');
1144          end if;
1145    end;
1146 --
1147    /* get the object Types for this payroll_action */
1148    begin
1149      select /*+ INDEX(paa PAY_ASSIGNMENT_ACTIONS_N50)*/
1150             decode (ppa.action_type,
1151                     'X', paa.object_type,
1152                     decode(paa.object_type,
1153                            'PAF', null,
1154                            paa.object_type))
1155        into p_info.object_type
1156        from pay_assignment_actions paa,
1157             pay_payroll_actions    ppa
1158       where paa.payroll_action_id = p_info.pact_id
1159         and p_info.pact_id = ppa.payroll_action_id
1160         and paa.source_action_id is null
1161         and rownum = 1;
1162    exception
1163       when no_data_found then
1164         p_info.object_type := null;
1165    end;
1166 end get_pact_info;
1167 --
1168 --
1169 /*
1170  *  Insert a message indicating a rollback has occurred. This
1171  *  is used for both assignment and payroll action rollback.
1172  */
1173 procedure ins_rollback_message(p_info in rollback_rec, p_level in varchar2) is
1174    c_indent varchar2(40);
1175    l_line_text     pay_message_lines.line_text%type;
1176    l_line_sequence number;
1177    l_payroll_id    number;
1178    l_source_id     number;
1179    l_source_type   pay_message_lines.source_type%type;
1180    l_action_name   hr_lookups.meaning%type;
1181 begin
1182    g_debug := hr_utility.debug_enabled;
1183    if g_debug then
1184       c_indent := 'py_rollback_pkg.ins_rollback_message';
1185       hr_utility.set_location(c_indent, 10);
1186    end if;
1187    -- Set up a message for either rollback at assignment or
1188    -- payroll action level.
1189    if(p_level = 'A') then
1190       hr_utility.set_message (801, 'HR_ACTION_ASACT_ROLLOK');
1191       hr_utility.set_message_token('ASG_NUMBER',p_info.assignment_number);
1192       hr_utility.set_message_token('FULL_NAME',p_info.full_name);
1193       hr_utility.set_message_token
1194               ('SYSDATE',fnd_date.date_to_canonical(p_info.current_date));
1195 --
1196       -- Message will insert at payroll action level.
1197       l_source_id := p_info.pact_id;
1198       l_source_type := 'P';
1199 --
1200    else
1201       -- Rollback level is 'P'.
1202 --
1203       -- For Magnetic Transfer, the action name must be taken
1204       -- from the Payment Type Name (i.e. BACS, NACHA etc).
1205       if(p_info.action_type = 'M') then
1206          if g_debug then
1207             hr_utility.set_location(c_indent, 90);
1208          end if;
1209          select ppt.payment_type_name
1210          into   l_action_name
1211          from   pay_payroll_actions pac,
1212                 pay_payment_types   ppt
1213          where  pac.payroll_action_id = p_info.pact_id
1214          and    ppt.payment_type_id   = pac.payment_type_id;
1215       else
1216          l_action_name := p_info.action_name;
1217       end if;
1218 --
1219       -- The message we set up depends on whether or not the
1220       -- Payroll Action is restricted or unrestricted.
1221       if(p_info.payroll_name is null) then
1222          hr_utility.set_message(801,'HR_ACTION_PACT_ROLLNOPAY');
1223       else
1224          hr_utility.set_message(801,'HR_ACTION_PACT_ROLLPAY');
1225          hr_utility.set_message_token('PAYROLL_NAME', p_info.payroll_name);
1226       end if;
1227 --
1228       -- Common message tokens.
1229       hr_utility.set_message_token('ACTION_TYPE',l_action_name);
1230       hr_utility.set_message_token('BG_NAME',p_info.bg_name);
1231       hr_utility.set_message_token('SYSDATE',
1232            fnd_date.date_to_canonical(p_info.current_date));
1233 --
1234       -- Message will insert at business group level.
1235       l_source_id := p_info.bg_id;
1236       l_source_type := 'B';
1237    end if;   --- rollback level.
1238 --
1239    -- Get text of message we have set up.
1240    l_line_text := substrb(hr_utility.get_message, 1, 240);
1241 --
1242    -- Write message into message lines table.
1243    if g_debug then
1244       hr_utility.set_location(c_indent, 10);
1245    end if;
1246    insert  into pay_message_lines (
1247            line_sequence,
1248            payroll_id,
1249            message_level,
1250            source_id,
1251            source_type,
1252            line_text)
1253    values (pay_message_lines_s.nextval,
1254            l_payroll_id,
1255            'I',    -- information.
1256            l_source_id,
1257            l_source_type,
1258            l_line_text);
1259 --
1260 end ins_rollback_message;
1261 --
1262 /*---------------------- ins_rollback_message ---------------------------*/
1263 /*
1264  *  overloaded procedure to insert a rollback message on successful
1265  *  completion of the rolling back of a payroll action. This must
1266  *  be callable externally, since the rollback process needs to be
1267  *  able to insert this message, independently of the plsql.
1268  */
1269 procedure ins_rollback_message(p_payroll_action_id in number) is
1270    info     rollback_rec;
1271 begin
1272    info.pact_id := p_payroll_action_id;
1273    get_pact_info(info);              -- payroll action information.
1274    ins_rollback_message(info, 'P');  -- the message itself.
1275 end ins_rollback_message;
1276 --
1277 /*------------------------ undo_stop_update -----------------------------*/
1278 /*
1279  *  This procedure is called when we have detected the need to undo the
1280  *  effect of a stop or update recurring entry formula result rule.
1281  *  Note that, due to the complexity of calculating entry end dates, we
1282  *  call the existing routine, but trap error messages that are
1283  *  inappropriate for our application.
1284  */
1285 procedure undo_stop_update(
1286    p_ee_id in number,
1287    p_mult  in varchar,
1288    p_date  in date,
1289    p_mode  in varchar2) is
1290 --
1291    -- Local variables.
1292    effstart   date;
1293    effend     date;
1294    val_start  date;
1295    val_end    date;
1296    next_end   date;
1297    max_end    date;
1298    orig_ee_id number;
1299    prev_asgact_id number;
1300    asg_id     number;
1301    el_id      number;
1302    c_indent   varchar2(40);
1303 begin
1304    -- Select some information about the entry we are operating on.
1305    if g_debug then
1306       c_indent := 'py_rollback_pkg.undo_stop_update';
1307       hr_utility.set_location(c_indent, 10);
1308    end if;
1309    select pee.effective_start_date,
1310           pee.effective_end_date,
1311           pee.original_entry_id,
1312           pee.assignment_id,
1313           pee.element_link_id
1314    into   effstart, effend, orig_ee_id, asg_id, el_id
1315    from   pay_element_entries_f pee
1316    where  pee.element_entry_id = p_ee_id
1317    and    p_date between
1318           pee.effective_start_date and pee.effective_end_date;
1319 --
1320    -- Do nothing if the entry end date is end of time.
1321    if(effend = c_eot) then
1322       return;
1323    end if;
1324 --
1325    -- For undo update, we have to get next effective start date.
1326    if(p_mode = 'DELETE_NEXT_CHANGE') then
1327       begin
1328          if g_debug then
1329             hr_utility.set_location(c_indent, 20);
1330          end if;
1331          select min(ee.effective_end_date)
1332          into   next_end
1333          from   pay_element_entries_f ee
1334          where  ee.element_entry_id     = p_ee_id
1335          and    ee.effective_start_date > effend;
1336       exception
1337          when no_data_found then null;
1338       end;
1339 --
1340       val_start := effend + 1;
1341 --
1342       if next_end is null then
1343          val_end := c_eot;
1344       else
1345          val_end := next_end;
1346       end if;
1347    elsif(p_mode = 'FUTURE_CHANGE') then
1348       val_start := effend + 1;
1349       val_end   := c_eot;
1350    end if;
1351 --
1352    -- For either mode, we need to obtain the date to which
1353    -- we may legally extend the entry.
1354    declare
1355       message    varchar2(200);
1356       applid     varchar2(200);
1357    begin
1358       max_end := hr_entry.recurring_entry_end_date (
1359                   asg_id, el_id, p_date, 'Y', p_mult, p_ee_id, orig_ee_id);
1360    exception
1361       -- Several error messages can be raised from this procedure.
1362       -- We wish to trap a number of them, as they should be ignored
1363       -- for our purposes.
1364       when hr_utility.hr_error then
1365       hr_utility.get_message_details(message,applid);
1366 --
1367       if(message in ('HR_7699_ELE_ENTRY_REC_EXISTS',
1368                      'HR_7700_ELE_ENTRY_REC_EXISTS',
1369                      'HR_6281_ELE_ENTRY_DT_DEL_LINK',
1370                      'HR_6283_ELE_ENTRY_DT_ELE_DEL',
1371                      'HR_6284_ELE_ENTRY_DT_ASG_DEL')
1372       ) then
1373          -- We cannot extend the entry.
1374          if g_debug then
1375             hr_utility.set_location(c_indent, 25);
1376          end if;
1377          if(p_mode = 'DELETE_NEXT_CHANGE') then
1378               update pay_element_entries_f ee
1379               set    updating_action_id=NULL
1380                       ,updating_action_type =NULL
1381               where  ee.element_entry_id     = p_ee_id
1382               and    ee.effective_start_date = val_start;
1383          elsif(p_mode = 'FUTURE_CHANGE') then
1384               update pay_element_entries_f ee
1385               set    updating_action_id=NULL
1386                       ,updating_action_type =NULL
1387               where  ee.element_entry_id   = p_ee_id
1388               and  ee.effective_start_date = effstart;
1389          end if;
1390          return;
1391       else
1392          -- Should fail if it is anything else.
1393          raise;
1394       end if;
1395    end;
1396 --
1397    -- Process the delete of element entries.
1398    if(p_mode = 'DELETE_NEXT_CHANGE') then
1399       hr_utility.set_location(c_indent, 40);
1400       delete from pay_element_entries_f ee
1401       where  ee.element_entry_id     = p_ee_id
1402       and    ee.effective_start_date = val_start;
1403 --
1404       hr_utility.set_location(c_indent, 45);
1405       delete from pay_element_entry_values_f eev
1406       where  eev.element_entry_id     = p_ee_id
1407       and    eev.effective_start_date = val_start;
1408 --
1409       hr_utility.set_location(c_indent, 50);
1410       update pay_element_entries_f ee
1411       set    ee.effective_end_date   = next_end
1412       where  ee.element_entry_id     = p_ee_id
1413       and    ee.effective_start_date = effstart;
1414 --
1415       hr_utility.set_location(c_indent, 55);
1416       update pay_element_entry_values_f eev
1417       set    eev.effective_end_date   = next_end
1418       where  eev.element_entry_id     = p_ee_id
1419       and    eev.effective_start_date = effstart;
1420 --
1421    elsif(p_mode = 'FUTURE_CHANGE') then
1422 --
1423       hr_utility.set_location(c_indent, 60);
1424       delete from pay_element_entries_f ee
1425       where  ee.element_entry_id     = p_ee_id
1426       and    ee.effective_start_date > effstart;
1427 --
1428       hr_utility.set_location(c_indent, 65);
1429       delete from pay_element_entry_values_f eev
1430       where  eev.element_entry_id     = p_ee_id
1431       and    eev.effective_start_date > effstart;
1432 --
1433       hr_utility.set_location(c_indent, 70);
1434       update pay_element_entries_f ee
1435       set    ee.effective_end_date = max_end,
1436              ee.updating_action_id=NULL,
1437 			 ee.updating_action_type=NULL
1438       where  ee.element_entry_id   = p_ee_id
1439       and  ee.effective_start_date = effstart;
1440 	  /*BUG#6200530*/
1441       /*check for the additional assignment id (in case of an STOP RECURRING after an UPDATE RECURRING)*/
1442       select ee.prev_upd_action_id
1443       into prev_asgact_id
1444       from pay_element_entries_f ee
1445       where ee.element_entry_id   = p_ee_id
1446       and  ee.effective_start_date = effstart;
1447       /*If it is the case then update the updating_action_id with the asg_action_id of the previous UPDATE RECURRING operation*/
1448       if(prev_asgact_id is not null) then
1449             update pay_element_entries_f ee
1450               set    ee.updating_action_id=prev_asgact_id,
1451                      ee.prev_upd_action_id=NULL,
1452                      ee.updating_action_type='U'
1453               where  ee.element_entry_id   = p_ee_id
1454               and  ee.effective_start_date = effstart;
1455       end if;
1456       /*End of BUG#6200530*/
1457 --
1458       hr_utility.set_location(c_indent, 75);
1459       update pay_element_entry_values_f eev
1460       set    eev.effective_end_date   = max_end
1461       where  eev.element_entry_id     = p_ee_id
1462       and    eev.effective_start_date = effstart;
1463    end if;
1464 --
1465 end undo_stop_update;
1466 --
1467 /*
1468  *  This procedure attempts to reverse the effects of stop and/or
1469  *  update formula result rules. Due to the implementation of
1470  *  this functionality, the undo is non-deterministic, i.e. we
1471  *  cannot guarantee to return the database to the exact state
1472  *  it was in before the Payroll Run or QuickPay was processed.
1473  */
1474 procedure proc_entry_dml(p_info in rollback_rec) is
1475    -- This cursor returns candidates for possible undo
1476    -- of stop ree frr. i.e. recurring entries that have
1477    -- an effective_end_date that is same as runs date earned.
1478    cursor stp is
1479    select pet.multiple_entries_allowed_flag,
1480           pee.element_entry_id,pee.updating_action_type
1481    from   pay_element_types_f   pet,
1482           pay_element_links_f   pel,
1483           pay_element_entries_f pee
1484    where  pee.assignment_id      = p_info.assignment_id
1485    and    pee.entry_type         = 'E'
1486    and    pel.element_link_id    = pee.element_link_id
1487    and    p_info.action_date between
1488           pel.effective_start_date and pel.effective_end_date
1489    and    pet.element_type_id    = pel.element_type_id
1490    and    p_info.action_date between
1491           pet.effective_start_date and pet.effective_end_date
1492    and    pet.processing_type    = 'R'
1493    and    pee.updating_action_id   = p_info.assact_id
1494    and    ((pee.effective_end_date = p_info.date_earned
1495             and    pee.effective_start_date <> p_info.action_date
1496             and    pee.updating_action_type is NULL
1497             and    p_info.date_earned between
1498               pee.effective_start_date and pee.effective_end_date)
1499           or(pee.updating_action_type='S'));
1500 
1501 --
1502    -- This cursor returns candidates for undo update ree frr.
1503    -- i.e. entries that have been updated on the date of the
1504    -- Payroll Run, by the updating assignment action.
1505    cursor upd is
1506    select pet.multiple_entries_allowed_flag,
1507           pee.element_entry_id
1508    from   pay_element_types_f   pet,
1509           pay_element_links_f   pel,
1510           pay_element_entries_f pee
1511    where  pee.assignment_id        = p_info.assignment_id
1512    and    pee.entry_type           = 'E'
1513    and    ((pee.effective_start_date = p_info.action_date
1514             and    pee.updating_action_type is NULL)
1515             or pee.updating_action_type='U')
1516    and    pee.updating_action_id   = p_info.assact_id
1517    and    pel.element_link_id      = pee.element_link_id
1518    and    p_info.action_date between
1519           pel.effective_start_date and pel.effective_end_date
1520    and    pet.element_type_id      = pel.element_type_id
1521    and    p_info.action_date between
1522           pet.effective_start_date and pet.effective_end_date
1523    and    pet.processing_type      = 'R';
1524 --
1525    c_indent varchar2(40);
1526    v_max_date date;   -- maximum entry end date
1527 begin
1528    if g_debug then
1529       c_indent := 'py_rollback_pkg.proc_entry_dml';
1530       hr_utility.set_location(c_indent,90);
1531    end if;
1532    -- Begin by processing for stop entry dml.
1533    for stprec in stp loop
1534 
1535     if (stprec.updating_action_type is NULL)
1536     then
1537       --  We may have a stopped entry, but we need to
1538       --  see if this really is the case.
1539       if g_debug then
1540          hr_utility.set_location(c_indent,90);
1541       end if;
1542       select max(pee.effective_end_date)
1543       into   v_max_date
1544       from   pay_element_entries_f pee
1545       where  pee.element_entry_id = stprec.element_entry_id;
1546     else
1547       v_max_date := p_info.date_earned;
1548     end if;
1549 --
1550       if(v_max_date = p_info.date_earned) then
1551          --  Assume entry has been chopped by the run.
1552          --  Call procedure to actually perform undo.
1553          undo_stop_update (stprec.element_entry_id,
1554                            stprec.multiple_entries_allowed_flag,
1555                            p_info.date_earned, 'FUTURE_CHANGE');
1556       end if;
1557    end loop;
1558 --
1559    -- Process for update entry dml.
1560    for updrec in upd loop
1561       --  Since it is not possible to use the Payroll Run to
1562       --  perform a correction on an entry, we know there
1563       --  should be an entry record existing on the date
1564       --  before the run. This is important, since it is
1565       --  required by the procedure that follows.
1566       undo_stop_update (updrec.element_entry_id,
1567                         updrec.multiple_entries_allowed_flag,
1568                         (p_info.action_date - 1), 'DELETE_NEXT_CHANGE');
1569    end loop;
1570 end proc_entry_dml;
1571 --
1572 --
1573 /*
1574  *  Following the main work of rolling back or marking an
1575  *  assignment action for retry, the assignment action
1576  *  row itself (the 'base table' row) may need updating or
1577  *  deleting. (Depends on the wishes of the client). In
1578  *  addition, we may need to remove interlock rows.
1579  */
1580 procedure act_base_table_dml(p_info in rollback_rec) is
1581    c_indent constant varchar2(40) := 'py_rollback_pkg.act_base_table_dml';
1582 begin
1583    --   see if we want to alter the assignment action itself (we wouldn't
1584    --   if we were being called from a form).
1585    --   However, if we are called from the payroll action level,
1586    --   we must process the assignment action row.
1587    if(not p_info.leave_row or p_info.rollback_level = 'P') then
1588       if(p_info.rollback_mode) = 'RETRY' then
1589          if g_debug then
1590             hr_utility.set_location(c_indent, 10);
1591          end if;
1592 --
1593          update pay_assignment_actions
1594          set    action_status = 'M'
1595          where  source_action_id = p_info.assact_id;
1596 --
1597          update pay_assignment_actions
1598          set    action_status = 'M'
1599          where  assignment_action_id = p_info.assact_id;
1600 --
1601       elsif(p_info.rollback_mode) = 'BACKPAY' then
1602          if g_debug then
1603             hr_utility.set_location(c_indent, 20);
1604          end if;
1605 --
1606          update pay_assignment_actions
1607          set    action_status = 'B'
1608          where  source_action_id = p_info.assact_id;
1609 --
1610          update pay_assignment_actions
1611          set    action_status = 'B'
1612          where  assignment_action_id = p_info.assact_id;
1613 --
1614       elsif(p_info.rollback_mode) = 'ROLLBACK' then
1615          -- there may be pay_action_interlock rows.
1616          -- which are locking other assignment actions.
1617          if g_debug then
1618             hr_utility.set_location(c_indent, 30);
1619          end if;
1620          delete from pay_action_interlocks lck
1621          where  lck.locking_action_id = p_info.assact_id;
1622 --
1623          remove_archive_items(p_info, p_info.assact_id, 'AAC');
1624          remove_action_information(p_info.assact_id, 'AAC');
1625 --
1626          delete from pay_assignment_actions
1627           where source_action_id = p_info.assact_id;
1628 --
1629          delete from pay_assignment_actions
1630          where  assignment_action_id = p_info.assact_id;
1631       end if;
1632    else
1633       -- In the case of rolling back (from the form), we
1634       -- still need to delete interlock rows. Of course,
1635       -- in this case we do not delete the action.
1636       if(p_info.rollback_mode = 'ROLLBACK') then
1637 --
1638          remove_archive_items(p_info, p_info.assact_id, 'AAC');
1639          remove_action_information(p_info.assact_id, 'AAC');
1640 --
1641          delete from pay_assignment_actions
1642           where source_action_id = p_info.assact_id;
1643 --
1644          delete from pay_action_interlocks lck
1645          where  lck.locking_action_id = p_info.assact_id;
1646 --
1647       end if;
1648    end if;
1649 end act_base_table_dml;
1650 --
1651 /*----------------------  do_assact_rollback -------------------------------*/
1652 /*
1653   NAME
1654     do_assact_rollback - Perform dml to rollback assignment action.
1655   DESCRIPTION
1656     performs rollback/mark for retry dml for assignment action.
1657   NOTES
1658     This internal routine is central to the rollback process. It does
1659     the actual work of rolling back/marking for retry an assignment
1660     action. The routine makes no checks for validity of the action.
1661 --
1662     There are nested procedures to perform many of the specific
1663     actions required. This is in an attempt to keep the logic
1664     more understandable.
1665 */
1666 procedure do_assact_rollback(p_info in rollback_rec) is
1667    c_indent varchar2(40);
1668    chld_info rollback_rec;
1669    purge_child boolean;
1670 --
1671 --
1672 cursor chdact (p_asgact_id in number) is
1673 select paa_chd.assignment_action_id
1674 from pay_assignment_actions paa_chd
1675 where paa_chd.source_action_id = p_asgact_id
1676 order by paa_chd.action_sequence desc;
1677 --
1678 begin
1679 --
1680    if g_debug then
1681       c_indent := 'py_rollback_pkg.do_assact_rollback';
1682       hr_utility.set_location(c_indent, 10);
1683       hr_utility.set_location('p_info.assact_id'||p_info.assact_id,11);
1684       hr_utility.set_location('p_info.action_date'||p_info.action_date,12);
1685       hr_utility.set_location('p_info.pact_id'||p_info.pact_id,13);
1686    end if;
1687 --
1688    -- Firstly remove any child actions.
1689    chld_info := p_info;
1690    for chdrec in chdact (p_info.assact_id) loop
1691       chld_info.assact_id := chdrec.assignment_action_id;
1692       do_assact_rollback(chld_info);
1693       --
1694       -- Remove child assignment actions if needed.
1695       purge_child := TRUE;
1696 --
1697       if (p_info.rollback_mode = 'BACKPAY'
1698        and p_info.retro_purge = 'N') then
1699         purge_child := FALSE;
1700       end if;
1701 --
1702       -- If its an Enhanced retropay by Ele and using the
1703       -- process group level interlocking then do not
1704       -- remove the child actions.
1705       if (p_info.retro_definition_id is not null
1706           and p_info.independent_periods_flag = 'G') then
1707          purge_child := FALSE;
1708       end if;
1709 --
1710       if (purge_child = TRUE) then
1711         delete from pay_action_interlocks
1712          where locking_action_id = chld_info.assact_id;
1713         if g_debug then
1714            hr_utility.set_location('About to remove assg actions' , 11);
1715         end if;
1716         delete from pay_assignment_actions
1717          where assignment_action_id = chld_info.assact_id;
1718       end if;
1719    end loop;
1720    --
1721    -- Perform actions that are specific to sequenced actions.
1722    -- In other words, remove the rows that are only inserted
1723    -- by these types of actions.
1724 --
1725    if(p_info.sequenced_flag) then
1726    --
1727    -- if the assignment being rolled back contributes to a group run balance
1728    -- need to remove the contributing amount from the group run balance.
1729    --
1730      if (p_info.rollback_mode <> 'BACKPAY') then
1731         pay_balance_pkg.remove_asg_contribs(p_info.pact_id
1732                                            ,p_info.assact_id
1733                                            ,p_info.grp_multi_thread);
1734         --
1735         -- now delete assignment level run balances
1736         --
1737         delete from pay_run_balances
1738         where  assignment_action_id = p_info.assact_id;
1739      else
1740         --
1741         -- now update assignment level run balances
1742         --
1743         update pay_run_balances
1744            set balance_value = 0
1745         where  assignment_action_id = p_info.assact_id;
1746      end if;
1747      --
1748      remove_balances(p_info);     -- latest balances.
1749      remove_run_results(p_info);  -- run results and values.
1750      remove_action_contexts(p_info.assact_id); -- action contexts
1751    end if;
1752    --
1753    -- Delete specific types of rows for certain action types.
1754    if((p_info.action_type = 'B' and p_info.rollback_mode = 'ROLLBACK') OR
1755       (p_info.action_type = 'I' )) then
1756 --
1757       -- OK here's the scoop. If we are in rollback mode
1758       -- then remove the element entries for bal adjust
1759       --
1760       -- Otherwise we must be in Retry mode, hence only remove the
1761       -- Entries if it is a formula based balance adjustment.
1762 --
1763       -- entries/values for bal adjust.
1764       if (p_info.rollback_mode = 'ROLLBACK' or p_info.action_type = 'I') then
1765          undo_bal_adjust(p_info.action_date, p_info.assact_id);
1766       else
1767          declare
1768            l_et_id pay_payroll_actions.element_type_id%type;
1769          begin
1770 --
1771            select ppa.element_type_id
1772              into l_et_id
1773              from pay_assignment_actions paa,
1774                   pay_payroll_actions    ppa
1775             where ppa.payroll_action_id = paa.payroll_action_id
1776               and paa.assignment_action_id = p_info.assact_id;
1777 --
1778            if (l_et_id is not null) then
1779              undo_bal_adjust(p_info.action_date, p_info.assact_id);
1780            end if;
1781 --
1782          end;
1783       end if;
1784    --
1785    elsif(p_info.action_type in ('R', 'Q')) then
1786       proc_entry_dml(p_info);               -- stop/update ree frr.
1787    --
1788    elsif(p_info.action_type in ('P', 'U')) then
1789       -- Remove pre-payment rows.
1790       -- Note, this causes cascade delete of pay_coin_anal_elements.
1791       if g_debug then
1792          hr_utility.set_location('Error abt to occur', 13);
1793       end if;
1794       delete from pay_pre_payments ppp
1795       where  ppp.assignment_action_id = p_info.assact_id;
1796    --
1797    elsif(p_info.action_type in ('C', 'S', 'EC')) then
1798       -- Remove costing rows.
1799       if g_debug then
1800          hr_utility.set_location(c_indent, 20);
1801       end if;
1802       delete from pay_costs pc
1803       where  pc.assignment_action_id = p_info.assact_id;
1804    --
1805    elsif(p_info.action_type = 'CP') then
1806       -- Remove costing rows.
1807       delete from pay_payment_costs ppc
1808       where  ppc.assignment_action_id = p_info.assact_id;
1809    --
1810    elsif(p_info.action_type = 'T') then
1811       -- Remove intermediate transfer table rows.
1812       if (p_info.sub_ledger_acc = 'N') then
1813          remove_gl_entries(p_info);
1814       else
1815          pay_sla_pkg.delete_event(p_info.assact_id);
1816       end if;
1817    --
1818     elsif(p_info.action_type = 'M') then
1819       -- Reset prenote date if this is a dummy payment i.e. payment value
1820       -- of zero.
1821       reset_prenote(p_info.assact_id);
1822       remove_archive_items(p_info, p_info.assact_id, 'AAP');
1823       remove_file_details(p_info, p_info.assact_id, 'PAA');
1824    --
1825     elsif(p_info.action_type = 'PP') then
1826       remove_archive_items(p_info, p_info.assact_id, 'AAP');
1827       remove_file_details(p_info, p_info.assact_id, 'PAA');
1828    --
1829    elsif(p_info.action_type = 'O') then
1830       -- Remove Retropay rows.
1831       remove_retro_ee(p_info.assact_id);
1832    --
1833    elsif(p_info.action_type = 'F') then
1834       -- Remove Advance pay rows.
1835       remove_adv_ee(p_info.assact_id);
1836    --
1837    elsif(p_info.action_type = 'X') then
1838       --Remove Archive Items
1839       remove_archive_items(p_info, p_info.assact_id, 'AAP');
1840       remove_action_information(p_info.assact_id, 'AAP');
1841       remove_file_details(p_info, p_info.assact_id, 'PAA');
1842    --
1843    elsif(p_info.action_type = 'G') then
1844       -- Remove Retropay by Action rows
1845       remove_retroact_ee(p_info.assact_id);
1846    --
1847    elsif(p_info.action_type = 'L') then
1848       -- Remove Retropay by Element rows
1849       remove_retroele_ee(p_info.assact_id, p_info.rollback_mode);
1850       --
1851       -- The following logic in now moved within the above procedure.
1852       --
1853       -- -- Finally reset the pay_retro_assignment_table if needed
1854       -- if (p_info.rollback_mode <> 'RETRY') then
1855       --
1856       --    pay_retro_pkg.merge_retro_assignments(p_info.assact_id);
1857       --
1858       --    -- Remove the asg act id, and in case merge has new earlier entries
1859       --    -- also change the reprocess_date
1860       --    update pay_retro_assignments  ra
1861       --       set ra.retro_assignment_action_id = null,
1862       --           ra.reprocess_date = nvl( (
1863       --                 select min(effective_date)
1864       --                 from pay_retro_entries re
1865       --                 where re.retro_assignment_id = ra.retro_assignment_id )
1866       --             ,ra.reprocess_date)
1867       --    where ra.retro_assignment_action_id = p_info.assact_id;
1868       --
1869       -- end if;
1870    --
1871    elsif(p_info.action_type = 'W') then
1872       -- Remove Advance Pay by Element rows
1873       remove_advpayele_ee(p_info.assact_id);
1874    --
1875    elsif(p_info.action_type = 'Z') then
1876       -- Remove the purge rollup balance rows.
1877       delete from pay_purge_rollup_balances rub
1878       where  rub.assignment_action_id = p_info.assact_id;
1879    elsif(p_info.action_type = 'BEE') then
1880       -- Remove Batch Element Entry rows
1881       pay_mix_rollback_pkg.undo_mix_asg(p_info.assact_id);
1882    elsif(p_info.action_type = 'PRU') then
1883       -- Remove Rolled up payments
1884       delete from pay_contributing_payments
1885       where assignment_action_id = p_info.assact_id;
1886    end if;
1887    --
1888    -- Delete messages for the assignment action.
1889    remove_messages(p_info, 'A');
1890 --
1891    -- Rollback specific code.
1892    if(p_info.rollback_mode = 'ROLLBACK') then
1893       --  Insert message indicating rollback of assignment action.
1894       --  Only insert message if action is not an initial
1895       --  balance adjustment.
1896       if (p_info.action_type <> 'I') then
1897          ins_rollback_message(p_info, 'A');
1898       end if;
1899 --
1900       --  When we are rolling back QuickPay, we need to
1901       --  remove the QuickPay Inclusions.
1902       if(p_info.action_type = 'Q') then
1903          if g_debug then
1904             hr_utility.set_location(c_indent, 30);
1905          end if;
1906          --
1907          -- Enhancement 3368211
1908          --
1909          -- Delete from both PAY_QUICKPAY_INCLUSIONS and PAY_QUICKPAY_EXCLUSIONS.
1910          --
1911          -- There is a chance the assignment action id exists in both tables if
1912          -- the assignment action was created before the QuickPay Exclusions
1913          -- data model was in use.
1914          --
1915          delete from pay_quickpay_exclusions exc
1916          where  exc.assignment_action_id = p_info.assact_id;
1917          --
1918          delete from pay_quickpay_inclusions inc
1919          where  inc.assignment_action_id = p_info.assact_id;
1920          --
1921       end if;
1922    end if;
1923 --
1924    -- Following main processing, may need to do some
1925    -- work on the assignment action row itself.
1926    act_base_table_dml(p_info);
1927 --
1928 --
1929 end do_assact_rollback;
1930 --
1931 /*
1932  *  Internal procedure : called for an individual assignment
1933  *  action to validate that a rollback or mark for retry is
1934  *  legal. Note, it does not guarantee that the rollback
1935  *  will succeed, as this does not perform any dml.
1936  *
1937  *  Assumes that val_pact_rollback has already been called
1938  *  to obtain payroll action level information.
1939  */
1940 procedure val_assact_rollback(p_info in out nocopy rollback_rec)
1941 is
1942    l_action_sequence pay_assignment_actions.action_sequence%type;
1943    l_action_status   pay_assignment_actions.action_status%type;
1944    l_person_id       per_all_people_f.person_id%type;
1945    l_sec_status      pay_assignment_actions.secondary_status%type;
1946    c_indent varchar2(40);
1947 begin
1948    --  Obtain information about this assignment action which we will
1949    --  need later on.
1950    --  Some of this is required for messages.
1951    if g_debug then
1952       c_indent := 'py_rollback_pkg.val_assact_rollback';
1953       hr_utility.trace('assact_id : ' || p_info.assact_id);
1954    end if;
1955 --
1956    -- OK We need to run different statements for different types
1957    -- of processes
1958 --
1959    hr_utility.set_location(c_indent, 10);
1960    if ((p_info.action_type = 'L'
1961        and p_info.object_type = 'POG')
1962        or p_info.object_type is not null
1963        ) then
1964 --
1965       if (p_info.action_type = 'L') then
1966 --
1967         hr_utility.set_location(c_indent, 20);
1968         -- OK this is a retropay that using the Object Group
1969         -- actions
1970         select null,
1971                ACT.action_sequence,
1972                ACT.action_status,
1973                ACT.secondary_status,
1974                null,
1975                PEO.person_id,
1976                substr(PEO.full_name,1,80),
1977                null
1978         into   p_info.assignment_id,
1979                l_action_sequence,
1980                l_action_status,
1981                l_sec_status,
1982                p_info.payroll_id,
1983                l_person_id,
1984                p_info.full_name,
1985                p_info.assignment_number
1986         from
1987                per_all_people_f           PEO,
1988                pay_object_groups      POG_PER,
1989                pay_assignment_actions ACT
1990         where  ACT.assignment_action_id = p_info.assact_id
1991         and    ACT.source_action_id     is null
1992         and    ACT.object_id            = POG_PER.object_group_id
1993         and    POG_PER.source_id        = PEO.person_id
1994         and    p_info.action_date between
1995                        PEO.effective_start_date and PEO.effective_end_date;
1996       else
1997 --
1998         hr_utility.set_location(c_indent, 30);
1999         -- OK its some sort of object action
2000         select null,
2001                ACT.action_sequence,
2002                ACT.action_status,
2003                ACT.secondary_status,
2004                null,
2005                null,
2006                null,
2007                null
2008         into   p_info.assignment_id,
2009                l_action_sequence,
2010                l_action_status,
2011                l_sec_status,
2012                p_info.payroll_id,
2013                l_person_id,
2014                p_info.full_name,
2015                p_info.assignment_number
2016         from   pay_assignment_actions ACT
2017         where  ACT.assignment_action_id = p_info.assact_id;
2018 --
2019       end if;
2020 --
2021    else
2022 --
2023       hr_utility.set_location(c_indent, 40);
2024       -- It's a normal action
2025 --
2026       select ACT.assignment_id,
2027              ACT.action_sequence,
2028              ACT.action_status,
2029              ACT.secondary_status,
2030              ASS.payroll_id,
2031              PEO.person_id,
2032              substr(PEO.full_name,1,80),
2033              ASS.assignment_number
2034       into   p_info.assignment_id,
2035              l_action_sequence,
2036              l_action_status,
2037              l_sec_status,
2038              p_info.payroll_id,
2039              l_person_id,
2040              p_info.full_name,
2041              p_info.assignment_number
2042       from   per_all_assignments_f      ASS,
2043              per_all_people_f           PEO,
2044              pay_assignment_actions ACT
2045       where  ACT.assignment_action_id = p_info.assact_id
2046       and    ASS.assignment_id        = ACT.assignment_id
2047       and    PEO.person_id            = ASS.person_id
2048       and    ((p_info.action_type = 'X'
2049                and ASS.effective_start_date = (select max(ASS2.effective_start_date)
2050                                                from   per_all_assignments_f ASS2
2051                                                where  ASS2.assignment_id = ASS.assignment_id)
2052                and PEO.effective_start_date = (select max(PEO2.effective_start_date)
2053                                                from   per_all_people_f PEO2
2054                                                where  PEO2.person_id = PEO.person_id)
2055               )
2056              or
2057               ((p_info.action_type = 'Z' or p_info.action_type = 'PRU')
2058                and ASS.effective_start_date = (select max(ASS2.effective_start_date)
2059                                                from   per_all_assignments_f ASS2
2060                                                where  ASS2.assignment_id = ASS.assignment_id
2061                                                and    ASS2.effective_start_date <= p_info.action_date)
2062                and PEO.effective_start_date = (select max(PEO2.effective_start_date)
2063                                                from   per_all_people_f PEO2
2064                                                where  PEO2.person_id = PEO.person_id
2065                                                and    PEO2.effective_start_date <= p_info.action_date)
2066               )
2067              or
2068               (p_info.action_type = 'BEE'
2069                and ASS.effective_start_date = (select max(ASS2.effective_start_date)
2070                                             from   per_all_assignments_f ASS2,
2071                                                    pay_batch_lines pbl
2072                                             where  ASS2.assignment_id = ASS.assignment_id
2073                                             and    pbl.batch_id (+) = p_info.batch_id
2074                                             and    pbl.assignment_id (+) = ASS.assignment_id
2075                                             and    pbl.effective_Date (+) between ASS2.effective_start_date
2076                                                    and ASS2.effective_end_date)
2077                and PEO.effective_start_date = (select max(PEO2.effective_start_date)
2078                                             from   per_all_people_f PEO2,
2079                                                    pay_batch_lines pbl
2080                                             where  PEO2.person_id = PEO.person_id
2081                                             and    PEO2.person_id = ASS.person_id
2082                                             and    pbl.batch_id (+) = p_info.batch_id
2083                                             and    pbl.assignment_id (+) = ASS.assignment_id
2084                                             and    pbl.effective_Date (+) between PEO2.effective_start_date
2085                                                    and PEO2.effective_end_date)
2086               )
2087              or
2088              (p_info.action_type not in ('BEE','Z','X', 'PRU')
2089               and    p_info.action_date between
2090                     ASS.effective_start_date and ASS.effective_end_date
2091               and    p_info.action_date between
2092                      PEO.effective_start_date and PEO.effective_end_date));
2093    end if;
2094 --
2095    hr_utility.set_location(c_indent, 50);
2096 --
2097    --  for Purge, we simply wish to confirm that we are not
2098    --  attempting to rollback an assignment action that has
2099    --  a 'C' secondary status.  If everything ok, we simpy
2100    --  exit this procedure.
2101    if(p_info.action_type = 'Z') then
2102       if(l_sec_status = 'C') then
2103          hr_utility.set_message(801, 'PAY_289118_PUR_NACT_ROLLBACK');
2104          hr_utility.raise_error;
2105       end if;
2106 --
2107       if g_debug then
2108          hr_utility.trace('Purge act : exit');
2109       end if;
2110       return;
2111    end if;
2112 --
2113    --  can only retry if already complete
2114    if(p_info.rollback_mode = 'RETRY' and l_action_status not in ('C', 'S'))
2115    then
2116       hr_utility.set_message (801, 'HR_7506_ACTION_RET_NOT_COMP');
2117       hr_utility.set_message_token ('ASG_NO', p_info.assignment_number);
2118       hr_utility.raise_error;
2119    end if;
2120 --
2121 --
2122    --
2123    -- If rolling back or retrying, we need to know if assignments
2124    -- can be considered in isolation (as prescribed by the
2125    -- independent time periods flag for this legislation). Assignments
2126    -- with no Payroll are independent.
2127    --
2128    -- Operation is disallowed if this is a sequenced action AND there
2129    -- exists any sequenced actions in the future. Also disallowed
2130    -- if any child action exists (e.g can't rollback a run if already
2131    -- costed).
2132    -- Note - exception is if are attempting to roll back Reversal or
2133    -- Balance Adjustment actions, where we do not bother to perform
2134    -- the future actions check.
2135    --
2136    declare
2137       dummy number;
2138    begin
2139       -- For either legislation, examine the assignment action
2140       -- to see if it is locked by another action. Peform
2141       -- slightly different checks for RETRY and ROLLBACK
2142       -- modes. See comments below.
2143       if(p_info.rollback_mode = 'RETRY')
2144       then
2145          -- Case for RETRY mode.
2146          -- Check that the assignment action we are attempting to
2147          -- mark for retry is not locked by an assignment action
2148          -- that has an action_status that is not mark for retry.
2149          --
2150          -- Bug 1923535. If the locking action is a Payments Process and has
2151          -- been 'Marked for Retry' then the locked action cannot be
2152          -- 'Marked for Retry'.
2153          --
2154          if g_debug then
2155             hr_utility.set_location(c_indent, 20);
2156          end if;
2157          select null
2158          into   dummy
2159          from   dual
2160          where  not exists (
2161                 select null
2162                 from   pay_action_interlocks int,
2163                        pay_assignment_actions act
2164                 where  int.locked_action_id     =  p_info.assact_id
2165                 and    act.assignment_action_id =  int.locking_action_id
2166                 and    ((exists
2167                          (select null
2168                             from pay_payroll_actions pac
2169                            where pac.payroll_action_id = act.payroll_action_id
2170                              and action_type in ('A','H','M', 'PP', 'PRU')
2171                              and act.action_status = 'M'
2172                          )
2173                         )
2174                           or act.action_status        <> 'M'
2175                        ));
2176       else
2177          -- Case for ROLLBACK mode.
2178          -- Check that the assignment action we are attempting to
2179          -- roll back is not locked by an assignment action.
2180          if g_debug then
2181             hr_utility.set_location(c_indent, 30);
2182          end if;
2183          select null
2184          into   dummy
2185          from   dual
2186          where  not exists (
2187                 select null
2188                 from   pay_action_interlocks int
2189                 where  int.locked_action_id = p_info.assact_id);
2190       end if;
2191 --
2192       --  Now, the following checks are only applicable to sequenced
2193       --  actions, excluding Balance Adjustment and Reversal. These
2194       --  are special cases.
2195       if (p_info.sequenced_flag and
2196           (p_info.action_type <> 'B' and p_info.action_type <> 'I'
2197              and p_info.action_type <> 'V'))
2198       then
2199          -- Check the legislation case.
2200          if(p_info.independent_periods_flag = 'Y')
2201          then
2202             --  Check for other actions on this ASSIGNMENT
2203             --  Perform different checks for RETRY or ROLLBACK.
2204             --  We deal with both 'RETRY' and 'ROLLBACK' (BACKPAY) cases.
2205             --
2206             --  For RETRY:
2207             --    disallow mark for retry assignment action if there are
2208             --    future SEQUENCED assignment actions for the assignment
2209             --    that are not marked for retry. (Nested mark for retry).
2210             --
2211             --  For ROLLBACK (and BACKPAY):
2212             --    disallow rollback assignment action if there are
2213             --    future SEQUENCED assignment actions for the assignment.
2214             if g_debug then
2215                hr_utility.set_location(c_indent, 40);
2216             end if;
2217             --
2218             if (p_info.rollback_mode = 'RETRY')
2219             then
2220                select null into dummy
2221                from   dual
2222                where  not exists
2223                   (select null
2224                    from   pay_assignment_actions      ACT,
2225                           pay_payroll_actions        PACT,
2226                           pay_action_classifications CLASS
2227                    where  ACT.assignment_id         = p_info.assignment_id
2228                    and    ACT.action_sequence       > l_action_sequence
2229                    and    ACT.action_status         in ('C', 'S')
2230                    and    ACT.payroll_action_id     = PACT.payroll_action_id
2231                    and    PACT.action_type          = CLASS.action_type
2232                    and    CLASS.classification_name = 'SEQUENCED');
2233             else
2234                select null into dummy
2235                from   dual
2236                where  not exists
2237                   (select null
2238                    from   pay_assignment_actions      ACT,
2239                           pay_payroll_actions        PACT,
2240                           pay_action_classifications CLASS
2241                    where  ACT.assignment_id         = p_info.assignment_id
2242                    and    ACT.action_sequence       > l_action_sequence
2243                    and    ACT.action_status         in ('C', 'S','M')
2244                    and    ACT.payroll_action_id     = PACT.payroll_action_id
2245                    and    PACT.action_type          = CLASS.action_type
2246                    and    CLASS.classification_name = 'SEQUENCED');
2247             end if;
2248             --
2249           elsif (p_info.independent_periods_flag = 'G') then
2250             --
2251             -- There are 2 Types of processes here. They are
2252             -- either processing at the assignment level but
2253             -- doing Group interlocking or are processing
2254             -- at the group level
2255             --
2256             if (p_info.object_type is not null
2257                 and p_info.object_type = 'POG') then
2258               if (p_info.rollback_mode = 'RETRY')
2259               then
2260                  select null into dummy
2261                  from   dual
2262                  where  not exists
2263                     (select null
2264                      from   pay_action_classifications CLASS,
2265                             pay_payroll_actions        PACT,
2266                             pay_assignment_actions     ACT,
2267                             pay_object_groups          POG_ASG,
2268                             pay_object_groups          POG_PER,
2269                             pay_assignment_actions     PAA_RET
2270                      where  PAA_RET.assignment_action_id = p_info.assact_id
2271                        and  POG_PER.object_group_id = PAA_RET.object_id
2272                        and  POG_PER.source_type = 'PPF'
2273                        and  POG_ASG.parent_object_group_id = POG_PER.object_group_id
2274                        and  POG_ASG.source_type = 'PAF'
2275                        and  POG_ASG.source_id = ACT.assignment_id
2276                        and  ACT.action_sequence       > l_action_sequence
2277                        and  ACT.action_status         in ('C', 'S')
2278                        and  ACT.payroll_action_id     = PACT.payroll_action_id
2279                        and  PACT.action_type          = CLASS.action_type
2280                        and  CLASS.classification_name = 'SEQUENCED');
2281               else
2282                  select null into dummy
2283                  from   dual
2284                  where  not exists
2285                     (select null
2286                      from   pay_action_classifications CLASS,
2287                             pay_payroll_actions        PACT,
2288                             pay_assignment_actions     ACT,
2289                             pay_object_groups          POG_ASG,
2290                             pay_object_groups          POG_PER,
2291                             pay_assignment_actions     PAA_RET
2292                      where  PAA_RET.assignment_action_id = p_info.assact_id
2293                        and  POG_PER.object_group_id = PAA_RET.object_id
2294                        and  POG_PER.source_type = 'PPF'
2295                        and  POG_ASG.parent_object_group_id = POG_PER.object_group_id
2296                        and  POG_ASG.source_type = 'PAF'
2297                        and  POG_ASG.source_id = ACT.assignment_id
2298                        and  ACT.action_sequence       > l_action_sequence
2299                        and  ACT.action_status         in ('C', 'S', 'M')
2300                        and  ACT.payroll_action_id     = PACT.payroll_action_id
2301                        and  PACT.action_type          = CLASS.action_type
2302                        and  CLASS.classification_name = 'SEQUENCED');
2303               end if;
2304             else
2305               if (p_info.rollback_mode = 'RETRY')
2306               then
2307 
2308                  select null into dummy
2309                  from   dual
2310                  where  not exists
2311                     (select null
2312                      from   pay_action_classifications CLASS,
2313                             pay_payroll_actions        PACT,
2314                             pay_assignment_actions     ACT,
2315                             pay_object_groups          POG_ASG,
2316                             pay_object_groups          POG_ASG2
2317                      where   POG_ASG.source_type = 'PAF'
2318                        and  POG_ASG2.source_type = 'PAF'
2319                        and  POG_ASG.source_id = p_info.assignment_id
2320                        and  POG_ASG.parent_object_group_id = POG_ASG2.parent_object_group_id
2321                        and  POG_ASG2.source_id = ACT.assignment_id
2322                        and  ACT.action_sequence       > l_action_sequence
2323                        and  ACT.action_status         in ('C', 'S')
2324                        and  ACT.payroll_action_id     = PACT.payroll_action_id
2325                        and  PACT.action_type          = CLASS.action_type
2326                        and  CLASS.classification_name = 'SEQUENCED');
2327               else
2328                  select null into dummy
2329                  from   dual
2330                  where  not exists
2331                     (select null
2332                      from   pay_action_classifications CLASS,
2333                             pay_payroll_actions        PACT,
2334                             pay_assignment_actions     ACT,
2335                             pay_object_groups          POG_ASG,
2336                             pay_object_groups          POG_ASG2
2337                      where   POG_ASG.source_type = 'PAF'
2338                        and  POG_ASG2.source_type = 'PAF'
2339                        and  POG_ASG.source_id = p_info.assignment_id
2340                        and  POG_ASG.parent_object_group_id = POG_ASG2.parent_object_group_id
2341                        and  POG_ASG2.source_id = ACT.assignment_id
2342                        and  ACT.action_sequence       > l_action_sequence
2343                        and  ACT.action_status         in ('C', 'S', 'M')
2344                        and  ACT.payroll_action_id     = PACT.payroll_action_id
2345                        and  PACT.action_type          = CLASS.action_type
2346                        and  CLASS.classification_name = 'SEQUENCED');
2347               end if;
2348             end if;
2349             --
2350           else
2351             --   check for other actions on this PERSON.
2352             if g_debug then
2353                hr_utility.set_location(c_indent, 50);
2354             end if;
2355 --
2356             --
2357             if (p_info.rollback_mode = 'RETRY')
2358             then
2359                select null into dummy
2360                from   dual
2361                where  not exists
2362                   (select null
2363                    from   pay_action_classifications CLASS,
2364                           pay_payroll_actions        PACT,
2365                           pay_assignment_actions     ACT,
2366                           per_all_assignments_f      ASS,
2367                           per_periods_of_service     POS
2368                    where  POS.person_id             = l_person_id
2369                    and    ASS.period_of_service_id  = POS.period_of_service_id
2370                    and    ACT.assignment_id         = ASS.assignment_id
2371                    and    ACT.action_sequence       > l_action_sequence
2372                    and    ACT.action_status         in ('C', 'S')
2373                    and    ACT.payroll_action_id     = PACT.payroll_action_id
2374                    and    PACT.action_type          = CLASS.action_type
2375                    and    CLASS.classification_name = 'SEQUENCED');
2376             else
2377                select null into dummy
2378                from   dual
2379                where  not exists
2380                   (select null
2381                    from   pay_action_classifications CLASS,
2382                           pay_payroll_actions        PACT,
2383                           pay_assignment_actions     ACT,
2384                           per_all_assignments_f      ASS,
2385                           per_periods_of_service     POS
2386                    where  POS.person_id             = l_person_id
2387                    and    ASS.period_of_service_id  = POS.period_of_service_id
2388                    and    ACT.assignment_id         = ASS.assignment_id
2389                    and    ACT.action_sequence       > l_action_sequence
2390                    and    ACT.action_status         in ('C', 'S', 'M')
2391                    and    ACT.payroll_action_id     = PACT.payroll_action_id
2392                    and    PACT.action_type          = CLASS.action_type
2393                    and    CLASS.classification_name = 'SEQUENCED');
2394             end if;
2395             --
2396          end if;
2397       end if;
2398 --
2399 --  When rolling back a void payment then ensure that the void is against the
2400 --  latest chequewriter run for the payment.
2401 --
2402       if p_info.action_type = 'D' then
2403        select null
2404          into dummy
2405          from dual
2406         where not exists (select null
2407                         from
2408                              pay_assignment_actions paac2,
2409                              pay_assignment_actions paac,
2410                              pay_action_interlocks  pai
2411                        where pai.locking_action_id = p_info.assact_id
2412                          and pai.locked_action_id  = paac.assignment_action_id
2413                          and paac.pre_payment_id   = paac2.pre_payment_id
2414                          and paac2.action_sequence  > paac.action_sequence);
2415       end if;
2416 --
2417    exception
2418       when no_data_found then
2419          -- Catch all interlock failure message.
2420          if p_info.legislation_code = 'GB' then
2421             hr_utility.set_message (801, 'HR_52975_ACTION_UNDO_INTLOK_GB');
2422          else
2423             hr_utility.set_message (801, 'HR_7507_ACTION_UNDO_INTLOCK');
2424          end if;
2425          hr_utility.raise_error;
2426    end;
2427 end val_assact_rollback;
2428 --
2429 /*
2430  *  assignment level error handler. When we encounter
2431  *  an assignment level error, we call this procedure.
2432  *  This controls the counting of errors and writing
2433  *  messages to the message lines table.
2434  */
2435 procedure assact_error(p_info in rollback_rec,
2436           error_code in number, error_message in varchar2) is
2437    c_indent varchar2(40);
2438    message_text pay_message_lines.line_text%type;
2439 begin
2440    if g_debug then
2441       c_indent := 'py_rollback_pkg.assact_error';
2442       hr_utility.set_location(c_indent, 10);
2443    end if;
2444 --
2445    --  handle the assignment action level error.
2446    --  get the message text to write. Need to get it
2447    --  in diffferent ways for oracle and user errors.
2448    if(error_code = hr_utility.hr_error_number)
2449    then
2450       --  specific exception raised.
2451       message_text := substrb(hr_utility.get_message, 1, 240);
2452    else
2453       --  oracle error.
2454       message_text := error_message;
2455    end if;
2456 --
2457    --  we can now insert the messge to message lines.
2458    if g_debug then
2459       hr_utility.set_location(c_indent, 10);
2460    end if;
2461    insert  into pay_message_lines (
2462            line_sequence,
2463            payroll_id,
2464            message_level,
2465            source_id,
2466            source_type,
2467            line_text)
2468    values (pay_message_lines_s.nextval,
2469            p_info.payroll_id,
2470            'F',    -- it's a fatal message.
2471            p_info.assact_id,
2472            'A',    -- assignment action level.
2473            message_text);
2474 --
2475    pay_core_utils.push_message(801, null, message_text, 'F');
2476 --
2477    --  keep track of the number of errors
2478    --  fail if we have had too many.
2479    g_error_count := g_error_count + 1;
2480 --
2481    if(g_error_count > p_info.max_errors_allowed)
2482    then
2483       --  too many errors. we now abort with a message.
2484       --  commit any work we have already done if
2485       --  we are allowed to do so.
2486       if(p_info.dml_mode = 'FULL' or p_info.multi_thread)
2487       then
2488          commit;
2489       end if;
2490 --
2491       --  raise error to indicate entire process has failed.
2492       hr_utility.set_message (801, 'HR_7269_ASS_TOO_MANY_ERRORS');
2493       hr_utility.raise_error;
2494    end if;
2495 end assact_error;
2496 --
2497 /*
2498  *  Lock and return a range row.
2499  *  A range of ids are locked by first setting a database
2500  *  lock and then updating the status to 'P', at which
2501  *  point is 'belongs' to the thread and we can commit.
2502  *  If there are no lockable rows, returns a null for
2503  *  the chunk number to indicate end of processing.
2504  */
2505 function next_range(p_info in rollback_rec)
2506 return range_rec is
2507    norows     boolean;
2508    range_info range_rec;
2509    c_indent varchar2(40);
2510 begin
2511    if g_debug then
2512       c_indent := 'py_rollback_pkg.next_range';
2513       hr_utility.set_location(c_indent, 1);
2514    end if;
2515    -- select a range row for update.
2516    begin
2517       if g_debug then
2518          hr_utility.set_location(c_indent, 2);
2519       end if;
2520       select rge.chunk_number,
2521              rge.starting_person_id,
2522              rge.ending_person_id
2523       into   range_info
2524       from   pay_population_ranges rge
2525       where  rge.payroll_action_id = p_info.pact_id
2526       and    rge.range_status      = 'U'
2527       and    rownum < 2
2528       for update of rge.chunk_number;
2529 --
2530       if g_debug then
2531          hr_utility.set_location(c_indent, 3);
2532       end if;
2533       --  If we reach here, we have a range row
2534       --  and we therefore wish to lock it.
2535       update pay_population_ranges pop
2536       set    pop.range_status      = 'P'
2537       where  pop.payroll_action_id = p_info.pact_id
2538       and    pop.chunk_number      = range_info.chunk_number;
2539 --
2540       if g_debug then
2541          hr_utility.set_location(c_indent, 4);
2542       end if;
2543       --  Only commit if we are allowed to.
2544       if(p_info.multi_thread or p_info.dml_mode = 'FULL')
2545       then
2546          if g_debug then
2547             hr_utility.set_location(c_indent, 5);
2548          end if;
2549          commit;
2550       end if;
2551    exception
2552       when no_data_found then
2553         if g_debug then
2554            hr_utility.set_location(c_indent, 7);
2555         end if;
2556         range_info.chunk_number := null;
2557    end;
2558 --
2559    if g_debug then
2560       hr_utility.set_location(c_indent, 8);
2561    end if;
2562    return(range_info);
2563 end next_range;
2564 --
2565 procedure perform_act_rollback(p_info in out nocopy rollback_rec)
2566 is
2567 begin
2568    if g_debug then
2569       hr_utility.set_location ('perform_asg_rollback',10);
2570    end if;
2571 --
2572    --  set a savepoint in case we fail.
2573    savepoint before;
2574 --
2575    --  make checks for validity of rollback.
2576    val_assact_rollback(p_info);   --
2577 --
2578    --  actually perform the rollback/mark for retry.
2579    do_assact_rollback(p_info);
2580 --
2581    if g_debug then
2582       hr_utility.set_location ('perform_asg_rollback',20);
2583    end if;
2584    --  if succeeded in processing, we reset the
2585    --  error counter, since we only wish to count
2586    --  consecutive errors.
2587    g_error_count := 0;
2588 --
2589 exception
2590    --  we may be reaching here due to failure in validation
2591    --  or because we have an unhandled exception (oracle error).
2592    --  in both cases we attempt to write the message text to
2593    --  message lines before continuing. This is done up to
2594    --  the error limit, then we exit.
2595    when others then
2596       if g_debug then
2597          hr_utility.set_location ('perform_asg_rollback',30);
2598       end if;
2599       rollback to savepoint before;    -- throw away any work.
2600       if(p_info.all_or_nothing)
2601       then
2602          --  fail immediately for this case.
2603          raise;
2604       else
2605          assact_error(p_info, sqlcode, sqlerrm);
2606       end if;
2607 end;
2608 /*
2609  *  Performs the dml for rolling back or
2610  *  marking for retry assignment actions.
2611  */
2612 procedure assact_dml(p_info in out nocopy rollback_rec) is
2613 --
2614    range_info        range_rec;
2615 --
2616    /*
2617     * Notice we outer join to period of service to
2618     * allow locking when we have a row.  We will not have
2619     * a period of service for benefit assignments.
2620     */
2621    cursor c1 is
2622    select /*+ ORDERED*/ act.assignment_action_id,
2623           asg.period_of_service_id
2624    from   per_all_assignments_f  asg,
2625           pay_assignment_actions act
2626    where  act.payroll_action_id    = p_info.pact_id
2627    and    asg.assignment_id        = act.assignment_id
2628    and    act.source_action_id is null
2629    and    ((p_info.action_type = 'X'
2630            and asg.effective_start_date = (select max(asg2.effective_start_date)
2631                                            from per_all_assignments_f asg2
2632                                            where asg2.assignment_id =
2633                                                         asg.assignment_id)
2634            )
2635           or
2636            ((p_info.action_type = 'PRU' or p_info.action_type = 'Z')
2637            and asg.effective_start_date = (select max(asg2.effective_start_date)
2638                                            from per_all_assignments_f asg2
2639                                            where asg2.assignment_id =
2640                                                         asg.assignment_id
2641                                            and asg2.effective_start_date <=
2642                                                         p_info.action_date)
2643             )
2644            or
2645             (p_info.action_type = 'BEE'
2646             and asg.effective_start_date = (select max(ASS2.effective_start_date)
2647                                             from   per_all_assignments_f ASS2,
2648                                                    pay_batch_lines pbl
2649                                             where  ASS2.assignment_id = asg.assignment_id
2650                                             and    pbl.batch_id (+) =  p_info.batch_id
2651                                             and    pbl.assignment_id (+) = asg.assignment_id
2652                                             and    pbl.effective_Date (+) between ASS2.effective_start_date
2653                                                    and ASS2.effective_end_date))
2654            or
2655             (p_info.action_type not in ('BEE','Z','X')
2656             and p_info.action_date between
2657                 asg.effective_start_date and asg.effective_end_date))
2658    and    asg.person_id between
2659           range_info.starting_person and range_info.ending_person
2660    for update of act.action_status,
2661                  asg.assignment_id
2662    order by act.action_sequence desc;
2663 --
2664    cursor c2 is
2665    select act.assignment_action_id
2666    from   pay_assignment_actions act
2667    where  act.payroll_action_id    = p_info.pact_id
2668    and    act.source_action_id is null
2669    and    act.object_id between
2670           range_info.starting_person and range_info.ending_person
2671    for update of act.action_status
2672    order by act.action_sequence desc;
2673 --
2674    cursor c3(c_period_of_service_id number) is
2675    select pos.period_of_service_id
2676    from   per_periods_of_service pos
2677    where  pos.period_of_service_id = c_period_of_service_id
2678    for update of pos.period_of_service_id;
2679 --
2680    commit_limit number;
2681 begin
2682    if g_debug then
2683       hr_utility.set_location ('assact_dml',1);
2684    end if;
2685    --  Attempt to get a range to process.
2686    range_info := next_range(p_info);
2687 --
2688    if g_debug then
2689       if g_debug then
2690          hr_utility.trace('max_single_undo    = ' || p_info.max_single_undo);
2691          hr_utility.trace('max_errors_allowed = ' || p_info.max_errors_allowed);
2692          hr_utility.set_location ('assact_dml',2);
2693       end if;
2694    end if;
2695    --  Continue to process a chunk at a time,
2696    --  as long as we can lock a range row.
2697    while(range_info.chunk_number is not null)
2698    loop
2699       hr_utility.set_location ('assact_dml',3);
2700 --
2701       /* By default it must be an assignment action */
2702       if (p_info.object_type is null) then
2703          for c1rec in c1 loop
2704             p_info.assact_id := c1rec.assignment_action_id;
2705             if c1rec.period_of_service_id is not null then
2706               for c3rec in c3(c1rec.period_of_service_id) loop
2707                 null; -- Locking Period of service.
2708               end loop;
2709             end if;
2710             perform_act_rollback(p_info);
2711          end loop;  -- assact loop.
2712       else
2713          /* OK, it must be an object action */
2714          for c2rec in c2 loop
2715             p_info.assact_id := c2rec.assignment_action_id;
2716             perform_act_rollback(p_info);
2717          end loop;  -- objact loop.
2718       end if;
2719 --
2720       --  this range row is finished with.
2721       if g_debug then
2722          hr_utility.set_location('assact_dml', 20);
2723       end if;
2724       delete from pay_population_ranges range
2725       where  range.payroll_action_id = p_info.pact_id
2726       and    range.chunk_number      = range_info.chunk_number;
2727 --
2728       if g_debug then
2729          hr_utility.set_location ('assact_dml',10);
2730       end if;
2731       --  commit our processing, but only if we are
2732       --  mult-threading and dml_mode is appropriate.
2733       --  reset the commit limit to zero.
2734       if(p_info.multi_thread or p_info.dml_mode = 'FULL')
2735       then
2736          commit;
2737          commit_limit := 0;
2738       end if;
2739 --
2740       if g_debug then
2741          hr_utility.set_location ('assact_dml',11);
2742       end if;
2743       --  Attempt to lock another range.
2744       range_info := next_range(p_info);
2745    end loop;
2746 --
2747    if g_debug then
2748       hr_utility.set_location ('assact_dml',12);
2749    end if;
2750 end assact_dml;
2751 -- --
2752 /*
2753  *  validates rules that control what type of
2754  *  actions we can perform a rollback or mark
2755  *  for retry payroll action on.
2756  */
2757 procedure val_pact_rr_rules (p_info in rollback_rec)
2758 is
2759    dummy NUMBER;
2760 begin
2761    if g_debug then
2762       hr_utility.set_location('val_pact_rr_rules', 10);
2763    end if;
2764 --
2765    if(p_info.rollback_mode = 'RETRY')
2766    then
2767       if(p_info.action_type in ( 'E', 'H', 'D', 'PP'))
2768       then
2769          hr_utility.set_message(801, 'HR_7093_ACTION_CANT_RETPAY');
2770          hr_utility.set_message_token('ACTION_NAME', p_info.action_name);
2771          hr_utility.raise_error;
2772       end if;
2773    end if;
2774 --
2775    -- Special check for Purge for both modes.
2776    -- We are not allowed to rollback or mark for retry an entire
2777    -- purge payroll action if there are any assignment actions
2778    -- with secondary_status = 'C'.
2779    if (p_info.action_type = 'Z') then
2780       declare
2781          l_complete number;
2782       begin
2783          select count(*)
2784          into   l_complete
2785          from   pay_assignment_actions act
2786          where  act.payroll_action_id = p_info.pact_id
2787          and    act.secondary_status  = 'C';
2788 --
2789          if(l_complete > 0) then
2790             hr_utility.set_message(801, 'PAY_289020_PUR_CANT_ROLLBACK');
2791             hr_utility.raise_error;
2792          end if;
2793       end;
2794    end if;
2795 end val_pact_rr_rules;
2796 --
2797 --
2798 /*
2799  *  checks if the process that is being checked for retry has a dependant, or
2800  *  succeeding, process that is not in a status of complete.
2801  */
2802 procedure val_dependant (p_info in rollback_rec)
2803 is
2804    w_payroll_id_1 number(9);
2805 
2806    cursor chk_dep is
2807       select distinct pac.payroll_action_id
2808         from pay_assignment_actions  act2,
2809              pay_action_interlocks   pai,
2810              pay_assignment_actions  act,
2811              pay_payroll_actions     pac,
2812              pay_payroll_actions     pac2
2813        where pac2.payroll_action_id = p_info.pact_id
2814          and act2.payroll_action_id = pac2.payroll_action_id
2815          and pac.payroll_action_id = act.payroll_action_id
2816          and pai.locking_action_id = act.assignment_action_id
2817          and pai.locked_action_id = act2.assignment_action_id
2818          and pac.action_status <> 'C'
2819          and pac.action_type in ('A', 'H', 'M', 'PP');
2820 
2821 begin
2822    if g_debug then
2823       hr_utility.set_location('val_dependant', 18);
2824    end if;
2825 
2826   open chk_dep;
2827   fetch chk_dep into w_payroll_id_1;
2828 
2829   if chk_dep%found
2830   then
2831       if p_info.legislation_code = 'GB' then
2832          hr_utility.set_message (801, 'HR_52975_ACTION_UNDO_INTLOK_GB');
2833       else
2834          hr_utility.set_message (801, 'HR_7507_ACTION_UNDO_INTLOCK');
2835       end if;
2836       hr_utility.raise_error;
2837   end if;
2838 
2839   close chk_dep;
2840  --
2841 end val_dependant ;
2842 --
2843 /*
2844  *  validates rules that control what type of actions we
2845  *  can perform a rollback/mark for retry assignment action on.
2846  */
2847 procedure val_assact_rr_rules (p_info in rollback_rec)
2848 is
2849 begin
2850    -- Validate the rollback and mark for retry rules for
2851    -- assignment actions.
2852    if g_debug then
2853       hr_utility.set_location('val_assact_rr_rules', 10);
2854    end if;
2855 --
2856    if(p_info.rollback_mode = 'RETRY')
2857    then
2858       if(p_info.action_type in (  'PRU', 'E', 'M', 'H', 'D', 'PP') or
2859          (p_info.action_type = 'T' and p_info.sub_ledger_acc = 'N'))
2860       then
2861          hr_utility.set_message(801, 'HR_7508_ACTION_ACT_RR_RULE');
2862          hr_utility.set_message_token('ACTION_NAME', p_info.action_name);
2863          hr_utility.raise_error;
2864       end if;
2865    else
2866       -- !!!! note - temporary change for RN project.
2867       -- allow rollback of individual Magnetic Transfer assact.
2868       if(p_info.action_type in ('Q',   'U', 'E', 'PRU') or
2869          (p_info.action_type = 'T' and p_info.sub_ledger_acc = 'N'))
2870       then
2871          hr_utility.set_message(801, 'HR_7508_ACTION_ACT_RR_RULE');
2872          hr_utility.set_message_token('ACTION_NAME', p_info.action_name);
2873          hr_utility.raise_error;
2874       end if;
2875    end if;
2876 end val_assact_rr_rules;
2877 --
2878 /*
2879  *  validate the parameters passed to the rollback
2880  *  assignment and payroll action procedures.
2881  */
2882 procedure val_params (p_info in rollback_rec)
2883 is
2884 begin
2885    --  where applicable, check that parameters
2886    --  have reasonable values.
2887    if g_debug then
2888       hr_utility.set_location('val_params', 10);
2889    end if;
2890    if(p_info.rollback_mode not in ('RETRY', 'ROLLBACK', 'BACKPAY'))
2891    then
2892       hr_utility.set_message(801, 'HR_7000_ACTION_BAD_ROLL_MODE');
2893       hr_utility.raise_error;
2894    end if;
2895 --
2896    if(p_info.dml_mode not in ('FULL', 'NO_COMMIT', 'NONE'))
2897    then
2898       hr_utility.set_message(801, 'HR_7509_ACTION_BAD_DML_MODE');
2899       hr_utility.raise_error;
2900    end if;
2901 --
2902    --  certain values are illegal if they are combined.
2903    --  note that these checks are only applicable to
2904    --  the payroll action rollback level.
2905    if(p_info.rollback_level = 'P')
2906    then
2907       null;
2908    end if;
2909 end val_params;
2910 --
2911 /*
2912  *  if the rollback payroll action is being called in
2913  *  single threaded mode, we need to insert a range
2914  *  row. This allows the processing to have the same
2915  *  interface for both multi and single-thread modes.
2916  *  NOTE: no date track restriction is required for
2917  *  this statement, as we obtaining min and max
2918  *  values.  This happens to be convenient for Purge.
2919  */
2920 procedure single_thread_range(p_info in rollback_rec)
2921 is
2922    l_payroll_action_id number;
2923 begin
2924    l_payroll_action_id := p_info.pact_id;
2925    --  ok, we are single-threading. Need to remove any existing
2926    --  range rows (thought there are unlikely to be any), and
2927    --  then insert a special row.
2928    if g_debug then
2929       hr_utility.set_location('single_thread_range', 10);
2930    end if;
2931    delete from pay_population_ranges range
2932    where  range.payroll_action_id = l_payroll_action_id;
2933 --
2934    if g_debug then
2935       hr_utility.set_location('single_thread_range', 20);
2936    end if;
2937 
2938    if (p_info.object_type is null) then
2939       insert into pay_population_ranges (
2940              payroll_action_id,
2941              chunk_number,
2942              starting_person_id,
2943              ending_person_id,
2944              range_status)
2945       select /*+ USE_NL(asg)
2946                  INDEX(asg PER_ASSIGNMENTS_F_PK) */
2947              pac.payroll_action_id,
2948              1,
2949              min(asg.person_id),
2950              max(asg.person_id),
2951              'U'
2952       from   pay_payroll_actions    pac,
2953              pay_assignment_actions act,
2954              per_all_assignments_f  asg
2955       where  pac.payroll_action_id = l_payroll_action_id
2956       and    act.payroll_action_id = pac.payroll_action_id
2957       and    asg.assignment_id     = act.assignment_id
2958       group by pac.payroll_action_id;
2959    else
2960       insert into pay_population_ranges (
2961              payroll_action_id,
2962              chunk_number,
2963              starting_person_id,
2964              ending_person_id,
2965              range_status)
2966       select pac.payroll_action_id,
2967              1,
2968              min(act.object_id),
2969              max(act.object_id),
2970              'U'
2971       from   pay_payroll_actions    pac,
2972              pay_assignment_actions act
2973       where  pac.payroll_action_id = l_payroll_action_id
2974       and    act.payroll_action_id = pac.payroll_action_id
2975       group by pac.payroll_action_id;
2976    end if;
2977 --
2978    if g_debug then
2979       hr_utility.set_location('single_thread_range', 30);
2980    end if;
2981 end single_thread_range;
2982 --
2983 /*
2984  *  this is called when we are rolling back. We need to know
2985  *  whether or not the assignment actions have all been
2986  *  deleted, otherwise we do not wish to remove the payroll
2987  *  action.
2988  */
2989 function rollback_complete(p_payroll_action_id in number)
2990 return boolean is
2991    dummy number;
2992 begin
2993    select null
2994    into   dummy
2995    from   sys.dual
2996    where  exists (
2997           select null
2998           from   pay_assignment_actions act
2999           where  act.payroll_action_id = p_payroll_action_id);
3000 --
3001    -- There are still assignment actions.
3002    return(false);
3003 --
3004 exception
3005    when no_data_found then
3006       --  There are no longer assignment actions.
3007       --  the rollback is considered complete.
3008       return(true);
3009 end rollback_complete;
3010 --
3011 /*
3012  *  If we are limiting the dml that can be performed, this procedure
3013  *  is called to ensure that we do not breach the limit.
3014  *  This should only occur when the rollback procedure is called
3015  *  from a forms session. In this case, user is advised to launch
3016  *  a Rollback process from SRS.
3017  */
3018 procedure val_limit_dml(p_info in rollback_rec) is
3019    action_count number;
3020 begin
3021    select count(*)
3022    into   action_count
3023    from   pay_assignment_actions act
3024    where  act.payroll_action_id = p_info.pact_id
3025    and    rownum < (p_info.max_single_undo + 2);
3026 --
3027    if(action_count > p_info.max_single_undo) then
3028       hr_utility.set_message(801, 'HR_7722_ACTION_COMMIT_LIMIT');
3029       hr_utility.set_message_token('COMMIT_LIMIT',p_info.max_single_undo);
3030       hr_utility.raise_error;
3031    end if;
3032 end val_limit_dml;
3033 --
3034 /*
3035  *  Perform the rolling back or Marking for Retry of a Payroll Action.
3036  *  Can also be used for validation that such an action is
3037  *  permissible. For the use and meaning of the parameters, please
3038  *  refer to the package header.
3039  */
3040 procedure rollback_payroll_action
3041 (
3042    p_payroll_action_id    in number,
3043    p_rollback_mode        in varchar2 default 'ROLLBACK',
3044    p_leave_base_table_row in boolean  default false,
3045    p_all_or_nothing       in boolean  default true,
3046    p_dml_mode             in varchar2 default 'NO_COMMIT',
3047    p_multi_thread         in boolean  default false,
3048    p_limit_dml            in boolean  default false,
3049    p_grp_multi_thread     in boolean  default false
3050 ) is
3051    info     rollback_rec;   -- 'global' information.
3052    c_indent varchar2(40);
3053    l_date_earned date;
3054 begin
3055    g_debug := hr_utility.debug_enabled;
3056    if g_debug then
3057       c_indent := 'py_rollback_pkg.rollback_payroll_action';
3058       hr_utility.set_location(c_indent, 5);
3059    end if;
3060    --  set up the parameters.
3061    info.rollback_mode      := p_rollback_mode;
3062    info.rollback_level     := 'P';  -- processing entire Payroll Action.
3063    info.leave_row          := p_leave_base_table_row;
3064    info.all_or_nothing     := p_all_or_nothing;
3065    info.multi_thread       := p_multi_thread;
3066    info.grp_multi_thread   := p_grp_multi_thread;
3067    info.dml_mode           := p_dml_mode;
3068    info.limit_dml          := p_limit_dml;
3069    info.pact_id            := p_payroll_action_id;
3070 --
3071    -- Set the Continuous Calc override flag, so that the trigger points
3072    -- are not fired.
3073    pay_continuous_calc.g_override_cc := TRUE;
3074 --
3075    -- Ensure delete from gl_interface in remove_gl_entries on
3076    -- each execution.
3077    mtgl_mode_cached := FALSE;
3078 --
3079    --  how many errors can we stand, what commit limit do we have?
3080    info.max_errors_allowed := action_parameter('MAX_ERRORS_ALLOWED');
3081    info.max_single_undo := action_parameter('MAX_SINGLE_UNDO');
3082    info.set_date_earned := action_parameter('SET_DATE_EARNED');
3083 --
3084    --  May wish to limit number of actions that can
3085    --  be rolled back.  This is mainly for forms.
3086    if(info.limit_dml and not info.multi_thread) then
3087       val_limit_dml(info);
3088    end if;
3089 --
3090    get_pact_info(info);      --  get payroll action level information.
3091 --
3092    info.retro_purge := legislation_rule(info.legislation_code, 'RETRO_DELETE');
3093    pay_core_utils.get_upgrade_status(info.bg_id,
3094                                      'SINGLE_BAL_TABLE',
3095                                      info.single_bal_table);
3096 --
3097    val_params(info);         --  validate parameters passed in.
3098 
3099    if(info.rollback_mode = 'RETRY' and info.action_status in ('C', 'S'))
3100    then
3101       val_dependant(info);   --  does the payroll action have an uncompleted
3102                              --  dependant payroll action?
3103    end if;
3104 
3105    val_pact_rr_rules(info);  --  can we rollback the payroll action.
3106 --
3107    if(not info.multi_thread) then
3108       --  single threading, insert special range row.
3109       single_thread_range(info);
3110    end if;
3111 --
3112    -- Depending on the dml mode, we may wish to
3113    -- set a savepoint.
3114    if(info.dml_mode = 'NONE') then
3115       if g_debug then
3116          hr_utility.set_location(c_indent, 10);
3117       end if;
3118       savepoint no_dml;
3119    end if;
3120 --
3121    if (info.action_type = 'PRU') then
3122       remove_pact_payment(info.pact_id);
3123    end if;
3124 --
3125    assact_dml(info);            -- do the rollback of assact rows.
3126 --
3127 -- delete archive_items for the context of payroll_action_id
3128 --
3129    if g_debug then
3130       hr_utility.set_location(c_indent, 12);
3131    end if;
3132 --
3133    -- Remove archiver items at the payroll action level
3134    if (info.action_type = 'X' or
3135        info.action_type = 'PP' or
3136        info.action_type = 'M') then
3137      remove_archive_items(info, info.pact_id, 'PA');
3138      remove_action_information(info.pact_id, 'PA');
3139      remove_file_details(info, info.pact_id, 'PPA');
3140    end if;
3141 --
3142    if g_debug then
3143       hr_utility.set_location(c_indent, 15);
3144    end if;
3145 --
3146    --
3147    -- delete group level run balances
3148    --
3149    if (info.sequenced_flag and
3150        rollback_complete(info.pact_id)) then
3151      delete from pay_run_balances
3152      where  payroll_action_id = info.pact_id;
3153    end if;
3154 --
3155    if(info.dml_mode = 'NONE') then
3156       hr_utility.set_location(c_indent, 20);
3157       rollback to savepoint no_dml;
3158    end if;
3159 --
3160    --  we insert a message to indicate that the rollback was successful.
3161    --  Note that we perform this whether or not we are going to actually
3162    --  delete the payroll action row, as we assume that the caller
3163    --  will perform this action, even if we do not. Also note that it is
3164    --  only done if we have rolled back all assignment actions.
3165    --  Finally, if we are multi-threading, we wish to leave the process
3166    --  to insert the message.
3167    if(info.rollback_mode = 'ROLLBACK' and
3168       rollback_complete(info.pact_id) and
3169       not info.multi_thread)
3170    then
3171       remove_messages(info, 'P');
3172       -- Only insert message if the action is not an
3173       -- initial balance upload.
3174       if (info.action_type <> 'I') then
3175         ins_rollback_message(info, 'P');
3176       end if;
3177    end if;
3178 --
3179    -- now if the rollback is successful then we update the bee batch.
3180    if (rollback_complete(info.pact_id) and info.action_type ='BEE') then
3181       pay_mix_rollback_pkg.set_status(info.pact_id,info.leave_row);
3182    end if;
3183 --
3184    --  now we perform any action that we require (and
3185    --  are allowed to perform) on the payroll action
3186    --  row itself. Normally, we would not wish to touch
3187    --  the row if the client was a form.
3188    if(not info.leave_row and rollback_complete(info.pact_id))
3189    then
3190       --  delete the payroll action row if we are told to.
3191       if g_debug then
3192          hr_utility.set_location(c_indent, 30);
3193       end if;
3194       delete from pay_chunk_status
3195        where payroll_action_id = info.pact_id;
3196       delete from pay_payroll_actions pac
3197       where  pac.payroll_action_id = info.pact_id;
3198    else
3199      if (info.sequenced_flag=FALSE) then
3200        if (info.rollback_mode <> 'BACKPAY'
3201           and info.rollback_mode <> 'RETRY'
3202           and info.action_type <> 'BEE') then
3203          if info.rollback_level = 'P' then
3204            if info.set_date_earned = 'Y' then
3205               select max(date_earned)
3206               into   l_date_earned
3207               from   pay_payroll_actions    locked_pact,
3208                      pay_assignment_actions locked,
3209                      pay_assignment_actions locking,
3210                      pay_action_interlocks  locks
3211               where  locking.payroll_action_id    =info.pact_id
3212               and    locking.assignment_action_id =locks.locking_action_id
3213               and    locked.assignment_action_id  =locks.locked_action_id
3214               and    locked.payroll_action_id     =locked_pact.payroll_action_id;
3215 --
3216               update pay_payroll_actions pac
3217               set    pac.date_earned              = l_date_earned
3218               where  pac.payroll_action_id        = info.pact_id;
3219            end if;
3220          end if;
3221        end if;
3222      end if;
3223    end if;
3224 --
3225    --  decide if we wish to perform that final commit
3226    if(info.dml_mode = 'FULL')
3227    then
3228       if g_debug then
3229          hr_utility.set_location(c_indent, 40);
3230       end if;
3231       commit;
3232    end if;
3233 --
3234    pay_continuous_calc.g_override_cc := FALSE;
3235 --
3236    exception
3237       when others then
3238         pay_continuous_calc.g_override_cc := FALSE;
3239         raise;
3240 end rollback_payroll_action;
3241 --
3242 /*
3243  *  Interface to rollback/mark for retry of an assignment action.
3244  *  see the package header for details of the parameters.
3245  *  Takes into account assignment level erroring.
3246  */
3247 procedure rollback_ass_action
3248 (
3249    p_assignment_action_id in number,
3250    p_rollback_mode        in varchar2 default 'ROLLBACK',
3251    p_leave_base_table_row in boolean  default false,
3252    p_all_or_nothing       in boolean  default true,
3253    p_dml_mode             in varchar2 default 'NO_COMMIT',
3254    p_multi_thread         in boolean  default false,
3255    p_grp_multi_thread     in boolean  default false
3256 ) is
3257    info     rollback_rec;
3258    c_indent varchar2(40);
3259    l_date_earned date;
3260    l_current_date_earned date;
3261    src_action_id number;
3262 --
3263 begin
3264    g_debug := hr_utility.debug_enabled;
3265    --  need to know the payroll action.
3266    if g_debug then
3267       c_indent := 'py_rollback_pkg.rollback_ass_action';
3268       hr_utility.set_location(c_indent, 10);
3269    end if;
3270    select act.payroll_action_id, act.source_action_id, act.object_type
3271    into   info.pact_id, src_action_id, info.object_type
3272    from   pay_assignment_actions act
3273    where  act.assignment_action_id = p_assignment_action_id;
3274 --
3275    --  instantiate the other parameters that are relevant.
3276    info.assact_id          := p_assignment_action_id;
3277    info.rollback_mode      := p_rollback_mode;
3278    info.rollback_level     := 'A';
3279    info.leave_row          := p_leave_base_table_row;
3280    info.dml_mode           := p_dml_mode;
3281    info.multi_thread       := p_multi_thread;
3282    info.grp_multi_thread   := p_grp_multi_thread;
3283 --
3284    -- Check that it is a master action.
3285    if src_action_id is not null then
3286       hr_utility.set_message(801, 'PAY_289114_RLBK_CHLD_ACT');
3287       hr_utility.raise_error;
3288    end if;
3289 --
3290    --  how many errors can we stand, what commit limit do we have?
3291    info.max_errors_allowed := action_parameter('MAX_ERRORS_ALLOWED');
3292    info.max_single_undo := action_parameter('MAX_SINGLE_UNDO');
3293    info.set_date_earned := action_parameter('SET_DATE_EARNED');
3294 --
3295    get_pact_info(info);  --  get info about payroll action.
3296 --
3297    info.retro_purge := legislation_rule(info.legislation_code, 'RETRO_DELETE');
3298    pay_core_utils.get_upgrade_status(info.bg_id,
3299                                      'SINGLE_BAL_TABLE',
3300                                      info.single_bal_table);
3301 --
3302    val_params(info);     --  parameter validation.
3303 --
3304    --  For BackPay, we do not care about normal
3305    --  rules about whether a single action of a
3306    --  particular action type can be rolled
3307    --  back or not.
3308    if(info.rollback_mode <> 'BACKPAY') then
3309       val_assact_rr_rules(info);
3310    else
3311       select assignment_id
3312         into info.assignment_id
3313         from pay_assignment_actions
3314        where assignment_action_id = info.assact_id;
3315    end if;
3316 --
3317    --  perform the rollback/mark for retry itself.
3318    --  from now on, errors are considered to be assignment action
3319    --  level. Depending on the mode, we may stop immediately.
3320    --  In backpay case, we do not wish to validate the rollback,
3321    --  simply wishing to perform it. This is because BackPay does
3322    --  only performs rollback on Reversals, Runs and QuickPays.
3323    begin
3324 --
3325       -- in case we fail.
3326       savepoint before;
3327 --
3328       -- Set the Continuous Calc override flag, so that the trigger points
3329       -- are not fired.
3330       pay_continuous_calc.g_override_cc := TRUE;
3331 --
3332       if(info.rollback_mode <> 'BACKPAY') then
3333          val_assact_rollback(info);
3334       end if;
3335 --
3336       -- Only perform dml if allowed to.
3337       if(info.dml_mode <> 'NONE') then
3338          do_assact_rollback(info);
3339          -- update date earned for payroll action
3340          if (info.sequenced_flag=FALSE) then
3341           if (info.rollback_mode <> 'BACKPAY'
3342              and info.rollback_mode <> 'RETRY'
3343              and info.action_type <> 'X'
3344              and info.action_type <> 'BEE') then
3345             if info.rollback_level = 'A' then
3346 
3347               if info.set_date_earned = 'Y' then
3348                 begin
3349                   -- Handle that the rolled back assignment action
3350                   -- may have been the last one
3351                   select max(locked_pact.date_earned), locking_pact.date_earned
3352                   into   l_date_earned, l_current_date_earned
3353                   from   pay_payroll_actions    locked_pact,
3354                          pay_assignment_actions locked,
3355                          pay_assignment_actions locking,
3356                          pay_action_interlocks  locks,
3357                          pay_payroll_actions    locking_pact
3358                   where  locking_pact.payroll_action_id =info.pact_id
3359                   and    locking.payroll_action_id    =locking_pact.payroll_action_id
3360                   and    locking.assignment_action_id =locks.locking_action_id
3361                   and    locked.assignment_action_id  =locks.locked_action_id
3362                   and    locked.payroll_action_id     =locked_pact.payroll_action_id
3363                   group by locking_pact.date_earned;
3364 --
3365                   if (l_date_earned < l_current_date_earned) then
3366                     update pay_payroll_actions pac
3367                     set    pac.date_earned              = l_date_earned
3368                     where  pac.payroll_action_id        = info.pact_id;
3369                   end if;
3370 --
3371                 exception
3372                   when others then
3373                     update pay_payroll_actions pac
3374                     set    pac.date_earned              = null
3375                     where  pac.payroll_action_id        = info.pact_id;
3376                 end;
3377               end if;
3378             end if;
3379           end if;
3380          end if;
3381 --
3382 --       Remove the group run balances for resersal.
3383 --
3384          if (info.action_type = 'V') then
3385 --
3386            delete from pay_run_balances
3387             where payroll_action_id = info.pact_id;
3388 --
3389          end if;
3390       end if;
3391       g_error_count := 0;     --  only count consecutive errors.
3392       pay_continuous_calc.g_override_cc := FALSE;
3393    exception
3394       -- Throw away any work we have done.
3395       when others then
3396          rollback to savepoint before;
3397          pay_continuous_calc.g_override_cc := FALSE;
3398          if(p_all_or_nothing) then
3399             raise;
3400          else
3401             assact_error(info, sqlcode, sqlerrm);
3402          end if;
3403    end;
3404 --
3405    --  we may wish to commit.
3406    if(info.dml_mode = 'FULL')
3407    then
3408       commit;
3409    end if;
3410 end rollback_ass_action;
3411 --
3412 --
3413 begin
3414 --
3415    --  Having the error counter as a package global and
3416    --  initialising it here allows the error counting
3417    --  mechanism to work whether we are rolling back a
3418    --  whole payroll action or assignment action by
3419    --  assignment action.
3420    g_error_count := 0;
3421 --   hr_utility.trace_on(null, 'ORACLE');
3422 end py_rollback_pkg;