Peoplesoft HCM (HR, BA, PR, and TL) comes with at least 1300 run control records, yet my organization has added 2% more over the past ten years.  We’re not running out of table space or disk space, but we probably did more work than we needed; creating new records, tables, and pages.  For that matter, Oracle probably did more work than they needed, not reusing their run control objects.

Run Control Objects

The Peoplesoft Process Scheduler uses a process definition to run any batch program, including SQR programs.  To let Peoplesoft users run programs on demand, we need to give them a “Run” button.  The second easiest way to do that is to put a Peoplesoft-delivered subpage (subpanel) on our page.  (The easiest way to do that is to use a Peoplesoft-delivered run control page.)

The PRCSRUNCNTL_SBP and similar subpages contain the PRCSRQSTDLG_WRK record.  That record includes the LOADPRCSRQSTDLGPB field, which appears as a button.  Its FieldChange Peoplecode calls the LaunchProcessRequestDlg function in its FieldFormula Peoplecode.  That function calls the LaunchAndRunProcessRequest function in the same Peoplecode program, which loads the familiar secondary page PRCSRQSTDLG to let the user run the process.

If our SQR program doesn’t need user inputs (see Batch User Interfaces), we can use a run control page with a subpage like PRCSRUNCNTL_SBP and nothing further, like PRCSRUNCNTL.  If our program does need inputs, we might find an existing run control record and page to meet our needs (see below), or we may need to create a page and possibly a record.

Our program might be so similar, or complementary to, an existing program that it can share run control record, page, and even component.  In this case, we can specify the component in our process definition and piggyback on the existing facility.  We can use the “process groups” parameter in the process definition to control who sees each batch process that shares the same component.

If our program should have a separate menu item, we create a component for our new or reused page and register it in the portal.

While preparing for our Peoplesoft 8.9 upgrade in 2006, I noticed that my organization had created a large collection of run control pages.  There were several naming standards, many orphan pages (not included in any component), and many orphan or obsolete page / component sets.  I made three resolutions at that point.

  1. To check with my colleagues, and then to delete unnecessary Peopletools objects.  We budgeted the upgrade project based on the number of custom and customized objects.  Although it takes no effort or expense to carry forward a run control page, once the money is budgeted, it will be spent.  (It did take some effort to place components in the portal since the menu structure was quite different from version 8.0.)
  2. To adopt a new naming standard.  If my SQR program was PRPAYCHK (print pay check), a dedicated run control page and component would be PRPAYCHK_RC.  It’s easier to inventory run control pages with a standard “where PNLNAME like ‘%RC’” than to have a variety of name styles; RUN_PRPAYCHK, PRPAYCHK_RUN, PRPAYCHK_RUN_CNTL, PRPAYCHK_RUNCNTL, PRINT_PAY_CHECK, etc.
  3. To reuse existing run control pages or to create generic pages that can be reused; GET_EMPLID_RC, GET_ASOFDATE_RC, GET_DATE_RANGE_RC, etc.

Reuse Record and Page

In my blog entry, How To Read Peoplesoft Run Control Parameters In SQR, we saw how to read the run control table without knowing its name.  I developed that approach in order to decouple the Peopletools development from the SQR development and to avoid writing many slight variations of the same begin-select code.

When it is time to select or create a run control record and page, we can keep notes of frequently used candidates; a page with no fields, a page with EMPLID, a page with the payroll RUN_ID, and a few others.  If we’ve got an unusual set of parameters, here’s a tool to help search for possible records and pages to use.

#define false 0
#define true  1

begin-setup
  create-array name=field size=10
    field=name:char=''
    field=type:integer=0
    field=length:integer=0
    field=decimalpos:integer=0
end-setup

begin-program
  do input_fieldnames
  do find_records_that_contain_all_fields
  show $recnames
  do find_pages_that_contain_all_fields
  do finish_program
end-program

begin-procedure input_fieldnames
  while {true}
    input $fieldname 'Enter fieldname'
    if $fieldname = ''
      break
    end-if
    uppercase $fieldname
    do read_psdbfield
  end-while
  move #field_num to #num_fields
end-procedure input_fieldnames

begin-procedure read_psdbfield
  move {true} to #field_not_found
begin-select
FIELDTYPE
LENGTH
DECIMALPOS
  move {false} to #field_not_found
  if $fieldnames <> ''
    concat ',' with $fieldnames
  end-if
  let $fieldnames = $fieldnames || '''' || $fieldname || ''''
  put $fieldname &FIELDTYPE &LENGTH &DECIMALPOS into field(#field_num)
  add 1 to #field_num
 from PSDBFIELD
where FIELDNAME = $fieldname
end-select
  if #field_not_found
    show 'Cannot find ' $fieldname
  end-if
end-procedure read_psdbfield

begin-procedure find_records_that_contain_all_fields
begin-select
RF1.RECNAME
  if $recnames <> ''
    concat ',' with $recnames
  end-if
  let $recnames = $recnames || '''' || &RF1.RECNAME || ''''
 from PSRECFIELD RF1, PSRECFIELD RF2, PSRECFIELD RF3
where RF1.FIELDNAME  = 'OPRID'
  and RF1.FIELDNUM   = 1
  and RF2.RECNAME    = RF1.RECNAME
  and RF2.FIELDNAME  = 'RUN_CNTL_ID'
  and RF2.FIELDNUM   = 2
  and RF3.RECNAME    = RF1.RECNAME
  and RF3.FIELDNAME in ([$fieldnames])
group by RF1.RECNAME
having count(RF3.FIELDNAME) = #num_fields
end-select
end-procedure find_records_that_contain_all_fields

begin-procedure find_pages_that_contain_all_fields
begin-select
PF.PNLNAME
PF.RECNAME
PF.FIELDNAME
  if &PF.PNLNAME <> $prev_pnlname
    if $prev_pnlname <> ''
      let $prev_pnlname = rpad($prev_pnlname, 18, ' ')
      show $prev_pnlname ' wanted: ' #num_wanted_fields edit 99 ' unwanted: ' #num_unwanted_fields edit 99
    end-if
    move 0 to #num_wanted_fields
    move 0 to #num_unwanted_fields
    move &PF.PNLNAME to $prev_pnlname
  end-if
  if  instr($recnames,   '''' || &PF.RECNAME   || '''', 1)
  and instr($fieldnames, '''' || &PF.FIELDNAME || '''', 1)
    add 1 to #num_wanted_fields
  else
    add 1 to #num_unwanted_fields
  end-if
 from PSPNLFIELD PF
where exists (select 1
                from PSPNLFIELD
               where PNLNAME    = PF.PNLNAME
                 and RECNAME   in ([$recnames])
                 and FIELDNAME in ([$fieldnames]))
                 and PF.FIELDNAME <> ' '
order by PF.PNLNAME
end-select
end-procedure find_pages_that_contain_all_fields

This program is just the foundation of what you could create.  Its user interface is primitive; you give it a list of fields, it gives you a list of records and a list of pages.  Each page has the count of the fields you requested that are on that page and the number of other fields on that page.

Here are some projects for anyone who would like to improve the program.

  • Divide the count of “unwanted” fields into fields of the run control record versus other fields.  If our run control record has EMPLID and we have a related display of NAME from PERSON_DATA, is that really unwanted?
  • Shorten the lists by omitting the worst choices (based on your judgment).
  • (Most Challenging) Use the field type, length, and decimal position to expand our selection of run control records by considering other fields which have the same characteristics as the fields we want.

User Group

Send me an e-mail at steven@peoplesoftsqr.com if you’re interested in the Northern California Regional Peoplesoft & J.D. Edwards Users Group.  We will meet at the Oracle Headquarters in Redwood Shores, California on December 10, 2009.  There will be an informal discussion table for SQR/SQL developers.  I hope to meet you there.