DBA Data[Home] [Help]

PACKAGE BODY: APPS.HR_USER_ACCT_EMP_EXTRACT

Source


1 PACKAGE BODY HR_USER_ACCT_EMP_EXTRACT AS
2 /* $Header: hrempext.pkb 120.2.12000000.2 2007/03/08 06:01:24 tkghosh ship $*/
3 --
4 --
5 -- |--------------------------------------------------------------------------|
6 -- |--< PRIVATE GLOBAL VARIABLES >--------------------------------------------|
7 -- |--------------------------------------------------------------------------|
8   g_data_pump_create_user    constant varchar2(30) := 'hrdpp_create_user_acct';
9   g_data_pump_upd_user       constant varchar2(30) := 'hrdpp_update_user_acct';
10   g_commit_limit             constant number := 20;
11   l_commit_count             number default 0;
12   g_package                  constant varchar2(72) :='hr_user_acct_emp_extract';
13   g_dp_str                   constant varchar2(15) :='~!@UAEEP@!~';
14   g_dp_ins_str               constant varchar2(25) := 'SS_' || g_dp_str || '_INS';
15   g_dp_upd_str               constant varchar2(25) := 'SS_' || g_dp_str || '_UPD';
16 
17 
18 --
19 /*
20 ||===========================================================================
21 || PROCEDURE: run_process
22 ||----------------------------------------------------------------------------
23 ||
24 || Description:
25 ||     This procedure is invoked by Concurrent Manager to extract
26 ||     employees based on input parameters passed.
27 ||
28 || Pre-Conditions:
29 ||     Employee Data must exist on the database.
30 ||
31 || Input Parameters:
32 ||
33 || Output Parameters:
34 ||
35 || In out nocopy Parameters:
36 ||
37 || Post Success:
38 ||      Selected employees are written to hr_pump_batch_lines table.
39 ||
40 || Post Failure:
41 ||     Raise exception.
42 ||
43 || Access Status:
44 ||     Public
45 ||
46 ||=============================================================================
47 */
48   PROCEDURE run_process (
49      errbuf                     out nocopy varchar2
50     ,retcode                    out nocopy number
51     ,p_batch_name               in hr_pump_batch_headers.batch_name%TYPE
52     ,p_date_from                in varchar2 default null
53     ,p_date_to                  in varchar2 default null
54     ,p_business_group_id        in per_all_people_f.business_group_id%type
55     ,p_single_org_id            in per_organization_units.organization_id%type
56                                    default null
57     ,p_organization_structure_id in
58                    per_organization_structures.organization_structure_id%type
59                                    default null
60     ,p_org_structure_version_id in
61                    per_org_structure_versions.org_structure_version_id%type
62                                    default null
63     ,p_parent_org_id            in per_organization_units.organization_id%type
64                                    default null
65     ,p_run_type                 in varchar2
66   )
67   IS
68 --
69 --
70   CURSOR lc_check_if_batch_name_used
71   IS
72   SELECT  'Y'
73   FROM    hr_pump_batch_headers
74   WHERE   upper(batch_name) = upper(p_batch_name);
75 --
76 
77   CURSOR lc_get_bg_name
78   IS
79   SELECT name
80   FROM   hr_all_organization_units
81   WHERE  business_group_id = p_business_group_id
82   AND    organization_id = p_business_group_id;
83 --
84   CURSOR      lc_get_org_id
85   IS
86   SELECT      organization_id_child
87   FROM        per_org_structure_elements
88   CONNECT BY  organization_id_parent = prior organization_id_child
89   AND         org_structure_version_id = prior org_structure_version_id
90   START WITH  organization_id_parent = p_parent_org_id
91   AND         org_structure_version_id = p_org_structure_version_id
92   UNION
93   SELECT      p_parent_org_id
94   FROM        SYS.DUAL;
95 --
96 
97 CURSOR      lc_get_ex_emp_per_type_id
98   IS
99   SELECT      person_type_id
100   FROM        per_person_types
101   WHERE       business_group_id = p_business_group_id
102   AND        SYSTEM_PERSON_TYPE = 'EMP'
103   AND         active_flag = 'Y';
104 
105 --
106   CURSOR      lc_get_emp_per_type_id
107   IS
108   SELECT      person_type_id
109   FROM        per_person_types
110   WHERE       business_group_id = p_business_group_id
111   AND         (SYSTEM_PERSON_TYPE = 'EMP'
112                OR
113                SYSTEM_PERSON_TYPE = 'EMP_APL')
114   AND         active_flag = 'Y';
115 --
116   CURSOR      lc_get_asg_status_type_id (p_per_sys_status  in varchar2)
117   IS
118   SELECT      ast.assignment_status_type_id
119   FROM        per_assignment_status_types    ast
120   WHERE       nvl(ast.business_group_id, p_business_group_id)
121               = p_business_group_id
122   AND         ast.active_flag = 'Y'
123   AND         ast.per_system_status = p_per_sys_status;
124 
125 
126   l_proc      varchar2(2000) := 'hr_user_acct_emp_extract.run_process';
127   l_batch_name_found         varchar2(1) default null;
128   l_data_pump_pkg_name1      varchar2(30) default null;
129   l_data_pump_pkg_name2      varchar2(30) default null;
130   l_date_from                date default null;
131   l_date_from_char                varchar2(2000) default null;
132   l_date_to                  date default null;
133   l_date_to_char                  varchar2(2000) default null;
134   l_basic_sql_clause         varchar2(2000) default null;
135   l_org_matching             varchar2(5000) default null;
136   l_new_hires_matching       varchar2(10000) default null;
137   l_terminated_ee_matching   varchar2(10000) default null;
138   l_all_ee_matching          varchar2(10000) default null;
139   l_sql_clause               varchar2(32000) default null;
140   l_group_by_clause          varchar2(500) default null;
141   l_inactivate_user_sql_clause  varchar2(32000) default null;
142   l_temp                     number default null;
143   l_date_temp                date default null;
144   l_batch_id                 number default null;
145   l_dynamic_cursor_id        integer := 0;
146   l_index                    integer :=0;
147   l_rows                     integer :=0;
148   l_new_user_count           number :=0;
149   l_inactivate_user_count    number :=0;
150   l_person_id                number default null;
151   l_effective_start_date     date default null;
152   l_effective_end_date       date default null;
153   l_hire_date                date default null;
154   l_term_date                date default null;
155   l_bg_name                  hr_all_organization_units.name%type default null;
156   l_commit_count             number default 0;
157   l_org_id_list              varchar2(32000);
158   l_per_type_id_list         varchar2(2000);
159   l_asg_status_type_id       number;
160   l_asg_status_type_clause   varchar2(200);
161   l_msg                      varchar2(2000) default null;
162   l_asg_eff_start_date       date default null;
163   l_asg_eff_end_date         date default null;
164   l_asg_id                   number default null;
165 
166   l_prev_per_id              number default null;
167   l_prev_eff_start_date      date default null;
168   l_prev_eff_end_date        date default null;
169   l_prev_asg_id              number default null;
170   l_prev_asg_eff_start_date  date default null;
171   l_prev_asg_eff_end_date    date default null;
172   l_prev_hire_date           date default null;
173   l_prev_term_date           date default null;
174   l_asg_status_type_id_list  varchar2(2000);
175 
176   l_unique_str               varchar2(200);
177 --
178 BEGIN
179   --
180  hr_utility.set_location('Entering ' || l_proc, 10);
181 
182   IF p_batch_name is NULL
183   THEN
184      fnd_message.set_name('PER', 'HR_BATCH_NAME_NOT_SPECIFIED');
185      fnd_message.raise_error;
186   ELSE
187      OPEN lc_check_if_batch_name_used;
188      FETCH lc_check_if_batch_name_used into l_batch_name_found;
189      IF lc_check_if_batch_name_used%NOTFOUND
190      THEN
191         CLOSE lc_check_if_batch_name_used;
192      ELSE
193         CLOSE lc_check_if_batch_name_used;
194         fnd_message.set_name('PER', 'HR_BATCH_NAME_ALREADY_EXISTS');
195         fnd_message.raise_error;
196      END IF;
197   END IF;
198   --
199   hr_utility.set_location('run_type=' || p_run_type, 20);
200 
201   -- Check run type
202   -----------------------------------------------------------------------------
203   -- NOTE:
204   -- When p_run_type is g_cr_user_new_hires, g_cr_user_all_emp,
205   -- l_data_pump_pkg_name1 contains a value, l_data_pump_pkg_name2 will be
206   -- null.
207   -- When p_run_type is gv_inactivate_user , then l_data_pump_pkg_name2
208   -- contains a value, l_data_pump_pkg_name1 will be null.
209   -- When p_run_type is gv_cr_n_inact_user, then both l_data_pump_pkg_name1
210   -- and l_data_pump_pkg_name2 contain a value.
211   -----------------------------------------------------------------------------
212   IF p_run_type = hr_user_acct_utility.g_cr_user_new_hires OR
213      p_run_type = hr_user_acct_utility.g_cr_user_all_emp
214   THEN
215      l_data_pump_pkg_name1 := g_data_pump_create_user;
216   ELSIF p_run_type = hr_user_acct_utility.g_inactivate_user
217   THEN
218      l_data_pump_pkg_name2 := g_data_pump_upd_user;
219   ELSE  -- create and inactivate user accounts
220      l_data_pump_pkg_name1 := g_data_pump_create_user;
221      l_data_pump_pkg_name2 := g_data_pump_upd_user;
222   END IF;
223 
224 --Get bg name
225   OPEN lc_get_bg_name;
226   FETCH lc_get_bg_name into l_bg_name;
227   IF lc_get_bg_name%NOTFOUND
228   THEN
229      close lc_get_bg_name;
230      l_bg_name := null;
231   ELSE
232      close lc_get_bg_name;
233   END IF;
234 --
235   -- Convert varchar2 dates to date datatype
236   -- 1) Convert format
237   -- 2) Remove time component
238   IF p_date_from is NOT NULL
239   THEN
240 	-- For R11.5, the FND date format is 'YYYY/MM/DD HH24:MI:SS'.
241      l_date_from := to_date(p_date_from, fnd_date.canonical_dt_mask);
242      l_date_from := trunc(l_date_from);
243   ELSE
244      l_date_from := trunc(sysdate);
245   END IF;
246   --
247   IF p_date_to is NOT NULL
248   THEN
249      l_date_to   := to_date(p_date_to, fnd_date.canonical_dt_mask);
250      l_date_to   := trunc(l_date_to);
251   ELSE
252      -- Default date_to to end of time so that we can allow future date
253      -- execution.  For example, date_from is a future date with respective to
254      -- sysdate.  Hence, setting date_to to sysdate in this case will cause
255      -- date_to smaller than the date_from.
256      l_date_to := trunc(hr_api.g_eot);
257   END IF;
258   --
259   -- Check if Date_from is greater than date_to
260   IF l_date_to < l_date_from
261   THEN
262      fnd_message.set_name('PER', 'PER_7003_ALL_DATE_FROM_TO');
263      fnd_message.raise_error;
264   END IF;
265 --
266   -- Now, convert the date to varchar2 format for use in dynamic sql statement.
267   -- In R11.5, use the FND standard date format, which is 'YYYY/MM/DD'
268   l_date_from_char := to_char(l_date_from, fnd_date.canonical_mask);
269   l_date_to_char := to_char(l_date_to, fnd_date.canonical_mask);
270 --
271 -------------------------------------------------------------------------------
272 -- NOTE: If users enter Organization Hierarchy and Version, then the
273 --       p_single_org_id is ignored.  Organization Hierarchy and Single Org
274 --       are mutually exclusive.
275 -------------------------------------------------------------------------------
276   IF p_org_structure_version_id IS NOT NULL AND
277      p_parent_org_id IS NOT NULL
278   THEN
279      FOR get_hierarchy_org_id in lc_get_org_id
280      LOOP
281         l_org_id_list := l_org_id_list ||
282                          get_hierarchy_org_id.organization_id_child || ',';
283      END LOOP;
284      --
285      -- Remove the last comma, -1 in the instr function means to scan from
286      -- right to left for the 1st occurrence of the comma.
287      l_org_id_list := substr(l_org_id_list, 1,
288                                 instr(l_org_id_list, ',', -1, 1) - 1);
289      --
290      l_org_matching :=
291        ' AND     paf.organization_id  in (' ||
292        l_org_id_list || ')';
293   ELSIF
294      p_parent_org_id IS NOT NULL
295   THEN
296      l_org_matching :=
297        ' AND     paf.organization_id = ' ||
298         to_char(p_parent_org_id);
299   --
300   ELSIF p_single_org_id IS NOT NULL
301   THEN
302      l_org_matching :=
303        ' AND     paf.organization_id = ' ||
304         to_char(p_single_org_id);
305   END IF;
306 --
307 --
308 -- Build a list for ACTIVE assignment status type id.
309   IF upper(p_run_type) = hr_user_acct_utility.g_cr_user_new_hires OR
310      upper(p_run_type) = hr_user_acct_utility.g_cr_n_inact_user OR
311      upper(p_run_type) = hr_user_acct_utility.g_cr_user_all_emp
312   THEN
313      FOR get_asg_status_type_id in lc_get_asg_status_type_id
314                              (p_per_sys_status => 'ACTIVE_ASSIGN')
315      LOOP
316         l_asg_status_type_id_list := l_asg_status_type_id_list ||
317           get_asg_status_type_id.assignment_status_type_id || ',';
318      END LOOP;
319 
320      -- Remove the last comma, -1 in the instr function means to scan from
321      -- right to left for the 1st occurrence of the comma.
322      l_asg_status_type_id_list := substr(l_asg_status_type_id_list, 1,
323                               instr(l_asg_status_type_id_list, ',', -1, 1) - 1);
324   END IF;
325   --
326   --
327 
328   IF upper(p_run_type) = hr_user_acct_utility.g_cr_user_new_hires OR
329      upper(p_run_type) = hr_user_acct_utility.g_cr_n_inact_user
330   THEN
331      l_asg_status_type_clause := ' AND paf.assignment_status_type_id in ( ' ||
332                                 l_asg_status_type_id_list || ')';
333      --
334      l_basic_sql_clause :=
335         'SELECT  DISTINCT ppf.person_id
336                 ,ppf.effective_start_date
337                 ,ppf.effective_end_date
338                 ,paf.assignment_id
339                 ,paf.effective_start_date
340                 ,paf.effective_end_date
341                 ,ppos.date_start    hire_date
342          FROM    per_periods_of_service  ppos
343                 ,per_people_f            ppf
344                 ,per_assignments_f       paf
345          WHERE   ppf.person_id = paf.person_id
346          and      paf.primary_flag = ''Y''
347          AND     ppf.business_group_id + 0 = ' ||
348                  to_char(p_business_group_id);
349 
350 
351      -- Select those new hires whose per_periods_of_service.date_start is
352      -- between the p_date_from and p_date_to dates
353      l_new_hires_matching :=
354        ' AND (ppf.effective_start_date >= to_date(''' ||
355             l_date_from_char ||
356             ''', ''' || fnd_date.canonical_mask || ''')' ||
357             ' and ppf.effective_start_date <= to_date(''' ||
358             l_date_to_char ||
359             ''', ''' || fnd_date.canonical_mask || ''')' ||
360             ' and ppf.effective_end_date >= to_date(''' ||
361             l_date_to_char ||
362             ''', ''' || fnd_date.canonical_mask || '''))' ||
363        ' AND (paf.effective_start_date >= to_date(''' ||
364             l_date_from_char ||
365             ''', ''' || fnd_date.canonical_mask || ''')' ||
366             ' and paf.effective_end_date >= to_date(''' ||
367             l_date_to_char ||
368             ''', ''' || fnd_date.canonical_mask || '''))' ||
369        ' AND  ((ppos.date_start >= to_date(''' ||
370         l_date_from_char || ''', ''' ||
371          fnd_date.canonical_mask || ''')' ||
372        ' AND ppos.date_start <= to_date(''' ||
373         l_date_to_char || ''', ''' ||
374          fnd_date.canonical_mask || '''))' ||
375 --
376 -- ---------------------------------------------------------------------------
377 --  The following is commented out.  If we need to change the termination_date
378 --  comparison, we can re-evaluate the comparsion.
379      ' AND nvl(ppos.actual_termination_date, to_date(''' ||
380       l_date_to_char || ''', ''' ||
381        fnd_date.canonical_mask || '''))' ||
382      ' <= to_date(''' || l_date_to_char ||
383      ''', ''' || fnd_date.canonical_mask || '''))' ||
384 -- ---------------------------------------------------------------------------
385 --
386 --       ' AND ppos.actual_termination_date IS NULL)' ||
387        ' AND ppos.person_id = ppf.person_id ' ||
388        ' and paf.period_of_service_id = ppos.period_of_service_id ' ||
389        ' AND paf.assignment_type = ''E'' ' ||         -- 4142819
390        ' AND ppos.business_group_id + 0 = ' || to_char(p_business_group_id);
391 
392      l_sql_clause := l_basic_sql_clause || l_asg_status_type_clause;
393      l_sql_clause := l_sql_clause || l_org_matching;
394      l_sql_clause := l_sql_clause || l_new_hires_matching;
395   END IF;
396 --
397   IF upper(p_run_type) = hr_user_acct_utility.g_cr_user_all_emp
398   THEN
399      -- For all employees, we want to select ppf.effective_start_date <=
400      -- p_date_to and ppf.effective_end_date >= p_date_to.  This conforms to
401      -- the selection logic in person search for "all employees"
402      -- (see hrprresw.pkb process_search logic).
403      --
404      --        |             |             |
405      --        |  <----------------> PerA  |
406      --        |             |             |
407      --        |       <-----------------------> PerB
408      --        |             |             |
409      --        | <----> PerC |             |
410      --        |             |             |
411      --        |             |   <----------------> PerD
412      --        |             |             |
413      --        X             Y             Z
414      --                    date_from     date_to
415      -- PerB and PerD will be selected but not PerA or PerC.
416      --
417      FOR get_emp_per_type_id_list in lc_get_emp_per_type_id
418      LOOP
419          l_per_type_id_list := l_per_type_id_list ||
420                                get_emp_per_type_id_list.person_type_id || ',';
421      END LOOP;
422      --
423      -- Remove the last comma, -1 in the instr function means to scan from
424      -- right to left for the 1st occurrence of the comma.
425      l_per_type_id_list := substr(l_per_type_id_list, 1,
426                                 instr(l_per_type_id_list, ',', -1, 1) - 1);
427      --
428      l_basic_sql_clause :=
429         'SELECT  DISTINCT ppf.person_id
430                 ,ppf.effective_start_date
431                 ,ppf.effective_end_date
432                 ,paf.assignment_id
433                 ,paf.effective_start_date
434                 ,paf.effective_end_date
435                 ,ppos.date_start    hire_date
436          FROM    per_periods_of_service  ppos
437                 ,per_people_f            ppf
438                 ,per_assignments_f       paf
439          WHERE   ppf.person_id = paf.person_id
440          and      paf.primary_flag = ''Y''
441          and      paf.assignment_type=''E''
442          AND     ppf.business_group_id + 0 = ' ||
443                  to_char(p_business_group_id);
444      --
445 
446      l_all_ee_matching :=
447        ' AND ppf.person_type_id in (' || l_per_type_id_list || ')' ||
448        ' AND (ppf.effective_start_date <= to_date(''' ||
449             l_date_to_char ||
450             ''', ''' || fnd_date.canonical_mask || ''')' ||
451             ' and ppf.effective_end_date >= to_date(''' ||
452             l_date_to_char ||
453             ''', ''' || fnd_date.canonical_mask || '''))' ||
454        ' AND (paf.effective_start_date <= to_date(''' ||
455             l_date_to_char ||
456             ''', ''' || fnd_date.canonical_mask || ''')' ||
457             ' and paf.effective_end_date >= to_date(''' ||
458             l_date_to_char ||
459             ''', ''' || fnd_date.canonical_mask || '''))' ||
460        ' AND  (ppos.date_start <= to_date(''' ||
461         l_date_to_char || ''', ''' ||  fnd_date.canonical_mask || ''')' ||
462        ' AND nvl(ppos.actual_termination_date, to_date(''' ||
463         l_date_to_char || ''', ''' ||  fnd_date.canonical_mask || '''))' ||
464        ' >= to_date(''' || l_date_to_char ||
465        ''', ''' || fnd_date.canonical_mask || '''))' ||
466        ' AND ppos.person_id = ppf.person_id ' ||
467        ' and paf.period_of_service_id = ppos.period_of_service_id ' ||
468        ' AND ppos.business_group_id + 0 =  ' || to_char(p_business_group_id);
469      --
470      l_sql_clause := l_basic_sql_clause || l_asg_status_type_clause;
471      l_sql_clause := l_sql_clause || l_org_matching;
472      l_sql_clause := l_sql_clause || l_all_ee_matching;
473   END IF;
474 --
475   IF upper(p_run_type) = hr_user_acct_utility.g_inactivate_user OR
476      upper(p_run_type) = hr_user_acct_utility.g_cr_n_inact_user
477      -- For terminated ee, we want to select ppos.actual_termination_date 1 day
478      -- before the per_all_people_f.effective_start_date where
479      -- ppf.effective_start_date >= p_date_from and ppf.effective_end_date >=
480      -- p_date_to and ppf.person_type_id in system_person_type of 'EX_EMP' or
481      -- 'EX_EMP_APL'.
482      --
483      --        |             |             |
484      --        |  <----------------> PerA  |
485      --        |             |             |
486      --        |             |<-----> PerB |
487      --        |             |             |
488      --        | <----> PerC |             |
489      --        |             |             |
490      --        X             Y             Z
491      --                    date_from     date_to
492      -- PerA and PerB will be selected but not PerC.
493      --
494      -- We want to select the max(actual_termination_date) to cover cases
495      -- where an employee has multiple periods of service like the following:
496      --
497      --    PERSON_ID  DATE_STAR ACTUAL_TERM_DATE
498      --    ---------- --------- ----------------
499      --          2525 06-FEB-00        08-FEB-00
500      --          2525 27-AUG-99        20-JAN-00
501      --
502      -- If the selection date range is 01-Jan-1999 and 10-Feb-2000, then we
503      -- want the latest termination date record 08-Feb-00 to be returned. Hence,
504      -- we want to drive off from the max(actual_termination_date) of the
505      -- per_periods_of_service.
506      --
507      -- We also need to join to per_people_f.person_type_id where the
508      -- person_type_id has a system_person_type of either 'EX_EMP' or
509      -- 'EX_EMP_APL'.  Otherwise, we'll get 2 records returned with the same
510      -- person_id as in the following example:
511      --
512      --  PERSON_ID PPF EFF START PPF EFF END PERSON_TYPE_ID
513      --  --------- ------------- ----------- --------------
514      --       2525     27-AUG-99   20-JAN-00 72 (EMP)
515      --       2525     21-JAN-00   05-FEB-00 75 (EX_EMP)
516      --       2525     06-FEB-00   08-FEB-00 72 (EMP, rehired)
517      --       2525     09-FEB-00   31-DEC-12 75 (EX_EMP)
518      --
519      --  We need to compare the ppf.effective_start_date >= date_range_low_end
520      --  and ppf.effective_end_date >= date_range_high_end (this is NOT a
521      --  mistake as you can see from the 4th record in the above that the
522      --  person record for an EX_EMP has the end-of-time in the effective_end
523      --  date), we want to select the latest EX_EMP person record.
524      --
525      --  In R11.5, for assignments, the assignment status type varies depending
526      --  on whether the Actual Termination Date and Final Process Date are the
527      --  same or not.
528      --  If the Actual Termination Date and Final Process Date are the same
529      --  same,then no period as TERM_ASSIGN is present in the assignments table.
530      --  If the Actual Termination Date and Final Process Date are different,
531      --  then the assignment has a status of TERM_ASSIGN in the period between
532      --  Actual Termination Date and Final Process Date are.
533      --  For example:
534      --      Date From = 01-Jan-2000
535      --      Date To: 31-May-2000
536      --      Run Type: Inactivate User Account
537      --      Actual Termination Date = 18-Apr-2000
538      --      Final Process Date = 18-Apr-2000
539      --
540      --  1) PER_ALL_ASSIGNMENTS_F:
541      --     select assignment_id, effective_start_date, effective_end_date,
542      --            assignment_status_type_id, assignment_type
543      --     from   per_all_assignments_f
544      --     where  person_id = 3;
545      --
546      --     ASSIGNMENT_ID EFF START EFF END   ASG_STATUS_TYPE_ID ASG_TYPE
547      --     ------------- --------- --------- ------------------ --------
548      --                 2 01-JAN-90 18-APR-00  1 (ACTIVE_ASSIGN) E (employee)
549      --              3432 19-APR-00 31-DEC-12  1 (ACTIVE_ASSIGN) B (benefits)
550      --
551      --  2) PER_PERIODS_OF_SERVICE
552      --     select date_start, actual_termination_date, final_process_date
553      --     from   per_periods_of_service
554      --     where  person_id = 3;
555      --
556      --     DATE_STAR ACTUAL_TE FINAL_PRO
557      --     --------- --------- ---------
558      --     01-JAN-90 18-APR-00 18-APR-00
559      --
560      -- So, there won't be a 'TERM_ASSIGN' status if ACTUAL_TERMINATION_DATE and
561      -- FINAL_PROCESS_DATE are the same.  However, if the FINAL_PROCESS_DATE is
562      -- null or different from the ACTUAL_TERMINATION_DATE, then there will be
563      -- a 'TERM_ASSIGN' status between the period of ACTUAL_TERMINATION_DATE and
564      -- FINAL_PROCESS_DATE.
565      -- Hence, we need to select the assignment record which has an
566      -- effective_end_date = to the ppos.actual_termination_date.  Since there
567      -- can only be 1 record for any given day, we don't need to compare the
568      -- effective_start_date and we don't want to limit the query to
569      -- assignment_status_type_id = 'ACTIVE_ASSIGN' because an employee can
570      -- be in a 'SUSPEND_ASSIGN' status before he got terminated.
571      -- But, we want to select only the primary assignment.
572      --------------------------------------------------------------------------
573   THEN
574      l_basic_sql_clause :=
575         'SELECT  ppf.person_id
576                 ,ppf.effective_start_date
577                 ,ppf.effective_end_date
578                 ,paf.assignment_id
579                 ,paf.effective_start_date
580                 ,paf.effective_end_date
581                 ,MAX(ppos.actual_termination_date) term_date
582          FROM    per_periods_of_service  ppos
583                 ,per_people_f            ppf
584                 ,per_assignments_f       paf
585          WHERE   ppf.person_id = paf.person_id
586          AND     paf.person_id = ppos.person_id
587          AND     ppf.business_group_id + 0 = ' ||
588                  to_char(p_business_group_id) ||
589        ' AND     ppf.effective_end_date BETWEEN to_date(''' ||
590                  l_date_from_char || ''', ''' ||  fnd_date.canonical_mask
591 			  || ''')'||
592        ' AND  to_date(''' ||
593                  l_date_to_char || ''', ''' ||  fnd_date.canonical_mask
594 			  || ''')' ||
595        ' AND     paf.primary_flag = ''Y''';
596 
597      --
598 
599      FOR get_ex_emp_per_type_id_list in lc_get_ex_emp_per_type_id
600      LOOP
601          l_per_type_id_list := l_per_type_id_list ||
602                               get_ex_emp_per_type_id_list.person_type_id || ',';
603      END LOOP;
604      --
605      -- Remove the last comma, -1 in the instr function means to scan from
606      -- right to left for the 1st occurrence of the comma.
607      l_per_type_id_list := substr(l_per_type_id_list, 1,
608                                 instr(l_per_type_id_list, ',', -1, 1) - 1);
609      --
610 
611    l_terminated_ee_matching :=
612        ' AND ppf.person_type_id in (' || l_per_type_id_list || ')' ||
613        ' AND ppos.actual_termination_date = ppf.effective_end_date ' ||
614        ' AND ppos.person_id = ppf.person_id ' ||
615        ' AND ppos.business_group_id + 0 = ' || to_char(p_business_group_id) ||
616        ' AND paf.assignment_type = ''E'' ' || -- 4411293
617        ' AND paf.effective_end_date = ppos.actual_termination_date ' ||
618        ' AND ppos.actual_termination_date = '||
619        ' (select max(actual_termination_date) from '||
620        ' per_periods_of_service b '||
621        ' where b.person_id=ppf.person_id '||
622        ' and business_group_id + 0 = ' || to_char(p_business_group_id) ||
623        ' and ppos.person_id= paf.person_id '||
624        ' and b.actual_termination_date BETWEEN to_date(''' ||
625                  l_date_from_char || ''', ''' ||  fnd_date.canonical_mask
626 			  || ''')'||
627        ' AND  to_date(''' ||
628                  l_date_to_char || ''', ''' ||  fnd_date.canonical_mask
629 			  || ''')' ||
630      ' ) AND ppf.person_id not in( '||
631      ' select a.person_id from per_all_people_f a,'||
632      ' per_periods_of_service b'||
633      ' where a.effective_start_date= b.date_start'||
634      ' and a.person_id=b.person_id'||
635      ' and a.business_group_id = b.business_group_id'||
636      ' and b.actual_termination_date IS NULL '||
637      ' and a.person_type_id in('||
638      ' SELECT person_type_id'||
639      ' FROM per_person_types'||
640      ' WHERE business_group_id = ' || to_char(p_business_group_id) ||
641      ' AND system_person_type = ''EMP'' ' ||
642      ' AND active_flag = ''Y'' ))' ;
643      --
644      l_inactivate_user_sql_clause := l_basic_sql_clause;
645      l_inactivate_user_sql_clause := l_inactivate_user_sql_clause ||
646                                      l_org_matching;
647      --
648      l_group_by_clause := ' GROUP BY ppf.person_id, ppf.effective_start_date' ||
649                           ', ppf.effective_end_date' ||
650                           ', paf.assignment_id, paf.effective_start_date' ||
651                           ', paf.effective_end_date';
652      l_inactivate_user_sql_clause := l_inactivate_user_sql_clause ||
653                                      l_terminated_ee_matching ||
654                                      l_group_by_clause;
655   END IF;
656 --
657   -- Dynamic sql steps:
658   -- ==================
659   -- 1. Open dynamic sql cursor
660   -- 2. Parse dynamic sql
661   -- 3. Bind variables
662   -- 4. Define the returning column
663   -- 5. Execute sql
664   -- 6. Fetch 1 row in buffer
665   -- 7. Get 1 row from buffer
666   -- 8. Close dynamic cursor
667   --
668   l_dynamic_cursor_id := dbms_sql.open_cursor;                        -- Step 1
669 
670   IF upper(p_run_type) = hr_user_acct_utility.g_cr_user_new_hires OR
671      upper(p_run_type) = hr_user_acct_utility.g_cr_n_inact_user OR
672      upper(p_run_type) = hr_user_acct_utility.g_cr_user_all_emp
673   THEN
674      BEGIN
675      hr_utility.set_location('In executing create user dynamic sql..', 35);
676 
677      dbms_sql.parse(l_dynamic_cursor_id, l_sql_clause, dbms_sql.v7); -- Step 2
678      -- ************************************************************************
679      -- NOTE:If we retrieve extra column,need to set the l_index accordingly.
680      -- ************************************************************************
681      --
682      l_index := 1;
683      --
684      -- Define the Person ID column
685      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_temp);
686      --
687      -- Now define Person record Effective Start Date
688      l_index := l_index + 1;
689      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
690      --
691      -- Now define Person record Effective End Date
692      l_index := l_index + 1;
693      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
694      --
695      -- Define the Assignment ID column
696      l_index := l_index + 1;
697      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_temp);
698      --
699      -- Now define Assignment record Effective Start Date
700      l_index := l_index + 1;
701      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
702      --
703      -- Now define Assignment record Effective End Date
704      l_index := l_index + 1;
705      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
706      --
707      -- Now define the Hire Date column
708      l_index := l_index + 1;
709      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
710      --
711      --
712      EXCEPTION
713        WHEN OTHERS THEN
714          null;
715      END;
716      --
717      l_new_user_count := 0;
718      l_rows := dbms_sql.execute(l_dynamic_cursor_id);               -- Step 5
719      --
720      -- Initialize the prev fields before entering the loop
721      l_prev_per_id := null;
722      l_prev_eff_start_date := null;
723      l_prev_eff_end_date := null;
724      l_prev_asg_id := null;
725      l_prev_asg_eff_start_date := null;
726      l_prev_asg_eff_end_date := null;
727      l_prev_hire_date := null;
728 
729      WHILE dbms_sql.fetch_rows(l_dynamic_cursor_id) > 0 LOOP         -- Step 6
730        dbms_sql.column_value(l_dynamic_cursor_id, 1, l_person_id);
731        dbms_sql.column_value(l_dynamic_cursor_id, 2, l_effective_start_date);
732        dbms_sql.column_value(l_dynamic_cursor_id, 3, l_effective_end_date);
733        dbms_sql.column_value(l_dynamic_cursor_id, 4, l_asg_id);
734        dbms_sql.column_value(l_dynamic_cursor_id, 5, l_asg_eff_start_date);
735        dbms_sql.column_value(l_dynamic_cursor_id, 6, l_asg_eff_end_date);
736        dbms_sql.column_value(l_dynamic_cursor_id, 7, l_hire_date);
737        --
738        -- We only want to create the batch header when there is record retreived
739        -- from the dynamic sql statement.  Otherwise, we won't create a header.
740        IF l_batch_id IS NOT NULL
741        THEN
742           null;
743        ELSE
744           l_batch_id := hr_pump_utils.create_batch_header
745                           (p_batch_name          => p_batch_name
746                           ,p_business_group_name => l_bg_name);
747        END IF;
748        --
749        -----------------------------------------------------------------------
750        -- NOTE:
751        --    Business Group Id is derived from the business group name saved in
752        --    the hrdpp_pump_batch_headers table.  We do not need to pass
753        --    p_business_group_id when inserting to batch lines record.
754        -----------------------------------------------------------------------
755 
756        -----------------------------------------------------------------------
757        -- NOTE:
758        --  Need to compare the current extracted record with the previous
759        --  one to prevent 1 person being written twice to hr_pump_batch_lines
760        --  due to a future dated assignment changes.
761        --  For example:
762        --   Run Type = Create and Inactivate User Accounts
763        --   Date From = 01-Jan-1999
764        --   Date To = 08-May-2000
765        --   Organization Hierarchy = XXXX Org Hierarchy
766        --   Parent Organization = Marketing
767        --   Organization ID covered in the hierarchy = 2,3,4,1025, 1026, 1027
768        --
769        --   Extracted records in hr_pump_batch_lines are:
770        --
771        --  PerID Per Start  Per End    Hire Dt    Asg ID Asg Start  Asg End
772        --  ----- ---------- ---------- ---------- ------ ---------- ---------
773        --  1182  2000/03/29 4712/12/31 2000/03/29 1222   2000/04/27 2000/10/26
774        --  1182  2000/03/29 4712/12/31 2000/03/29 1222   2000/10/27 4712/12/31
775        --
776        --  The person and assignment info. are as follows:
777        --                            Per  ASG                       ORG ASG
778        --  PerID Per Start Per End   Type ID    Asg Start Asg End   ID  Stat
779        --  ----- --------- --------- ---- ----- --------- --------- --- ----
780        --  1182  29-MAR-00 31-DEC-12 26   1222  29-MAR-00 26-APR-00 4   1
781        --  1182  29-MAR-00 31-DEC-12 26   1222  27-APR-00 31-DEC-12 4   1
782        --
783        --  From the above record information, two batch line records were
784        --  written due to a future dated assignment change.
785        --  Hence, we need to eliminate the 2nd extracted rec if the person_id,
786        --  person effective_start_date, person effective_end_date and person
787        --  type id are the same but only the assignment effective date are
788        --  different.
789        --
790        -----------------------------------------------------------------------
791        --
792        IF l_person_id = l_prev_per_id AND
793           l_effective_start_date = l_prev_eff_start_date AND
794           l_effective_end_date = l_prev_eff_end_date AND
795           l_asg_id = l_prev_asg_id
796        THEN
797           -- future dated assignment change exists, do not include this record
798           goto create_next;
799        END IF;
800        -- Fix 3332698.
801         l_unique_str := g_dp_ins_str || l_person_id || '_' || l_batch_id;
802 
803         hr_pump_utils.add_user_key(
804                                  p_user_key_value  =>l_unique_str
805                                  ,p_unique_key_id  =>l_person_id
806                                   );
807 
808        -- not the same person, write this to the batch record
809        hrdpp_create_user_acct.insert_batch_lines
810          (p_batch_id              => l_batch_id
811          ,p_user_sequence         => null
812          ,p_link_value            => null
813          ,p_person_user_key       => l_unique_str
814          ,p_date_from             => l_date_from
815          ,p_date_to               => l_date_to
816          ,p_org_structure_id      => p_organization_structure_id
817          ,p_org_structure_vers_id => p_org_structure_version_id
818          ,p_parent_org_id         => p_parent_org_id
819          ,p_single_org_id         => p_single_org_id
820          ,p_run_type              => p_run_type
821          ,p_per_effective_start_date  => l_effective_start_date
822          ,p_per_effective_end_date    => l_effective_end_date
823          ,p_assignment_id         => l_asg_id
824          ,p_asg_effective_start_date  => l_asg_eff_start_date
825          ,p_asg_effective_end_date    => l_asg_eff_end_date
826          ,p_hire_date             => l_hire_date);
827 
828        -- Increment the count
829        l_new_user_count := l_new_user_count + 1;
830 
831        l_commit_count := l_commit_count + 1;
832        IF l_commit_count = g_commit_limit
833        THEN
834           -- commit after so many employees
835           commit;
836           l_commit_count := 0;
837        END IF;
838 
839        -- Move the current record to previous record
840        l_prev_per_id := l_person_id;
841        l_prev_eff_start_date := l_effective_start_date;
842        l_prev_eff_end_date := l_effective_end_date;
843        l_prev_asg_id := l_asg_id;
844        l_prev_asg_eff_start_date := l_asg_eff_start_date;
845        l_prev_asg_eff_end_date := l_asg_eff_end_date;
846        l_prev_hire_date := l_hire_date;
847 
848        <<create_next>>
849        null;
850 
851      END LOOP;
852   END IF;
853 
854   IF upper(p_run_type) = hr_user_acct_utility.g_cr_n_inact_user OR
855      upper(p_run_type) = hr_user_acct_utility.g_inactivate_user
856   THEN
857      l_dynamic_cursor_id := 0;
858      l_dynamic_cursor_id := dbms_sql.open_cursor;                  -- Step 1
859 
860      BEGIN
861 
862      hr_utility.set_location('In executing inactivate user dynamic sql..', 37);
863 
864      dbms_sql.parse(l_dynamic_cursor_id, l_inactivate_user_sql_clause
865                    ,dbms_sql.v7);                                   -- Step 2
866      -- ************************************************************************
867      -- NOTE:If we retrieve extra column,need to set the l_index accordingly.
868      -- ************************************************************************
869      --
870      l_index := 1;
871      --
872      -- Define the Person Id column
873      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_temp);
874      --
875      -- Now define Person record Effective Start Date
876      l_index := l_index + 1;
877      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
878      --
879      -- Now define Person record Effective End Date
880      l_index := l_index + 1;
881      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
882      --
883      -- Define the Assignment Id column
884      l_index := l_index + 1;
885      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_temp);
886      --
887      -- Now define Assignment record Effective Start Date
888      l_index := l_index + 1;
889      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
890      --
891      -- Now define Assignment record Effective End Date
892      l_index := l_index + 1;
893      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
894      --
895      -- Now define the Term Date column
896      l_index := l_index + 1;
897      dbms_sql.define_column(l_dynamic_cursor_id, l_index, l_date_temp);
898      --
899      EXCEPTION
900        WHEN OTHERS THEN
901          null;
902      END;
903      --
904      l_inactivate_user_count := 0;
905      l_rows := dbms_sql.execute(l_dynamic_cursor_id);               -- Step 5
906      --
907      WHILE dbms_sql.fetch_rows(l_dynamic_cursor_id) > 0 LOOP         -- Step 6
908        dbms_sql.column_value(l_dynamic_cursor_id, 1, l_person_id);
909        dbms_sql.column_value(l_dynamic_cursor_id, 2, l_effective_start_date);
910        dbms_sql.column_value(l_dynamic_cursor_id, 3, l_effective_end_date);
911        dbms_sql.column_value(l_dynamic_cursor_id, 4, l_asg_id);
912        dbms_sql.column_value(l_dynamic_cursor_id, 5, l_asg_eff_start_date);
913        dbms_sql.column_value(l_dynamic_cursor_id, 6, l_asg_eff_end_date);
914        dbms_sql.column_value(l_dynamic_cursor_id, 7, l_term_date);
915        --
916        -- We only want to create the batch header when there is record retreived
917        -- from the dynamic sql statement.  Otherwise, we won't create a header.
918        IF l_batch_id IS NOT NULL
919        THEN
920           null;
921        ELSE
922           l_batch_id := hr_pump_utils.create_batch_header
923                           (p_batch_name          => p_batch_name
924                           ,p_business_group_name => l_bg_name);
925        END IF;
926        --
927        -----------------------------------------------------------------------
928        -- NOTE:
929        --    Business Group Id is derived from the business group name saved in
930        --    the hrdpp_pump_batch_headers table.  We do not need to pass
931        --    p_business_group_id when inserting to batch lines record.
932        -----------------------------------------------------------------------
933        -- Do the prev fields check for the same reason in create_user
934        -- above.
935        IF l_person_id = l_prev_per_id AND
936           l_effective_start_date = l_prev_eff_start_date AND
937           l_effective_end_date = l_prev_eff_end_date AND
938           l_asg_id = l_prev_asg_id
939        THEN
940           -- future dated assignment change exists, do not include this record
941           goto update_next;
942        END IF;
943         -- Fix 3332698.
944         l_unique_str := g_dp_upd_str || l_person_id || '_' || l_batch_id;
945 
946         hr_pump_utils.add_user_key(
947                                 p_user_key_value  =>l_unique_str
948                                 ,p_unique_key_id  =>l_person_id
949                                  );
950 
951        hrdpp_update_user_acct.insert_batch_lines
952          (p_batch_id              => l_batch_id
953          ,p_user_sequence         => null
954          ,p_link_value            => null
955          ,p_person_user_key       => l_unique_str
956          ,p_date_from             => l_date_from
957          ,p_date_to               => l_date_to
958          ,p_org_structure_id      => p_organization_structure_id
959          ,p_org_structure_vers_id => p_org_structure_version_id
960          ,p_parent_org_id         => p_parent_org_id
961          ,p_single_org_id         => p_single_org_id
962          ,p_run_type              => p_run_type
963          ,p_per_effective_start_date  => l_effective_start_date
964          ,p_per_effective_end_date    => l_effective_end_date
965          ,p_assignment_id         => l_asg_id
966          ,p_asg_effective_start_date  => l_asg_eff_start_date
967          ,p_asg_effective_end_date    => l_asg_eff_end_date
968          ,p_inactivate_date       => l_term_date);
969 
970        -- Increment the counter
971        l_inactivate_user_count := l_inactivate_user_count + 1;
972 
973        -- Move the current record to previous record
974        l_prev_per_id := l_person_id;
975        l_prev_eff_start_date := l_effective_start_date;
976        l_prev_eff_end_date := l_effective_end_date;
977        l_prev_asg_id := l_asg_id;
978        l_prev_asg_eff_start_date := l_asg_eff_start_date;
979        l_prev_asg_eff_end_date := l_asg_eff_end_date;
980        l_prev_term_date := l_term_date;
981 
982        <<update_next>>
983        null;
984 
985      END LOOP;
986   END IF;
987 --
988 
989   IF p_run_type = hr_user_acct_utility.g_cr_user_new_hires OR
990      p_run_type = hr_user_acct_utility.g_cr_user_all_emp
991   THEN
992      fnd_message.set_name('PER', 'HR_CREATE_USER_ACCT_COUNT');
993      l_msg := fnd_message.get || to_char(l_new_user_count);
994      fnd_file.put_line(FND_FILE.LOG, l_msg);
995   ELSIF p_run_type = hr_user_acct_utility.g_inactivate_user
996   THEN
997      fnd_message.set_name('PER','HR_INACTIVATE_USER_ACCT_COUNT');
998      l_msg := fnd_message.get || to_char(l_inactivate_user_count);
999      fnd_file.put_line(FND_FILE.LOG, l_msg);
1000   ELSIF p_run_type = hr_user_acct_utility.g_cr_n_inact_user
1001   THEN
1002      -- Now print the create user account count
1003      fnd_message.set_name('PER', 'HR_CREATE_USER_ACCT_COUNT');
1004      l_msg := fnd_message.get || to_char(l_new_user_count);
1005      fnd_file.put_line(FND_FILE.LOG, l_msg);
1006 
1007      -- Now print the inactivate user account count
1008      fnd_message.set_name('PER','HR_INACTIVATE_USER_ACCT_COUNT');
1009      l_msg := fnd_message.get || to_char(l_inactivate_user_count);
1010      fnd_file.put_line(FND_FILE.LOG, l_msg);
1011   END IF;
1012 --
1013   retcode := 0;
1014 
1015   hr_utility.set_location('Leaving ' || l_proc, 10);
1016 
1017   return;
1018 --
1019   EXCEPTION
1020     WHEN OTHERS THEN
1021       hr_utility.trace ('Error in the '|| l_proc ||' - ORA '||
1022                         to_char(SQLCODE));
1023       errbuf := sqlerrm;
1024       retcode := 2;
1025       rollback;
1026 --
1027 END run_process;
1028 --
1029 --
1030 END HR_USER_ACCT_EMP_EXTRACT;