Monday, August 25, 2008

Checklist -- Requirements of Client

Few of the clarifications needed for setup data (HCM) :
I will keep adding more list items as and when found..
  1. understand the number of and values of SETIDs and BUs
  2. no.of companies
  3. no. of countries
  4. is it a multi lingual implementation?
  5. aprroval hierarchy
  6. when managers are in LOA, what will be the route for approvals
  7. security
  8. portal changes needed? (like Logo, header level changes, etc)
  9. current no.of employees in the organisation (can be an estimated value)
  10. third party/ vendors

Wednesday, August 20, 2008

Inserting files in Database record from a folder in appserver..

Requirement:

This is a part of data migration requirement. There is a folder in appserver which contains all CVs of applicants. These have to be inserted into database tables which store applicants' resumae. This should be a job like an App Engine.

Note: As per the specifications, one CV per applicant is given by the client.



Technical Design:

1) Initailly identify the tables which store appl CVs -- HRS_APP_RES

2) Create an AE with one section having a PeopleCode.

3) The folder path on appserver has to be identified.

4) The design needs two things --


  • First loop through the Folder containing CVs

  • Insert each file into the table

5) Here the CV files naming convention that is suggested as ApplicantID.doc. This makes the job easy in mapping the CVs against the applicants.


6) The peoplecode in the peoplecode event is as follows. This is very much reusable.


Local array of string &FNAMES;

Local File &MYFILE;

Local string &CurrFile;

Local Record &REC_RES_UPLD = CreateRecord(Record.ICI_RES_UPLD);

Local Record &REC_HRS_RES = CreateRecord(Record.HRS_APP_RES);
&pwd = "
file://xyz.xyz.com/PQRS/ABCD/appserv/ASDFDEV/files/CV/";

&FNAMES = FindFiles(&pwd "*.doc", %FilePath_Absolute);

If &FNAMES.Len = 0 Then

/* No files in this directory - this must be a file instead */

MessageBox(0, "", 0, 0, "NO FILES IN THE DIRECTORY");

Else

&NEXT_RESUME_ID = GetNextNumberWithGapsCommit(HRS_APP_RES.HRS_RESUME_ID, 2147483647, 1);

&FILEEXTENSION = ".doc";

While &FNAMES.Len > 0

&CurrFile = &FNAMES.Shift();

&POS1 = Find("CV\", &CurrFile) + 3;

rem &POS2 = Find(".doc", &CurrFile) + 3;

&POS2 = Find(".doc", &CurrFile);

rem &applicant_id = substring(&CurrFile,&POS1,&POS2-&POS1+1);

&applicant_id = Substring(&CurrFile, &POS1, &POS2 - &POS1);

MessageBox(0, "", 0, 0, "EACH FILE NAME = " &CurrFile);

MessageBox(0, "", 0, 0, "EACH APPLICANT ID = " &applicant_id); &ATTACHSYSFILENAME = &applicant_id ".doc";

&ATTACHUSERFILE = &ATTACHSYSFILENAME;

&RETCODE = PutAttachment("record://ICI_RES_DOC_STR", &ATTACHSYSFILENAME, &CurrFile);

If &RETCODE = 0 Then

MessageBox(0, "", 0, 0, "File " &ATTACHSYSFILENAME " is inserted successfully.");

Else

MessageBox(0, "", 0, 0, "File " &ATTACHSYSFILENAME " is NOT inserted.");

End-If;

&REC_RES_UPLD.HRS_PERSON_ID.Value = &applicant_id; &REC_RES_UPLD.HRS_RESUME_ID.Value = &NEXT_RESUME_ID; &REC_RES_UPLD.ATTACHSYSFILENAME.Value = &ATTACHSYSFILENAME; &REC_RES_UPLD.ATTACHUSERFILE.Value = &ATTACHUSERFILE; &REC_RES_UPLD.Insert();


&REC_HRS_RES.HRS_PERSON_ID.Value = &applicant_id; &REC_HRS_RES.HRS_RESUME_ID.Value = &NEXT_RESUME_ID; &REC_HRS_RES.HRS_RESUME_TITLE.Value = "TEST"; &REC_HRS_RES.LANG_CD.Value = "ENG"; &REC_HRS_RES.ATTACHSYSFILENAME.Value = &ATTACHSYSFILENAME; &REC_HRS_RES.ATTACHUSERFILE.Value = &ATTACHUSERFILE; &REC_HRS_RES.HRS_ROW_ADD_DTTM.Value = %Datetime; &REC_HRS_RES.HRS_ROW_ADD_OPRID.Value = "PS"; &REC_HRS_RES.HRS_ROW_UPD_DTTM.Value = %Datetime; &REC_HRS_RES.HRS_ROW_UPD_OPRID.Value = "PS";

&REC_HRS_RES.Insert();

&NEXT_RESUME_ID = &NEXT_RESUME_ID + 1;

rem SQLExec("COMMIT");

End-While;

End-If;


Wednesday, August 6, 2008

Transactions which need approval -- Technical Design

Requirement:
A simple process is needed which allows employee to make a transaction with options of saving for later and submitting the transaction. This triggers a notification to next level for approval, say his supervisor. The supervisor should be able to approve/deny this transaction. It may have another level of approval which we don't discuss now..

Solution approach:
You can use an Application Workflow Engine(AWE) for this. But understanding and effort needed for this is slightly high. So let us look at the process which does not use an AWE.
One important Point: Understand what should happen when the employee 'Saves' the transaction and when he/she 'Submits' the transaction.
The following is the design technique.

1. Designing the records: First understand the transaction -- if it has to have child levels as well -- and design the tables accordingly -- Believe me this is very very important.. Designing the tables is very crucial. If the tables are not normalised, it definitely leads to rework later.
a) If Saving the transactions demands to store data in some intermediate SQL tables, then define them and expose those tables in the page.
b) Also try to have a field in level zero record which acts as flag for 'Save' or 'Submit' action. You can assign the flag field value accordingly when save button is clicked or submit button is clicked is its field change (preferably in component-record-field level Field change). This flag can be used in Search record views for filtering the data.
c) Have a status translate field in Level Zero record to track the transaction statuses like 'Saved by Employee', 'Submitted by Employee', 'Approved by Manager', 'Rejected by Manager', etc...

2. Designing Components: If it is one level approval, then there are two ways of doing it..
a) You will need two components with two search records -- one for employee and one for approving authority and make reuse of the page which u have created for employee and hide the approve/deny buttons or rename the lables accordingly for both the users. You will keep one component in Self Service and give access to Employees and other in Manager Self Service(MSS) and give permissions of manager.
b) You may reuse both page and component, and add the same component to Self Service as well as MSS menus with different search records defined at menu level.

If we look at second approach, whenever we have to add peoplecode at component/component-rec-field/component-rec levels, we always have to use conditions like
Evaluate %menu
when = "ROLE_EMPLOYEE"
.....
break;
when = "ROLE_MANAGER"
.....
break;
.....
end-evaluate;

So every validation that is put, will have to be in the above conditions.
So make a choice between the above.. I prefer the first method. Though it has a n extra component, it avoids hard-coding of menu names.

Also decide if delivered Saving process is needed or you have your own customised Save button. Because this requirement demands Save and Submit processes, it makes sense to have a cutomised Save as well as Submit buttons.

Modes of component(s):
Self Service component should have Add as well as Update /Display modes -- mandatory (other modes are optional)
Manager Self Service component should be in any of Update modes but only not in Add mode.

3. Search Records: The next step will be properly defining the search records. Again very important as this determines data security.
  • For the Self Service component, we can have a view on Level Zero record such that the employee picked up by the view will be %employeeid or u can some times have Level Zero table itself as the search record. But now we have Save button also for employee, it is better to have Level Zero record as Add Search Record and a view which shows Saved transactions and Approved/Denied transactions as Search Record.
  • For the MSS component, the search record should definitely be a view (makes life easy). This view can have the level zero table as well as a filter on the status like submitted ones only (not saved ones), or don't include approved and(or) rejected transactions, etc.

4. Validations/Considerations: The most common validations might be --

  • In the Post Build event of SelfService component -- Dont forget to add the statement -- AllowEmplidChng(); [Refer PeopleBooks]
  • In page activate if you have some code to hide/unhide some page controls then dont forget to write it in an 'If' condition for component (i.e. if %component = "...." then ... ) because same page is exposed in both the component.
  • Logically speaking -- after employee Submits a transaction (i.e. after he/she clicks the 'Submit' button) the entire page should be in display only(disabled) mode. So that the submitted transaction is not allowed to modify. For this, the best way is to use 'Transfer' function and transfer back to the current page with proper key values. This piece of code can be written in fieldchange (component-rec-field level) of the Submit button field.
  • You can reuse the same Save and Submit button fields as Approve and Deny buttons. All that you need is to change the label name in may be Post build event. [Refer field class properties/methods in PeopleBooks]
  • In the search mode for an employee, if you are showing Submitted/Approved/Denied transactions, make sure that you write make the page Display only in Post Build event of the component. [Ex. If Flag = "X" then GetPage(Page.XXXXX).Displayonly = true; ..........]
  • Dont forget to change the status field using code or allow the user to change the status according to his/her role.
  • Code to trigger email notifications should be written at component-rec-field level field change or in workflow events of the component. If there is no delivered Save button, then make sure you trigger the workflow event (by using DoSave() or DoSaveNow() functions).

5.Email Notifications: The Email notifications might have to be sent to approving authorities and employee also. This can be achieved by using WorkfFlows or by calling an application package with a mail template defined. This part is discussed in detail in the blog 'Different ways of trigerring Notifications'.