Saturday, 23 January 2016

Mail Level Approval Process

Direct Mail Approval is the trending process as we dont need to go back to application and then moving to approval process.
Steps involved in following process are:
Step:1:  Create application with authentication scheme as “No Authentication”. Also create a 
process for updation with point as before header. Updation process should be done with values 
in following items
         P1_SENDER      -  // Sender for whom updation needs to be done 
         P1_APPROVER   -  // Approver who approves the mail
         P1_STATUS       - // Status of Approval -whether approved /rejected
Step:2:  Create mail process with following PL/SQL Code which frames the content of     mail.
DECLARE
   lv_to_email     VARCHAR2 (100)   := 'richard.dalvi@doyensys.com';
   lv_from_email   VARCHAR2 (100)   := 'karthik.venkatachalam@doyensys.com';
   lv_body         VARCHAR2 (32767);
BEGIN
   lv_body :=
         '<html>
<body>
Hi,'
      || CHR (10)
      || 'Kindly Approve my leave on 15-DEC-2015'
      || CHR (10)
      || '<br/>
<br/><a href="https://apex.oracle.com/pls/apex/f?p=24370:1:&SESSION.::&DEBUG.:P1_TO_EMAIL,P1_STATUS,P1_FROM_EMAIL:'
      || lv_from_email
      || ',Approved,'
      || lv_to_email
      || '" id="h1"><button>Approve</button></a> <a href="https://apex.oracle.com/pls/apex/f?p=24370:1:&SESSION.::&DEBUG.:P1_TO_EMAIL,P1_STATUS,P1_FROM_EMAIL:'
      || lv_from_email
      || ',Rejected,'
      || lv_to_email
      || '" id="h1"><button>Reject</button></a></body>
</html>';
   DBMS_OUTPUT.put_line (lv_body);
   apex_mail.send (p_to             => lv_to_email,
                   p_from           => lv_from_email,
                   p_subj           => 'Leave request',
                   p_body           => '',
                   p_body_html      => lv_body
                  );
END;

Key Controlled Report View

Every application all over world is in fond of key controlled or having shortcuts to report view. I have implemented this with some Javascript.
Step:1:  By Default , report should not be visible , So we have added attribute to region as: 
                             Region Attributes : style= “display:none;”
Step: 2:  Create a new html region and following javascript code for key recognition 
              and report view :  [Shortcut Key: Ctrl+S]
 <html>
                <head>
  <script>
  function test(e) {
   e = e || window.event; //Get event
   if (e.ctrlKey) {
   var c = e.which || e.keyCode; //Get key code
   switch (c) {
    case 83:// Block Ctrl+S
    e.preventDefault();     // Prevents Default Fuctionality
    e.stopPropagation();
    $("#TEST_REPORT").dialog();  // Opens Dialog
        }
      }
   };
  </script>
  </head>
               <body onkeydown="javascript:test(event);"> </body>
</html>

Cascading - Text With Auto-Complete in Tabular Form

Text with Auto Complete is  most common requirement and can be done normally for item level. But coming to tabular form it seems to be tedious due to dynamic ids and queries. Also Cascading 
process inclusion adds a valuable requirement.
Following are steps involved Cascading - Text with Auto-complete:
Step : 1: For Cascading I have to get source id and value, so I have used
               dynamic action,
Event                : Click
Selection Type : JQuery Selector
                            Value : [name = f03]   //Source Id
Action               : Javascript Code
Code                 :   var source_element = this.triggeringElement.id; //gets source id 
                              var source_value = $("#"+source_element).val(); 
                                                        // gets source value
                              $("#P41_MAP_TYPE").val(source_value);
                                                // Assign to item
Step:2: List of Values to be displayed in Text with Auto-complete can be       listed as static or it can also be fetched from query. So I have added   one more true action to add query and assigned query result to item, which act as  result set for auto-complete.
       Action              : Execute PL/SQL Code
       PL/SQL Code : DECLARE
                     lv_tag_asset   VARCHAR2 (32767);
                     lv_temp VARCHAR2(1000);
                     BEGIN
                          FOR i IN (SELECT tag_code tag_asset
                            FROM doy_com_tag_master
                            WHERE NVL (status, 'Y') = 'Y'
                            AND :P41_MAP_TYPE = 'TAG'
                            AND company_id = :f121_company_id
                            AND location_id = :f121_location_id
                         UNION
                              SELECT serial_number tag_asset
                              FROM doy_com_item_transaction
                              WHERE NVL (status, 'Y') = 'Y'
                               AND :P41_MAP_TYPE = 'ASSET'
                               AND company_id = :f121_company_id
                               AND location_id = :f121_location_id)
                  LOOP
                      lv_tag_asset := lv_tag_asset || ','|| i.tag_asset;
                  END LOOP;
                      :P41_TAG_ASSET := lv_tag_asset;
                   END;
Page Items to Return : P41_TAG_ASSET
Step : 3 :  On resulting item key-down we need auto-complete list, So I have added      dynamic action on key-down of item,

Event                : Key Down
Selection Type : JQuery Selector
                             Value : [name = f05]   //Source Id
Action               : Javascript Code
Code                  :   var availableTags;
                               var temp = new Array();
                               var c = $("#P41_TAG_ASSET").val();
                               temp = c.split(",");
                               availableTags = temp; 
                               var id = this.triggeringElement.id;
                               $( "#"+id ).autocomplete({
                                 source: availableTags
                                          });
Event Scope    :   Dynamic
                  Static Container : #report_tab_form   
                                            // id of tabular form is tab_form
Step: 4        :   Jquery library has to be added in our header level , it is better to add      it in template level. 
               <script src="//code.jquery.com/jquery-1.10.2.js"></script>
                <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
      

Wednesday, 13 January 2016

User Hooks in Oracle HRMS



User Hooks

There were many times we need to put some extra logic before or after happening of some business event. In Such cases, we use user hook API. It is a functionality provided in Oracle HRMS through which you can have more control on application with respect to implementing business rules.

In Oracle HRMS, Oracle has provided location in HRMS APIs, where customer can put his business logic. When API processing reaches a user hook, core product processing stops and any customer specific logic for that event is executed. After processing of customer specific logic, main API resumes its processing.

Step 1: Find the API for which HOOK has to write.
Step 2: Create a PL/SQL Procedure which fits requirements.
Step 3: Register created procedure into Required Hook:
Step 4: Run the Pre Processors to make the hook effective.
Step 5: Verify the status of user hook in table HR_API_HOOK_CALLS.

Case Study:

Absences validation - Let’s assume we want to put logic to stop a user if he applied annual leave more than 30 days. It should validate before Absence Creation.
Run the below query to show all person absence relevant APIs and select the correct API that matches our requirement. CREATE_PERSON_ABSENCE API is the one we are going to use so we should note its API_HOOK_ID and API_MODULE_ID. The API_HOOK_ID will be used at the time of registration of user hook and API_MODULE_ID will be used in running the per processor.

Query:
SELECT AHK.API_HOOK_ID,
AHK.API_MODULE_ID,
AHK.HOOK_PACKAGE,
AHK.HOOK_PROCEDURE
FROM HR_API_HOOKS AHK, HR_API_MODULES AHM
WHERE AHM.MODULE_NAME like ‘%_PERSON_ABSENCE%’
AND AHM.API_MODULE_TYPE = ‘BP’
AND AHK.API_HOOK_TYPE = ‘AP’
AND AHK.API_MODULE_ID = AHM.API_MODULE_ID;

Custom Package:
Creating the custom code for implementing the custom business rules.
CREATE OR REPLACE PACKAGE APPS.XXCUS_USERHOOK_PKG AS
PROCEDURE XXCUS_CREATE_ABS
(P_EFFECTIVE_DATE IN DATE,
P_PERSON_ID IN NUMBER,
P_BUSINESS_GROUP_ID IN NUMBER,
P_ABSENCE_ATTENDANCE_TYPE_ID IN NUMBER,
P_ABS_ATTENDANCE_REASON_ID IN NUMBER,
P_COMMENTS IN LONG,
P_DATE_NOTIFICATION IN DATE,
P_DATE_PROJECTED_START IN DATE,
P_TIME_PROJECTED_START IN VARCHAR2,
P_DATE_PROJECTED_END IN DATE,
P_TIME_PROJECTED_END IN VARCHAR2,
P_DATE_START IN DATE,
P_TIME_START IN VARCHAR2,
P_DATE_END IN DATE,
P_TIME_END IN VARCHAR2,
P_ABSENCE_DAYS IN NUMBER,
P_ABSENCE_HOURS IN NUMBER,
P_AUTHORISING_PERSON_ID IN NUMBER,
P_REPLACEMENT_PERSON_ID IN NUMBER,
P_ATTRIBUTE_CATEGORY IN VARCHAR2,
P_ATTRIBUTE1 IN VARCHAR2,
...          – Please include all the attribute1 to attribute20
P_ATTRIBUTE20 IN VARCHAR2,
P_PERIOD_OF_INCAPACITY_ID IN NUMBER,
P_SSP1_ISSUED IN VARCHAR2,
P_MATERNITY_ID IN NUMBER,
P_SICKNESS_START_DATE IN DATE,
P_SICKNESS_END_DATE IN DATE,
P_PREGNANCY_RELATED_ILLNESS IN VARCHAR2,
P_REASON_FOR_NOTIFICATION_DELA IN VARCHAR2,
P_ACCEPT_LATE_NOTIFICATION_FLA IN VARCHAR2,
P_LINKED_ABSENCE_ID IN NUMBER,
P_BATCH_ID IN NUMBER,
P_CREATE_ELEMENT_ENTRY IN BOOLEAN,
P_ABS_INFORMATION_CATEGORY IN VARCHAR2,
P_ABS_INFORMATION1 IN VARCHAR2,
       – Please include all the abs_information1 to abs_information30
P_ABS_INFORMATION30 IN VARCHAR2,
P_ABSENCE_CASE_ID IN NUMBER);
END XXCUS_USERHOOK_PKG;
/

CREATE OR REPLACE PACKAGE BODY APPS. XXCUS_USERHOOK_PKG
PROCEDURE XXCUS_CREATE_ABS (
P_EFFECTIVE_DATE IN DATE,
P_PERSON_ID IN NUMBER,
P_BUSINESS_GROUP_ID IN NUMBER,
P_ABSENCE_ATTENDANCE_TYPE_ID IN NUMBER,
P_ABS_ATTENDANCE_REASON_ID IN NUMBER,
P_COMMENTS IN LONG,
P_DATE_NOTIFICATION IN DATE,
P_DATE_PROJECTED_START IN DATE,
P_TIME_PROJECTED_START IN VARCHAR2,
P_DATE_PROJECTED_END IN DATE,
P_TIME_PROJECTED_END IN VARCHAR2,
P_DATE_START IN DATE,
P_TIME_START IN VARCHAR2,
P_DATE_END IN DATE,
P_TIME_END IN VARCHAR2,
P_ABSENCE_DAYS IN NUMBER,
P_ABSENCE_HOURS IN NUMBER,
P_AUTHORISING_PERSON_ID IN NUMBER,
P_REPLACEMENT_PERSON_ID IN NUMBER,
P_ATTRIBUTE_CATEGORY IN VARCHAR2,
P_ATTRIBUTE1 IN VARCHAR2,
          – Please include all the attribute1 to attribute20
P_ATTRIBUTE20 IN VARCHAR2,
P_PERIOD_OF_INCAPACITY_ID IN NUMBER,
P_SSP1_ISSUED IN VARCHAR2,
P_MATERNITY_ID IN NUMBER,
P_SICKNESS_START_DATE IN DATE,
P_SICKNESS_END_DATE IN DATE,
P_PREGNANCY_RELATED_ILLNESS IN VARCHAR2,
P_REASON_FOR_NOTIFICATION_DELA IN VARCHAR2,
P_ACCEPT_LATE_NOTIFICATION_FLA IN VARCHAR2,
P_LINKED_ABSENCE_ID IN NUMBER,
P_BATCH_ID IN NUMBER,
P_CREATE_ELEMENT_ENTRY IN BOOLEAN,
P_ABS_INFORMATION_CATEGORY IN VARCHAR2,
P_ABS_INFORMATION1 IN VARCHAR2,
...       – Please include all the abs_information1 to abs_information30
P_ABS_INFORMATION30 IN VARCHAR2,
P_ABSENCE_CASE_ID IN NUMBER) IS
L_ABSENCE_TYPE VARCHAR2 (500) := NULL;
L_ASSIGNMENT_ID NUMBER;
L_ABSENCE_START_DATE DATE := NVL (P_DATE_START, P_DATE_PROJECTED_START);
L_ABSENCE_END_DATE DATE := NVL (P_DATE_END, P_DATE_PROJECTED_END);
L_ABSENCE_FUTURE_ST_DATE DATE;
L_ABSENCE_FUTURE_END_DATE DATE;
BEGIN
SELECT NAME
INTO L_ABSENCE_TYPE
FROM PER_ABSENCE_ATTENDANCE_TYPES
WHERE ABSENCE_ATTENDANCE_TYPE_ID = P_ABSENCE_ATTENDANCE_TYPE_ID
AND BUSINESS_GROUP_ID = P_BUSINESS_GROUP_ID;

IF UPPER(TRIM(L_ABSENCE_TYPE)) = ‘ANNUAL LEAVE’ THEN
    IF L_ABSENCE_END_DATE – L_ABSENCE_START_DATE > 30 THEN
        HR_UTILITY.SET_MESSAGE (800, ‘LSG_ANN_LEAVE_GREATER_THAN_30’);
        HR_UTILITY.RAISE_ERROR;
    END IF;
END IF;
END
END XXCUS_CREATE_ABS;
END XXCUS_USERHOOK_PKG;

Hook Registration Script:
Using an API the custom logic will be registered against user hook. The API_HOOK_ID identified in the above query is passed as the parameter (p_api_hook_id) to the API.
DECLARE
L_API_HOOK_ID NUMBER:= 3840;
L_API_HOOK_CALL_ID NUMBER;
L_OBJECT_VERSION_NUMBER NUMBER;
L_SEQUENCE NUMBER;
BEGIN
SELECT HR_API_HOOKS_S.NEXTVAL
INTO L_SEQUENCE FROM DUAL;
HR_API_HOOK_CALL_API.CREATE_API_HOOK_CALL
(P_VALIDATE => FALSE,
P_EFFECTIVE_DATE => TO_DATE(’01-JAN-1952′,’DD-MON-YYYY’),
P_API_HOOK_ID =>L_API_HOOK_ID,
P_API_HOOK_CALL_TYPE => ‘PP’,
P_SEQUENCE => L_SEQUENCE,
P_ENABLED_FLAG => ‘Y’,
P_CALL_PACKAGE => ‘XXCUS_USERHOOK_PKG’,
P_CALL_PROCEDURE => ‘XXCUS_CREATE_ABS’,
P_API_HOOK_CALL_ID => L_API_HOOK_CALL_ID,
P_OBJECT_VERSION_NUMBER => L_OBJECT_VERSION_NUMBER);
DBMS_OUTPUT.PUT_LINE(‘L_API_HOOK_CALL_ID ‘|| L_API_HOOK_CALL_ID);
END ;

Hook Activation Script:
Run pre-processor script (PER_TOP/admin/sql/hrahkone.sql) with module name as parameter.
Alternatively, using the below script you can trigger the pre-processor
DECLARE
L_API_MODULE_ID NUMBER := 1731; –VALUE DERIVED FROM ABOVE QUERY
BEGIN
HR_API_USER_HOOKS_UTILITY.CREATE_HOOKS_ONE_MODULE (L_API_MODULE_ID);
DBMS_OUTPUT.PUT_LINE (‘SUCCESS’);
EXCEPTION WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE (‘EXCEPTION : ‘||SQLERRM);
END;

Below query is used to check the reference of the custom package/procedure in table HR_API_HOOK_CALLS.
Eg: SELECT * FROM HR_API_HOOK_CALLS WHERE api_hook_id = 3840;

Other Scenarios:
Below are other scenarios where we want to put extra logic to add extra business rules.
1. Validate Data in EIT & SIT before or after insertion either through self service or core HR
2. Validating particular customer data: Eg: you could limit grade step promotions to a maximum of one step.
3. Maintaining additional data in your own user defined tables
4. Detecting a particular business event. Eg: The event of an employee termination could be made to send a message to the security database to disable the employee’s security pass.