PeopleCode

PeopleCode Events execution order:

1.SearchInit
2.Searchsave
3.RowSelect
4.Prebuild
5.RowInit
6.FieldDefault
7.FieldFormula
8.PostBuild
9.PageActivate
10.FieldEdit
11.FieldChange
12.RowInsert
13.RowDelete
14.SaveEdit
15.SavePrechange
16.WorkFlow
17.SavePostchange

Using PeopleCode Events

This section teaches you about each event, providing examples of use including actual PeopleCode.

SearchInit

The code in the SearchInit event is needed only for records that will be used as search records. If the record definition you have is not used as a search record, then code placed in here will never run. Code placed in this event is typically used to set up default values on the search page. For example, this event is mostly used to set up counters or defaults from the operator preferences on the search panel.

For example:


SetSearchEdit(BUSINESS_UNIT);

SetSearchDefault(BUSINESS_UNIT);

This example turns on edits and system defaults for the Business Unit field in the search page. This code does not cause any other PeopleCode category to activate; it simply sets up the information in the page object to be used in that specific field.

SearchSave


This code also applies to the search page and is typically used to validate the search page to make sure all the required fields are filled in. Because you cannot specify the required fields on a search record (the record definition's required attribute is for use only on the regular pages), you can place code here to do the validation of all the fields that must be filled in.

For example:

If None(BUSINESS_UNIT) Then
Error MsgGet(9000, 3, "Business Unit is a required field.");
End-If;
check_status(BUSINESS_UNIT, PO_ID, &STATUS);
If &STATUS = "C" Or &STATUS = "X" Then
Error MsgGet(10200, 164, "The specified PO exists, and is either Completed or
Cancelled.");
End-If;
check_auto_num(BUSINESS_UNIT, &AUTO_NUM);
If None(&AUTO_NUM) Then
Error MsgGet(10000, 1, "%1 is not a Purchasing business unit.",
BUSINESS_UNIT);
End-If;
If &AUTO_NUM = "N" And PO_ID = "NEXT" Then
Error MsgGet(10200, 34, "This business unit is not set up for purchase order auto numbering.");
End-If;

This example shows a little more about the capability of this event of code. The code here, although complex for now basically checks that certain fields are filled in. If they are filled in, then the data is validated for specific conditions. If an error condition exists, an error message is displayed and the search page is not closed.

RowInit :

Now you have arrived at events that are used more often in development projects. The code in the RowInit event runs every time a new row of data loads into a page. This section activates code for each level and each data row. For example, if you have a panel with a level 1 that has 15 data rows that load, the RowInit event will run 16 times: once for the level 0 (header information) and then 15 times for each row of data
on level 1. You need to understand that even though on the page you can see only five rows of data, this code activates for all rows of data that are loaded into the buffer. So it is not how many rows are visible on the page, but how many rows are loaded into the data buffer that determines how many times this PeopleCode category activates.

Consider the following 3 examples:

If %PanelGroup = PANELGROUP.VCHR_PO_STD Then
If All(PO_ID) Then
VCHR_PANELS_WRK.TXN_CURRENCY_SRC = "P";
End-If;
End-If;
If INSTALLATION.PO = "Y" Then
DERIVED.EDITTABLE13 = "ITM_PURCH_FS";
End-If;
Gray(LINE_NBR);
Gray(SCHED_NBR);
Gray(BUSINESS_UNIT_RECV);

These examples show different ways to use the RowInit event that are typically done. The first example shows, based on some information, that you can set some values into special fields. The second example shows that you can also set or change the prompts used. Finally, the third example shows how you can override the settings on the page to hide, gray (display-only), unhide, or ungray (not display-only) fields based on the initialization.

FieldDefault :


In this event, field defaults can be coded. This event works only to set defaults into fields where the logic is too complex to use the record definition. If, by contrast, you have a hard default that is always to be used, then you should set that value in the record definition. Otherwise, you can set the default based on a condition check of some other field or value using code from the FieldDefault event.

For example:

If None(ITM_SETID) Then ITM_SETID = GetSetId("BUSINESS_UNIT",
BUSINESS_UNIT, "MASTER_ITEM_TBL", ""); End-If;

This example checks whether the ITM_SETID field is filled in. If the field is not filled in, then the code runs a function to get the information and place it in this field.

FieldChange :

The FieldChange event occurs under two circumstances: once when a field is changed, and the other when a button is pressed. For the field change event, the code does not execute unless there is a net change (changing the value of a field to it's original value is not a net change) and the user moves out of the field or saves the page. Here you can do very complex validation upon the field.

Example: If VENDOR_ITM_VW1.ITM_STATUS = "A" Then If PRICE_DT_TYPE
= "P" And QTY_TYPE = "L"

Then check_line(); Else check_schedules(); End-If;
This example checks the values in a couple of fields and then, based on their settings,runs a different function. In the FieldChange event, you are not limited to using only the field from which the code is launched, but rather, you can access any field on the page as is shown in this example. You can also use the FieldChange event when you have a button on a panel; here you would place the code that you wish to activate when the button is pressed. The code you place for a button can be just about anything you want. This is what makes button actions so powerful—they can perform all sorts of actions, controls, and verifications. When you have a button and it is pressed, you are usually looking for some action to take place: jump to another panel, fill in the current panel with data based on some criteria you have set, or run a process,

for example.

UnhideScroll(RECORD.PO_LINE);
UnGray(GOTO_LINE_DTLS);
SEL_LINE_FLG = "Y";
LINES_SAVED = "N";
&WHERE = "where BUSINESS_UNIT = :1 and PO_ID = :2 and LINE_NBR >= :3";
If All(LINE_NBR_TO) Then
&WHERE = &WHERE | " and LINE_NBR <= :4";
End-If;
ScrollFlush(RECORD.PO_LINE);
ScrollSelect(1, RECORD.PO_LINE, RECORD.PO_LINE, &WHERE,
PO_HDR.BUSINESS_UNIT, PO_HDR.PO_ID, LINE_NBR_FROM,
LINE_NBR_TO, True);

This example is from a button which, when pressed, is going to fill in data based on some criteria. The scroll,on level 1 in the panel, is un-hidden (now visible on the panel), and the data buffer is emptied for this scroll (scroll flush). Finally, the scroll's data buffer is filled with data based on a selection criterion.

FieldEdit:


  1. Used to validate contents of a field
  2. Issue Error or Warning messages
  3. Can be associated with Record Fields or Component Record Fields


If None(PO_HDR.VENDOR_ID) Then
Error MsgGet(10200, 76, "Vendor %1 is not set up for item %2.",
PO_HDR.VENDOR_ID, INV_ITEM_ID);
End-if;

FieldFormula:

This event is typically reserved for custom-built functions. You have already learned about the flow of how PeopleCode activates from the PeopleSoft Panel Processor and that the process FieldFormula runs for all sorts of actions. You should not place any code in this category except custom-built functions.

Consider the following example:

Function update_sched() &CHANGED_SCHED = "N";
UpdateValue(LINE_NBR, &LINE, PO_LINE_SHIP.UNIT_PRC_TOL, &SCHED,
&UNIT_PRC_TOL);
UpdateValue(LINE_NBR, &LINE, PO_LINE_SHIP.PCT_UNIT_PRC_TOL,
&SCHED, &PCT_UNIT_PRC_TOL); End-Function;

This example shows a function that performs some actions. A function can take in multiple values and even send back values to the calling program. This enables you to write business logic into functions that many programs can call so that you do nothave to write the logic over and over in multiple PeopleCode categories. This is important to PeopleCode 8.1 in that you now have the ability to place code in new places. By having more places—pages and components—in which to load PeopleCode, you need to remember that you may require the same code in multiple places or categories. Instead of copying the code into all these different places and events, you can create the one function and then call it from the other places, thereby having your logic in only one place. Due to this added complexity, you will need to think more in terms of functions when writing code. Writing more functions that you place into this event will save you time and effort in the long run.

RowSelect:

This event is used to filter data loaded into a scroll level. This is an advancedtechnique that will not be covered in this book. Most developers who want to restrict rows of data create a view to use on the page with the restriction in the SQL where clause. By using this event, you can apply this restriction as you need to or you can even change the criteria as the page is being created.

RowDelete:

This event is used to activate code when a delete is performed for a row of data rather than for only a single field. This delete can be on any level. The developer, when using this code even, can control whether a row of data can be deleted by checking for orphaned records or other required validations. The purpose of this code is to prevent deletes unless a specific criterion has been met.
The process to show the pass or fail of the event is just like in the FieldEdit event. If you failed the validation, pass a message. If you do not issue any messages, then the delete process has passed the validation. This category can also use the warning and error message commands: An error always fails; a warning reports an issue to the user.

If VOUCHER.POST_STATUS_AP = "P" Then Error MsgGet(7030, 109, "You
cannot delete a voucher line if the voucher has been posted."); End-If;
The code here checks a field for a specific status. If a certain status is set, then the code prevents the deletion by issuing an error message. If the status is not set, the code will allow the deletion by not issuing any error or warning message.

RowInsert:

In the RowInsert event, you apply code to inserts of new data rows. Data, when loaded into the page, is validated through the RowInit event, but when you add a new record (level 0) or a new row of information (level 1 through 3), there is no RowInit to activate because it was not initiated into the panel. The RowInsert can and should perform the up-front validations that you would have placed in RowInit for new data rows being added.
Note As you can see, you might need to place the same code in the RowInit and RowInsert categories. This is another reason for looking at code that you could place into functions so that you do not end up copying the same code into multiple categories.

If VCHR_PANELS_WRK.FULL_SET_FLG = "Y" Then
MERCHANDISE_AMT = VCHR_PANELS_WRK.VCHR_BALANCE_AMT;
VCHR_PANELS_WRK.LN_BALANCE_AMT = MERCHANDISE_AMT;
End-If;

This code checks a work record field for a specific status and then updates some fields using information in some other work record fields. The process done here can be just about anything you think of, from graying (display only) and hiding fields to doing complex logic for recalculating a total.

SaveEdit:

In the SaveEdit event, you place code that validates on a save. This is used for the final validation of the record. Usually, you can do a lot of this validation in the FieldEdit event, but you might want the user to do all the input they can and then do a check just prior to the save. You might also have to validate multiple fields as a unit. It is hard to do this within FieldEdit, so you can place the overall validation in this
event instead. A final use for the SaveEdit event occurs when the user does not tab through every field so the FieldEdit code never activates. If you still need this validation, you will have to add it to SaveEdit to be sure that the code does run. As with the other edit events, you can prevent or just warn on a save when the
validation is incorrect. If you prevent, then the user is unable to save the panel. If you warn, then the user can stop the save process and edit the problem or they can continue. The process is the same regardless of whether you're using warning or error messages. Of course, no message means that you have passed the SaveEdit validation.

If DISTRIB_MTHD_FLG = "Q" And None(QTY_VCHR) Then
Error MsgGet(7030, 49, "You must enter either a quantity on Voucher Line %1 when
distributing by quantity. Or you can delete the line.", VOUCHER_LINE_NUM);
Else
If None(MERCHANDISE_AMT) Then
Error MsgGet(7030, 49, "You must enter either a merchandise amount on Voucher
Line %1 when distributing by amount. Or you can delete the line.",
VOUCHER_LINE_NUM);
End-If;
End-If

This code checks some values in the fields and then, if certain conditions exist, an error message is issued, preventing the save of this panel.

SavePreChange:

  1. Executes when SaveEdit completes without any error
  2. Can be used to manipulate data before the system updates the database (i.e. before COMMIT)
  3. Can be associated with Record Fields or Components or Component Records
For &BUFFER_ROW = 1 To &CURRENT_ROW
UpdateValue(VOUCHER_ID, CurrentRowNumber(), DISTRIB_LINE.DESCR,
&BUFFER_ROW, DESCR);
End-For;

This code loops through all the rows of a level 1 panel and updates a value in a lowerlevel
scroll (level 2).

SavePostChange:

In the SavePostChange event, you add code that you want to activate after the rows of data have been saved to the database. Code placed here could be line totals and other calculated fields. This is also where a lot of SQL execs are written and performed to update other necessary fields.

If %Mode = "A" and VENDOR.VENDOR_PERSISTENCE = "O" Then
&SETID = GetSetId("BUSINESS_UNIT", BUSINESS_UNIT, "VENDOR", "");
SQLExec("Update ps_vendor set VENDOR_STATUS = 'I' where setid = :1 and
vendor_id = :2", &SETID, VENDOR_ID)
End-If;

This code example shows that if the page is in Add mode and the vendor is set to a special persistence, then the vendor status must be set back to inactive so that no further POs can be used. This process is used on vendors that are set to one time use only. After you use them on a PO , the status is set to inactive so that you do not use them again. You can see in this example how you are updating the vendor based on an action in the PO system.

Workflow:

  1. Fires immediately after SavePreChange and before the database update
  2. Segregates Workflow related peoplecode from the rest of the application’s peoplecode
  3. Can be associated with Record Fields or Components

PreBuild

The PreBuild event is specific to the component; this code runs prior to the component being built. This is typically used to hide, unhide, gray, or ungray fields, or to set certain values in the component. PeopleCode within the component record gives you an opportunity to set variables that can be used later by PeopleCode located in other events. PreBuild can also be used to validate data in the search page just as is done in the SearchSave event. This event runs right after the RowSelect event within the flow of PeopleCode.

PostBuild

The PostBuild event is specific to the component; this code runs after the component is built. This is usually used to hide, unhide, gray, or ungray fields, or to set certain values in the component. The event can be thought of just like the RowInit event as the data is already loaded into the component. This even runs right after the RowInit even in the PeopleCode flow.

No comments: