Friday, December 16, 2011

Sending concurrent request output by e-mail

This post describes how to send a request output using e-mail.
First, create two directories. The first one should point to the output directory.
CREATE DIRECTORY xx_output AS '/u02/oracle/VISION/inst/apps/VISION/logs/appl/conc/out';
GRANT ALL ON DIRECTORY xx_output TO PUBLIC;
The second one should be any directory that the database user can access.
CREATE DIRECTORY xx_maildir AS '/home/oracle/tmp';
GRANT ALL ON DIRECTORY xx_maildir TO PUBLIC;
Then create a generic procedure that can send mail with attachments.
create or replace
PROCEDURE xx_send_mail_file(p_subject     IN VARCHAR2,
                            p_message     IN VARCHAR2,
                            p_recipient   IN VARCHAR2,
                            p_max_size    IN NUMBER   DEFAULT 9999999999,
                            p_filename1   IN VARCHAR2 DEFAULT NULL,
                            p_filename2   IN VARCHAR2 DEFAULT NULL,
                            p_filename3   IN VARCHAR2 DEFAULT NULL,
                            p_return_desc OUT VARCHAR2) IS

  -- to store the ip address of the smtp server
  l_smtp_server                 VARCHAR2(50);

  -- to store the smtp port of the smtp server
  l_smtp_server_port            NUMBER;

  -- to store the path / directory name of the file
  l_directory_name              VARCHAR2(200);

  -- to store the filename
  l_file_name                   VARCHAR2(100);

  -- to store the contents of the line read from the file
  l_line                        VARCHAR2(1000);
  crlf                          VARCHAR2(2):= CHR(13) || CHR(10);

  -- to store the p_message
  l_mesg                        VARCHAR2(32767);

  -- smtp connection variable
  conn                          UTL_SMTP.CONNECTION;

  -- to store the list of recipeints
  l_msg_to                      VARCHAR2(2000);

  -- to store the name of the sender
  l_sender_name                 VARCHAR2(200);
  v_numberOf                    NUMBER := 1;
  v_addr                        VARCHAR2(500);

  TYPE varchar2_table IS TABLE OF VARCHAR2(200) INDEX BY BINARY_INTEGER;

  -- an array to store the file names
  file_array                    VARCHAR2_TABLE;

  -- array index
  i                             BINARY_INTEGER;

  -- file pointer
  l_file_handle                 UTL_FILE.FILE_TYPE;

  -- to store the position of \ in the file name
  l_slash_pos                   NUMBER;

  -- to store the lenght of the p_message
  l_mesg_len                    NUMBER;

  -- user defined exception
  abort_program                 EXCEPTION;

  -- boolean variable to trap if the p_message lenght is exceeding
  mesg_length_exceeded          BOOLEAN := FALSE;


  -- variable to store the error p_message. to be returned to the calling program
  l_return_desc1                VARCHAR2(2000);

  -- this procedure fetches the values for miscellaneous parameters
  PROCEDURE fetch_misc IS
  BEGIN
     l_return_desc1  := '11 - E: PARAMETER NOT MAINTAINED IN   MISC FOR AM_KEY1 = SMTP SERVER. ';
     l_smtp_server := 'localhost';

     l_return_desc1       := '22 - E: PARAMETER NOT MAINTAINED IN MISC FOR AM_KEY1 = SMTP PORT. ';
     l_smtp_server_port := '25';

     l_return_desc1   := '33 - E: PARAMETER NOT MAINTAINED IN MISC FOR '||
                         'AM_KEY1 = TICKET_EMAIL AND KEY2 =SENDER EMAIL. ';
     l_sender_name  := 'mailer@ebs.com';
  EXCEPTION
    WHEN others THEN
      RAISE ABORT_PROGRAM;
  END fetch_misc;

BEGIN
   -- fetching miscellaneous parameters
   FETCH_MISC;

   -- assigning file names to array
   file_array(1) := p_filename1;
   file_array(2) := p_filename2;
   file_array(3) := p_filename3;

   l_return_desc1  := '10 - E: THERE WAS AN ERROR IN OPENING CONNECTION. ';

   -- open connection on the server
   CONN:= UTL_SMTP.OPEN_CONNECTION( L_SMTP_SERVER, L_SMTP_SERVER_PORT );

   -- do the initial hand shake
   UTL_SMTP.HELO( CONN, L_SMTP_SERVER );

   UTL_SMTP.MAIL( CONN, L_SENDER_NAME );

   l_return_desc1  := '20 - E: THERE WAS AN ERROR IN CREATING RECIPIENTS.';

   IF (instr(p_recipient,';') = 0) THEN
     UTL_SMTP.RCPT(CONN, p_recipient);
   -- handles morde then one recipient, separated by ;
   ELSE
     WHILE (instr(p_recipient, ';', v_numberOf) > 0) LOOP

       v_addr := substr(p_recipient, v_numberOf, instr(substr(p_recipient, v_numberOf),';')-1);
       v_numberOf := v_numberOf + instr(substr(p_recipient, v_numberOf), ';');

       UTL_SMTP.RCPT(CONN, v_addr);

     END LOOP;
   END IF;

   UTL_SMTP.OPEN_DATA ( CONN );

   -- generate the mime header
   l_return_desc1  := '30 - E: THERE WAS AN ERROR IN GENERATING MIME HEADER. ';

   l_mesg:= 'Date: '||TO_CHAR(SYSDATE, 'dd Mon yy hh24:mi:ss')||crlf||
            'From: '||l_sender_name||crlf||
            'Subject: '||p_subject||crlf||
            'To: '||l_msg_to||crlf||
            'Mime-Version: 1.0'||crlf||
            'Content-Type: multipart/mixed; boundary="DMW.Boundary.605592468"'||crlf||''||crlf||
            'This is a Mime message, which your current mail reader may not'|| crlf||
            'understand. Parts of the message will appear as text. If the remainder'|| crlf||
            'appears as random characters in the p_message body, instead of as'|| crlf||
            'attachments, then you''ll have to extract these parts and decode them'|| crlf||
            'manually.'|| crlf||''||crlf||
            '--DMW.Boundary.605592468'||crlf||
            'Content-Type: text/plain; name="p_message.txt"; charset=US-ASCII'||crlf||
            'Content-Disposition: inline; filename="p_message.txt"'||crlf||
            'Content-Transfer-Encoding: 7bit'||crlf||''||crlf||
            p_message||crlf||crlf||crlf;

   l_mesg_len := LENGTH(l_mesg);

   IF l_mesg_len > p_max_size THEN
      MESG_LENGTH_EXCEEDED := TRUE;
   END IF;

   l_return_desc1  := '40 - E: THERE WAS AN ERROR IN WRITING p_message TO CONNECTION. ';
   UTL_SMTP.WRITE_DATA ( CONN, l_mesg );

   -- start attaching the files
   FOR I IN  1..3 LOOP

       EXIT WHEN MESG_LENGTH_EXCEEDED;

       IF file_array(I) IS NOT NULL THEN
          BEGIN

             l_slash_pos := INSTR(file_array(I), '/', -1 );

             IF l_slash_pos = 0 THEN
                l_slash_pos := INSTR(file_array(I), '\', -1 );
             END IF;

             l_directory_name := 'XX_MAILDIR';

             l_file_name      := SUBSTR(file_array(I), l_slash_pos + 1 );

             l_return_desc1   := '50 - E: THERE WAS AN ERROR IN OPENING FILE. ';

             l_file_handle    := UTL_FILE.FOPEN(l_directory_name, l_file_name, 'R' );

             l_mesg           := crlf || '--DMW.Boundary.605592468'||crlf||
                                'Content-Type: application/octet-stream; name="'||
                                 l_file_name||'"'||crlf||
                                'Content-Disposition: attachment; filename="' ||
                                 l_file_name||'"'||crlf||
                                'Content-Transfer-Encoding: 7bit' || crlf || crlf ;

             l_mesg_len       := l_mesg_len + LENGTH(l_mesg);

             UTL_SMTP.WRITE_DATA ( CONN, l_mesg );

             LOOP
                 l_return_desc1  := '60 - E: THERE WAS AN ERROR IN READING FILE. ';
                 UTL_FILE.GET_LINE(l_file_handle, l_line);

                 IF l_mesg_len + LENGTH(l_line) > p_max_size THEN

                    l_mesg := '*** truncated ***' || crlf;
                    UTL_SMTP.WRITE_DATA ( CONN, l_mesg );
                    MESG_LENGTH_EXCEEDED := TRUE;
                    EXIT;

                 END IF;

                 l_mesg := l_line || CRLF;
                 UTL_SMTP.WRITE_DATA ( CONN, l_mesg );
                 l_mesg_len := l_mesg_len + LENGTH(l_mesg);
             END LOOP;
          EXCEPTION
             WHEN no_data_found THEN
               NULL;
             WHEN utl_file.invalid_path THEN
               RAISE ABORT_PROGRAM;
             WHEN others THEN
               RAISE ABORT_PROGRAM;
          END;

          l_mesg := crlf;

          UTL_SMTP.WRITE_DATA ( CONN, l_mesg );
          UTL_FILE.FCLOSE(l_file_handle);
        END IF;
   END LOOP;

   l_return_desc1  := '70 - E: THERE WAS AN ERROR IN CLOSING MIME BOUNDARY. ';
   l_mesg := crlf || '--DMW.Boundary.605592468--' || crlf;

   UTL_SMTP.WRITE_DATA ( CONN, l_mesg );
   UTL_SMTP.CLOSE_DATA( CONN );
   UTL_SMTP.QUIT( CONN );
EXCEPTION
  WHEN abort_program THEN
    p_return_desc := l_return_desc1;
  WHEN others THEN
    p_return_desc := l_return_desc1;
END xx_send_mail_file;
In the above code you need to change mailserver, port and sender so it suites your needs.

Next, create a procedure that will submit a request and send the output.
create or replace
PROCEDURE xx_send_mail_outp (errbuf        OUT VARCHAR2,
                             retcode       OUT VARCHAR2) IS

  v_response            VARCHAR2(1000);
  v_request_id          NUMBER;
  no_req                EXCEPTION;

  v_wait_status         BOOLEAN;

  v_request_phase       VARCHAR2(1000);
  v_request_status      VARCHAR2(1000);
  v_dev_request_phase   VARCHAR2(1000);
  v_dev_request_status  VARCHAR2(1000);
  v_request_status_mesg VARCHAR2(1000);
BEGIN
  v_request_id := fnd_request.submit_request('FND',       -- Application
                                             'FNDSCARU',  -- Request (Active Responsibilities and Users)
                                             '','',FALSE,
                                             '','','','','','','','',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '', '', '', '', '', '', '', '', '',
                                             '', '');

  -- Verify that the concurrent request was launched
  -- successfully.
  IF (v_request_id = 0) THEN
    raise no_req;
  ELSE
    fnd_file.put_line(fnd_file.log, 'Submitted request: '||v_request_id);
  END IF;

  COMMIT;

  -- wait for request to finish
  v_wait_status := fnd_concurrent.wait_for_request(v_request_id,
                                                   2,  -- interval in sec
                                                   60, -- total wait time in sec
                                                   v_request_phase,
                                                   v_request_status,
                                                   v_dev_request_phase,
                                                   v_dev_request_status,
                                                   v_request_status_mesg);


  -- copy file from output dir to tmp dir
  -- also renaming the file in the same operation
  utl_file.fcopy('XX_OUTPUT', 'o'||v_request_id||'.out', 'XX_MAILDIR', 'Active_Resp_'||
                              TO_CHAR(SYSDATE,'YYMMDD')||'.pdf');

  -- send the mail
  xx_send_mail_file('Sending the output of request Active Responsibilities and Users',
                    'Result is attached.'||chr(10)||'Sysadmin',
                    'yourname@yourdomain.com',
                    9999999999,
                    'Active_Resp_'||TO_CHAR(SYSDATE,'YYMMDD')||'.pdf',
                    NULL,
                    NULL,
                    v_response);

  fnd_file.put_line(fnd_file.log, 'Mail response: '||nvl(v_response,'SUCCESS'));

EXCEPTION
  WHEN no_req THEN
    fnd_file.put_line(fnd_file.log, 'ERROR: Could not submit request');
    retcode := '2';
  WHEN others THEN
    fnd_file.put_line(fnd_file.log, 'ERROR: '||SQLERRM);
    retcode := '2';
    RAISE;
END xx_send_mail_outp;
In the example above I am submitting the request Active Responsibilities and Users. The recipient is hardcoded but can easily be extended to be more dynamic, the code also handles more then one recipient (separate the addresses with ;). The procedure xx_send_mail_outp is created to be a request it self and if you would like to test this you need to do that setup.

Wednesday, December 14, 2011

FNDLOAD

This post describes how to down- and upload different components using FNDLOAD.

Value set
Download
FNDLOAD apps/appspwd O Y DOWNLOAD $FND_TOP/patch/115/import/afffload.lct download_file.ldt VALUE_SET FLEX_VALUE_SET_NAME="VALUE_SET_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afffload.lct download_file.ldt CUSTOM_MODE=FORCE

Note:
Use the optional FNDLOAD parameter P_VSET_DOWNLOAD_CHILDREN set to N if you do not want the value set values to be downloaded.

Concurrent Request
Download
FNDLOAD apps/appspwd O Y DOWNLOAD $FND_TOP/patch/115/import/afcpprog.lct download_file.ldt PROGRAM APPLICATION_SHORT_NAME="APPL_SHORT_NAME" CONCURRENT_PROGRAM_NAME="REQUEST_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afcpprog.lct download_file.ldt CUSTOM_MODE=FORCE

Note: If value sets are used by the request parameters the set up for them will also be included in the ldt-file. If the value set is not new it is recommended to remove the creation part from the upload file.

Request set
When using FNDLOAD for a request set it includes two parts, the request set definition and the request set linkage.

Download
FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/afcprset.lct download_file_def.ldt REQ_SET REQUEST_SET_NAME="REQUEST_SET_NAME"

FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/afcprset.lct download_file_link.ldt REQ_SET_LINKS REQUEST_SET_NAME="REQUEST_SET_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afcprset.lct download_file_def.ldt CUSTOM_MODE=FORCE

FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afcprset.lct download_file_link.ldt CUSTOM_MODE=FORCE

Request Group
Download
FNDLOAD apps/appspwd O Y DOWNLOAD $FND_TOP/patch/115/import/afcpreqg.lct download_file.ldt REQUEST_GROUP REQUEST_GROUP_NAME="REQUEST_GRP_NAME" APPLICATION_SHORT_NAME="APPL_SHORT_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afcpreqg.lct download_file.ldt CUSTOM_MODE=FORCE

Profile option
Download
FNDLOAD apps/appspwd O Y DOWNLOAD $FND_TOP/patch/115/import/afscprof.lct download_file.ldt PROFILE PROFILE_NAME="PROFILE_NAME" APPLICATION_SHORT_NAME="APPL_SHORT_NAME"

Upload
FNDLOAD apps/appspwd O Y UPLOAD $FND_TOP/patch/115/import/afscprof.lct download_file.ldt CUSTOM_MODE=FORCE

Descriptive Flexfield
Download
FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/afffload.lct download_file.ldt DESC_FLEX APPLICATION_SHORT_NAME="APPL_SHORT_NAME" DESCRIPTIVE_FLEXFIELD_NAME="DESC_FLEXFIELD_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afffload.lct download_file.ldt CUSTOM_MODE=FORCE

Form and Function
Download
FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/afsload.lct download_file.ldt FUNCTION FUNCTION_NAME=="FUNCTION_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afsload.lct download_file.ldt CUSTOM_MODE=FORCE

Menu
Download
FNDLOAD apps/appspwd O Y DOWNLOAD $FND_TOP/patch/115/import/afsload.lct download_file.ldt MENU MENU_NAME="MENU_NAME"

Upload
FNDLOAD apps/appspwd O Y UPLOAD $FND_TOP/patch/115/import/afsload.lct download_file.ldt CUSTOM_MODE=FORCE

Note: When a menu is downloaded all the entries in the menu will be included in the ldt-file. It is recommended to remove all the entries that are not new.

Message
Download
FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/afmdmsg.lct
download_file.ldt FND_NEW_MESSAGES APPLICATION_SHORT_NAME="APPL_SHORT_NAME" MESSAGE_NAME="MESSAGE_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afmdmsg.lct download_file.ldt CUSTOM_MODE=FORCE

Lookup value

Download
FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/aflvmlu.lct download_file.ldt FND_LOOKUP_TYPE APPLICATION_SHORT_NAME="APPL_SHORT_NAME" LOOKUP_TYPE="LOOKUP_TYPE_NAME"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/aflvmlu.lct download_file.ldt CUSTOM_MODE=FORCE

Folder
DownloadFNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/fndfold.lct download_file.ldt FND_FOLDERS NAME="folder name"

Upload
FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/fndfold.lct download_file.ldt CUSTOM_MODE=FORCE

Note: When you download a folder you need to set the language to get any data in the ldt-file (how-to is specified under Generic Notes).

Forms personalization
Download
FNDLOAD apps/appspwd 0 Y DOWNLOAD $FND_TOP/patch/115/import/affrmcus.lct download_file.ldt FND_FORM_CUSTOM_RULES FUNCTION_NAME="FUNCTION_NAME"

Upload
First, run the script to remove personalizations (the script have to be customized to remove the same data as you are uploading). We need to run this script because there is a bug in the upload script.

DECLARE
  CURSOR cu_functions IS
    SELECT DISTINCT
           form_name
         , function_name
         , rule_type
         , rule_key
    FROM fnd_form_custom_rules
    WHERE form_name = FORM NAME
    ORDER BY function_name;

BEGIN
  FOR ru_functions IN cu_functions
  LOOP
    fnd_form_custom_rules_pkg.delete_set
      ( ru_functions.rule_key
      , ru_functions.rule_type
      , ru_functions.function_name
      , ru_functions.form_name
      );
    COMMIT;
  END LOOP;
END;

FNDLOAD apps/appspwd 0 Y UPLOAD affrmcusx.lct download_file.ldt CUSTOM_MODE=FORCE

Note: The function name is the function short name as seen in the Function Definition Screen.

XML Publisher 
To handle the down- and upload of XML Publisher templates and Data Definitions there are a few extra steps to take care of. 

Download – Template and Data Definition
FNDLOAD apps/appspwd 0 Y DOWNLOAD $XDO_TOP/patch/115/import/xdotmpl.lct download_file.ldt XDO_DS_DEFINITIONS APPLICATION_SHORT_NAME="APPL_SHORT_NAME" DATA_SOURCE_CODE="DATA_SOURCE_CODE"

Download – Template physical file
java oracle.apps.xdo.oa.util.XDOLoader DOWNLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION apps.server:port:sid -APPS_SHORT_NAME app_short_name -LOB_CODE template_code -LOB_TYPE TEMPLATE -LANGUAGE language -TERRITORY territory

Example
java oracle.apps.xdo.oa.util.XDOLoader DOWNLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION server1.cpm.com:1521:TEST -APPS_SHORT_NAME XX -LOB_CODE XX_AR_BALANCE_REP -LOB_TYPE TEMPLATE -LANGUAGE sv -TERRITORY SE

Download – Data template physical file
java oracle.apps.xdo.oa.util.XDOLoader DOWNLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION apps.server:port:sid -APPS_SHORT_NAME app_short_name -DS_CODE data_definition_code

Example
java oracle.apps.xdo.oa.util.XDOLoader DOWNLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION server1.cpm.com:1521:TEST -APPS_SHORT_NAME XX -DS_CODE XX_AR_BALANCE_REP

Upload – Template and Data Definition
FNDLOAD apps/appspwd 0 Y UPLOAD $XDO_TOP/patch/115/import/xdotmpl.lct download_file.ldt CUSTOM_MODE=FORCE

Upload – Template physical file
java oracle.apps.xdo.oa.util.XDOLoader UPLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION apps.server:port:sid -APPS_SHORT_NAME app_short_name -LOB_CODE template_code -LOB_TYPE TEMPLATE -XDO_FILE_TYPE RTF -FILE_NAME template_name.rtf -CUSTOM_MODE FORCE -LANGUAGE language -TERRITORY territory

Example
java oracle.apps.xdo.oa.util.XDOLoader UPLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION server1.cpm.com:1521:TEST -APPS_SHORT_NAME XX -LOB_CODE XX_AR_BALANCE_REP -LOB_TYPE TEMPLATE -XDO_FILE_TYPE RTF -FILE_NAME XX_AR_BALANCE_REP.rtf -CUSTOM_MODE FORCE -LANGUAGE sv -TERRITORY SE

Upload – Data template physical file
java oracle.apps.xdo.oa.util.XDOLoader UPLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION apps.server:port:sid -APPS_SHORT_NAME app_short_name -LOB_CODE data_definition_code -LOB_TYPE DATA_TEMPLATE -XDO_FILE_TYPE XML -FILE_NAME data_definition_name.xml -CUSTOM_MODE FORCE

Example
java oracle.apps.xdo.oa.util.XDOLoader UPLOAD -DB_USERNAME apps -DB_PASSWORD appspwd -JDBC_CONNECTION server1.cpm.com:1521:TEST -APPS_SHORT_NAME XX -LOB_CODE XX_AR_BALANCE_REP -LOB_TYPE DATA_TEMPLATE -XDO_FILE_TYPE XML -FILE_NAME XX_AR_BALANCE_REP.xml -CUSTOM_MODE FORCE

Note
  • The valid valid for parameter LANGUAGE is sv for Swedish and en for English.
  • The valid valid for parameter TERRITORY is SE for Sweden and US for USA.
  • When you download the data definition physical file all the template files will be downloaded. 
  • Useful tables for XML P are XDO_TEMPLATES_B, XDO_LOBS and XDO_TEMPLATES_TL.

Generic notes

  • If the information you are downloading is not the same in English and Swedish you need to run the download command twice. Name your ldt-file with the ending _S (download_file_S.ldt) and _US (download_file_US.ldt).

    To download a specific language (other then English) you have to set NLS_LANG accordingly.
    Swedish:
    export NLS_LANG='SWEDISH_SWEDEN.WE8ISO8859P1'
  • If the information is the same in English and Swedish you only have to download once. Then create two files and name them accordingly. You need to change the LANGUAGE setting in the ldt-file to S for the _S-file and US for the _US-file.
    To get Swedish characters correct set
    export NLS_LANG='SWEDISH_SWEDEN.WE8ISO8859P1' before downloading.
  • Use upload parameter CUSTOM_MODE=FORCE to be sure that the informtion you are uploading is updating the system.FNDLOAD apps/appspwd 0 Y UPLOAD $FND_TOP/patch/115/import/afcpprog.lct download_file.ldt - CUSTOM_MODE=FORCE

Thursday, December 8, 2011

Diagnostics -> Examine

To be able to use the menu Help -> Diagnostics -> Examine you have to set the profile value Utilities:Diagnostics to Yes.


Thursday, November 24, 2011

Remove OAF Customization

First, list your customization to get the exact path:
begin
  jdr_utils.listdocuments('/oracle/apps/ar/hz/components/search/server',TRUE);
end;
Then, remove it:
begin
  jdr_utils.deletedocument(p_document => '/oracle/apps/ar/hz/components/search/server/customizations/site/0/HzPuiDQMSrchResultsVO');
  COMMIT;
end;

Monday, November 21, 2011

Compiling Form in R12 env

1. FTP your form to $AU_TOP/forms/US
2. Compile using:
frmcmp_batch userid=USERNAME/PASSWORD module=XXXXX.fmb output_file=XXXXX.fmx module_type=form
3. Move the fmx to the correct folder, ex
mv XXXXX.fmx $AP_TOP/forms/US/XXXXX.fmx
4. Done

Thursday, November 10, 2011

DBMS_SCHEDULER

When you back in the day wanted to schedule or run something in the backgound you used DBMS_JOB. With  the beginning of release 10g of the database new functionality was introduced to accomplish this, the DBMS_SCHEDULER.

DBMS_SCHEDULER is so much more flexible the DBMS_JOB and makes everything easier, some examples:

  • To set up your intervals you just specify the parameter repeat_interval.
    MON-FRI 22.00: repeat_interval=> 'FREQ=DAILY; BYDAY=MON,TUE,WED,THU,FRI; BYHOUR=22;'
    Every hour, every day: repeat_interval => 'FREQ=HOURLY;INTERVAL=1'
    Every monday, 05:00: repeat_interval=> 'FREQ=DAILY; BYDAY=MON; BYHOUR=5;'
  • You will not get the problem with shifting start times that you have with DBMS_JOB.
  • Possible to create chains of jobs that are dependent of each other.
  • Possible to schedule:
     
    - Execution of host scripts.
     - E-mail notifications.
     - Execute host scripts on remote servers (requires an agent on the remote server).
     - Execute jobs on multiple databases.
  • You can create a file watcher that will let you monitor a folder for files. When new files arrives the specified job will start.
To be able to use all the functions of DBMS_SCHEDULER you need to be on 11g release 2. There is a lot of artictles about the DBMS_SCHEDULER but you can get a good overview with examples can be found here.

One of the cooler features with the DBMS_SCHEDULER is the file watcher. I will illustrate the functionality with an exampel.

Create a new user and directory
CREATE USER fw_test_usr IDENTIFIED BY test;
GRANT connect, resource, dba TO fw_test_usr;

CREATE OR REPLACE DIRECTORY demo_dir AS '/home/oracle/tmp';
GRANT read, write ON DIRECTORY demo_dir TO fw_test_usr;

CREATE OR REPLACE DIRECTORY demo_old_dir AS '/home/oracle/tmp/old';
GRANT read, write ON DIRECTORY demo_old_dir TO fw_test_usr;
The file watchers will by default check for files every 10 minutes, we will decrease that to every minute.
CONN / AS SYSDBA

BEGIN
  DBMS_SCHEDULER.set_attribute(
    'file_watcher_schedule',
    'repeat_interval',
    'freq=minutely; interval=1');
END;
/
Now, logged in as fw_test_usr we need to set up OS privilege for file access.
BEGIN
  DBMS_SCHEDULER.create_credential(
    credential_name => 'watcher_credential',
    username        => 'oracle',
    password        => 'oracle');
END;

SELECT * FROM dba_scheduler_credentials;
The next step is to create the file watcher. The file watcher is not enabled yet (enabled => FALSE).
BEGIN
  DBMS_SCHEDULER.create_file_watcher(
    file_watcher_name => 'demo_file_watcher',
    directory_path    => '/home/oracle/tmp',
    file_name         => '*.txt',
    credential_name   => 'watcher_credential',
    destination       => NULL,
    enabled           => FALSE);
END;

SELECT * FROM dba_scheduler_file_watchers;
Create a table and the procedure that will be used by the file watcher.
CREATE TABLE fw_demo_tbl_output 
 (message VARCHAR2(4000),
  row1    VARCHAR2(4000));

CREATE OR REPLACE
PROCEDURE fw_demo_proc (p_fileinfo SYS.SCHEDULER_FILEWATCHER_RESULT) AS

  v_file    utl_file.file_type;
  v_message VARCHAR2(4000);
  v_row1    VARCHAR2(4000);
BEGIN
  -- file path, name and size
  v_message := p_fileinfo.directory_path||'/'||
               p_fileinfo.actual_file_name||'('||
               p_fileinfo.file_size||')';

  -- read the first row of the file
  v_file := utl_file.fopen('DEMO_DIR', p_fileinfo.actual_file_name, 'R');
  LOOP
    BEGIN
      utl_file.get_line(v_file, v_row1);
      EXIT;
    EXCEPTION
      WHEN OTHERS THEN
        EXIT;
    END;
  END LOOP;
  utl_file.fclose(v_file);

  -- move the file to the old directory with a new name
  utl_file.frename
     (src_location  => 'DEMO_DIR',
      src_filename  => p_fileinfo.actual_file_name,
      dest_location => 'DEMO_OLD_DIR',
      dest_filename => p_fileinfo.actual_file_name||'.'||to_char(SYSDATE, 'YYMMDDHH24MISS'),
      overwrite     => FALSE);

  INSERT INTO fw_demo_tbl_output (message, row1) VALUES (v_message, v_row1);
  COMMIT;
END;
Create a Program object with a Metadata argument (what will happen when the file watcher event is raised). The program must reference the event_message to retrieve information about the file, such as it's name. The program is not enabled yet (enabled => FALSE).
BEGIN
  DBMS_SCHEDULER.create_program(
    program_name        => 'fw_demo_prog',
    program_type        => 'stored_procedure',
    program_action      => 'fw_demo_proc',
    number_of_arguments => 1,
    enabled             => FALSE);
END;

BEGIN
  DBMS_SCHEDULER.define_metadata_argument(
    program_name       => 'fw_demo_prog',
    metadata_attribute => 'EVENT_MESSAGE',
    argument_position  => 1);
END;

SELECT *
FROM dba_scheduler_programs
WHERE program_name= 'FW_DEMO_PROG'
ORDER BY 1;

SELECT *
FROM dba_scheduler_program_args
WHERE program_name = 'FW_DEMO_PROG';
Now, create the job. The job is not enabled yet (enabled => FALSE).
BEGIN
  DBMS_SCHEDULER.create_job(
    job_name        => 'fw_demo_job',
    program_name    => 'fw_demo_prog',
    event_condition => NULL,
    queue_spec      => 'demo_file_watcher',
    auto_drop       => FALSE,
    enabled         => FALSE);
END;

SELECT *
FROM dba_scheduler_jobs
WHERE job_name='FW_DEMO_JOB';
By default, the arrival of new files will be ignored if the job is already running. If you need the job to fire for each new arrival, regardless of whether the job is already running or not, set the PARALLEL_INSTANCES attribute for the job to true. The job will then be run as a lightweight job.
BEGIN
  DBMS_SCHEDULER.set_attribute('fw_demo_job','parallel_instances',TRUE);
END;
The last step is to enable everything.
BEGIN
  DBMS_SCHEDULER.enable('demo_file_watcher');
  DBMS_SCHEDULER.enable('fw_demo_prog');
  DBMS_SCHEDULER.enable('fw_demo_job');
END;
Now create some .txt files in folder /home/oracle/tmp on the server. Then wait a couple a minutes and the information sould appear in the table. The files should also have been moved to the old folder on the server.
SELECT * FROM  fw_demo_tbl_output;

Wednesday, October 26, 2011

Contract line -> Inventory Item

Useful query which will fetch your inventory items from contract lines.

Service Products:
SELECT kl.line_number,
       ks.name,
       itm.segment1,
       itm.segment2
FROM okc_k_headers_v kh,
     okc_k_lines_v kl,
     okc_k_items ki,
     okc_line_styles_v ks,
     mtl_system_items_b itm
WHERE kh.contract_number = 'contract number'
AND   kh.contract_number_modifier IS NULL
AND   kh.id = kl.dnz_chr_id
AND   kh.id = ki.dnz_chr_id
AND   kl.id = ki.cle_id
AND   kl.lse_id = ks.id
AND   ki.jtot_object1_code IN ('OKX_SERVICE')
AND   kh.inv_organization_id = itm.organization_id
AND   ki.object1_id2 = itm.organization_id
AND   ki.object1_id1 = itm.inventory_item_id
ORDER BY kl.line_number;
Covered Products:
SELECT kl.line_number,
       ks.NAME,
       i.segment1,
       i.segment2
FROM okc_k_headers_b kh,
     okc_k_lines_b kl,
     okc_k_items ki,
     okc_line_styles_v ks,
     csi_item_instances c,
     mtl_system_items_b i
WHERE kh.contract_number = 'contract number'
AND   kh.contract_number_modifier IS NULL
AND   kh.id = kl.dnz_chr_id
AND   kh.id = ki.dnz_chr_id
AND   kl.id = ki.cle_id
AND   kl.lse_id = ks.id
AND   ki.jtot_object1_code IN ('OKX_CUSTPROD')
AND   c.last_vld_organization_id = i.organization_id
AND   ki.object1_id1 = c.instance_id
AND   c.inventory_item_id = i.inventory_item_id
ORDER BY kl.line_number;
References
  • Note 467334.1: 11i: How to Query the Service Contracts Tables for Header, Line, Subline and Billing Information in 11.5.10+ 
  • OTN Forum

List Forms Personalization and XX-Forms

In a R12 upgrade project it can be a good idea to read some information from the database regarding the customizations.

List Forms Personalization
SELECT ft.user_function_name, 
       fo.form_name,
       c.* 
FROM fnd_form_custom_rules c,
     fnd_form_functions f,
     fnd_form_functions_tl ft,
     fnd_form fo
WHERE c.function_name = f.function_name
AND   f.function_id = ft.function_id
AND   f.form_id = fo.form_id
ORDER BY 2
List Custom Forms
SELECT ft.user_form_name,
       f.* 
FROM fnd_form f,
     fnd_form_tl ft
WHERE f.form_id = ft.form_id
AND   form_name LIKE 'XX%'
ORDER BY 4

Wednesday, October 19, 2011

Set completion status of Concurrent Request (Host)

If you have a concurrent request executable of type host (shell script on unix) and you want to set the status of the request to Warning or Error upon completion you need to use a small SQL-script to accomplish this.

Warning
DECLARE
  l_result     BOOLEAN;
  l_session_id NUMBER;
  l_reqid      NUMBER;
BEGIN
  l_reqid := '&&1';
  dbms_output.put_line('l_reqid '||l_reqid);
  fnd_global.INITIALIZE(l_session_id, null, null, null,null, -1, null, null, null, 
                        null, l_reqid, null,null,null,null,null,null,-1);
  l_result := fnd_concurrent.set_completion_status('WARNING','Review log file for details.');
  COMMIT;
END;
/
exit 0;
Error
DECLARE
  l_result     BOOLEAN;
  l_session_id NUMBER;
  l_reqid      NUMBER;
BEGIN
  l_reqid := '&&1';
  dbms_output.put_line('l_reqid '||l_reqid);
  fnd_global.INITIALIZE(l_session_id, null, null, null,null, -1, null, null, null, 
                        null, l_reqid, null,null,null,null,null,null,-1);
  l_result := fnd_concurrent.set_completion_status('ERROR','Review log file for details.');
  COMMIT;
END;
/
exit 0;
Call the script from your shell script
sqlplus $unpw @$XX_TOP/sql/your file name.sql "$conc_request_id"
You can of course handle both Warning and Error in the same SQL-file.

Sunday, October 9, 2011

Concurrent request output directory

In most cases the output files will be written to $COMMON_TOP/admin/out/<ENV.NAME>.

If you don't find anything there investgate the environment variables $APPLCSF (path), $APPLLOG (folder name) and $APPLOUT (folder name).

I read somewhere that if $APPLCSF is not set the outputs will be written to $<APPLICATION_SHORT_NAME>/<VALUE OF $APPLOUT> e.g $AR_TOP/admin/out.

Saturday, October 8, 2011

Internet Exploring crashing when starting EBS (jInitiator)

Internet Exploring is crashing when starting EBS (jInitiator). You have installed jInitiator ver 1.3.1.21 without any problem but when you are trying to start the Forms environment IE is crashing. A workaround can be found here.

I have used this solution succsessfully both with XP and Win7.

Friday, October 7, 2011

List profile options and their values

This select will give you all the values for a specific profile option.
SELECT potl.language,
       potl.user_profile_option_name,
       potl.description,
       po.profile_option_id,
       DECODE(pov.level_id, 10001, 'Site',
                            10002, 'Application',
                            10003, 'Responsibility',
                            10004, 'User',
                            10005, 'Server',
                            10006, 'Org',
                            10007, DECODE(to_char(pov.level_value2), '-1', 'Responsibility',
                                   DECODE(to_char(pov.level_value), '-1', 'Server',
                                   'Server+Resp')),
                            'UnDef') level_set,
       DECODE(to_char(pov.level_id), '10001', '',
                                     '10002', app.application_short_name,
                                     '10003', rsp.responsibility_key,
                                     '10004', usr.user_name,
                                     '10005', svr.node_name,
                                     '10006', org.name,
                                     '10007', DECODE(to_char(pov.level_value2), '-1', 
                                                     rsp.responsibility_key,
                                              DECODE(to_char(pov.level_value), '-1',
                                             (SELECT node_name
                                              FROM fnd_nodes
                                              WHERE node_id = pov.level_value2),
                                             (SELECT node_name
                                              FROM fnd_nodes
                                              WHERE node_id = pov.level_value2)||'-'||
                                                              rsp.responsibility_key)),
                                     'UnDef') context,
       pov.profile_option_value value
FROM fnd_profile_options po,
     fnd_profile_options_tl potl,
     fnd_profile_option_values pov,
     fnd_user usr,
     fnd_application app,
     fnd_responsibility rsp,
     fnd_nodes svr,
     hr_operating_units org
WHERE po.profile_option_id = pov.profile_option_id
AND   po.profile_option_name = potl.profile_option_name
AND   usr.user_id (+) = pov.level_value
AND   app.application_id (+) = pov.level_value
AND   rsp.application_id (+) = pov.level_value_application_id
AND   rsp.responsibility_id (+) = pov.level_value
AND   svr.node_id (+) = pov.level_value
AND   org.organization_id (+) = pov.level_value
AND   po.profile_option_name = profile_option_name
ORDER BY 1, 5, 6
Tested with 11i.

Monday, October 3, 2011

Status of a customer

One of my clients who run the Finance modules (AR, ARP, GL etc), Service Contracts and Field Service in E-Business Suite R12 had some issues with customers who were inactive.
The issue arised when they were creating Service Requests (through API cs_servicerequest_pub.Create_ServiceRequest) and got an error reported by the API that the request could  not be created due to the customer was invalid.

The reason that a customer is invalid can vary but one reason is that some level of the customer is inactive. In AR and the TCA model the customer (party) status can be set in the following tables:

  • hz_parties (TCA)
  • hz_party_sites (TCA)
  • hz_party_site_uses (TCA)
  • hz_cust_accounts (TCA-AR)
  • hz_cust_acct_sites_all (TCA-AR)
  • hz_cust_site_uses_all (TCA-AR)
In my clients case status was Active in all tables except hz_party_site_uses. Below I will explain how it's possible to change the statuses.

Set status in Account Receivables

If you inactivate an Account Site Address/Account Site Details the status will be set to I (Inactive) in hz_party_siteshz_party_site_useshz_cust_acct_sites_all and hz_cust_site_uses_all.


By using the Restore icon on an adress the status will be set to A (Active) in hz_party_sites and hz_cust_acct_sites_all. Note that the purpose level (hz_party_site_uses and hz_cust_site_uses_all) is still Inactive and need to be reactivated manually.

When a Business Purpose is restored the status will be set to A (Active) in hz_cust_site_uses_all and hz_party_site_uses. In hz_party_site_uses a new row is created with status A.

The strange thing is that if we look in Service (Contact Center), we now have one Active and one Inactive usage for Bill To.

The table hz_party_site_uses is version controlled and the row that have status A have object_version_number 1 (not 2 as expected).


To inactivate the account level in AR open the Account (in the Customer form) and change the status.


Set status in Service
To activate/inactivate an account, site or purpose in Service, use responsibility Field Service Manager and open Contact Center, go to tab Addresses. You need to check Include Inactive to show the inactive sites and purposes.


If you inactivate an address the status will be set to I (Inactive) in hz_party_sites, hz_party_site_uses, hz_cust_acct_sites_all and hz_cust_site_uses_all.

If you activate an address the status will be set to A (Active) in hz_party_sites and hz_cust_acct_sites_all. Note that the purpose level (hz_party_site_uses and hz_cust_site_uses_all) is still Inactive and need to be reactivated manually.

To inactivate a account go to tab Accounts.


Set status on party level
If you want to inactivate the Party level (hz_parties) you need to use the responsibility Oracle Customers Data Librarian Superuser and Navigate: Data Quality -> Party Maintenance tab.


The query below can be helpful if you want to check the statuses in the database.
SELECT hp.party_id,
       hp.party_name,
       hp.party_number,
       hps.party_site_id,
       hcas.org_id,
       hpsu.site_use_type,                
       hps.party_site_number,
       hp.status hz_parties,
       hps.status hz_party_sites,
       hpsu.status hz_party_site_uses,                 
       hcsu.site_use_code,                              
       ca.status hz_cust_accounts,
       hcas.status hz_cust_acct_sites_all,                
       hcsu.status hz_cust_site_uses_all
FROM hz_parties hp,
     hz_party_sites hps,
     hz_party_site_uses hpsu,
     hz_cust_accounts ca,
     hz_cust_acct_sites_all hcas,
     hz_cust_site_uses_all hcsu
WHERE hp.party_id = hps.party_id
AND   hp.party_id = ca.party_id
AND   hps.party_site_id = hcas.party_site_id
AND   hcsu.cust_acct_site_id = hcas.cust_acct_site_id
AND   hps.party_site_id = hpsu.party_site_id 
AND   hcsu.site_use_code = hpsu.site_use_type
AND   hp.party_id = party_id
AND   hcas.org_id = org_id;

Monday, September 26, 2011

DBMS_JOB

Submitted/scheduled job can be found in:
dba_jobs
Running jobs can be found in:
dba_jobs_running
Remove a job:
dbms_job.remove(jobno);
DBMS_JOB have been deprecated and replaced by DBMS_SCHEDULER (available from 10.1). Read more about DBMS_SCHEDULER here.

Tuesday, September 20, 2011

Automatic deqeuing with multi level XML (Advanced Queing)

Using Advanced Queing is a good idea when you have some integration or other stuff you want to execute asynchronous. With Advanced Queing it's also possible to automte the deque process using a subscriber. This means, as soon as you put anything on the que it will be dequed as soon as possible.

The below example will illustrate that. The code will also show how to read a muli level XML using PL/SQL.

Create que table (also stops the que and drops the que table if it's existing).
BEGIN
  BEGIN
    DBMS_AQADM.STOP_QUEUE(queue_name => 'XXDEMO_INV_QUE');
  EXCEPTION
    WHEN others THEN
      NULL;
  END;

  BEGIN
    DBMS_AQADM.DROP_QUEUE(queue_name => 'XXDEMO_INV_QUE');
  EXCEPTION
    WHEN others THEN
      NULL;
  END;

  BEGIN
    DBMS_AQADM.DROP_QUEUE_TABLE(queue_table => 'XXDEMO_INV_AQTAB');
  EXCEPTION
    WHEN others THEN
      NULL;
  END;

  DBMS_AQADM.CREATE_QUEUE_TABLE (
    queue_table        => 'XXDEMO_INV_AQTAB',
    queue_payload_type => 'SYS.XMLtype',
    multiple_consumers => TRUE);
END;
Create and start the que.
BEGIN
  DBMS_AQADM.CREATE_QUEUE (
    queue_name  => 'XXDEMO_INV_QUE',
    queue_table => 'XXDEMO_INV_AQTAB');

  DBMS_AQADM.START_QUEUE (
    queue_name => 'XXDEMO_INV_QUE');
END;
Create tables to save the message and the detailed information from the XML.
DROP TABLE xxdemo_AQ_mess_table;
DROP TABLE xxdemo_AQ_data_table_head;
DROP TABLE xxdemo_AQ_data_table_det;

CREATE TABLE xxdemo_AQ_mess_table (message       XMLTYPE,
                                   creation_date DATE);

CREATE TABLE xxdemo_AQ_data_table_head (id            NUMBER,
                                        first         VARCHAR2(600),
                                        last          VARCHAR2(600),
                                        creation_date DATE);

CREATE TABLE xxdemo_AQ_data_table_det (id            NUMBER,
                                       address       VARCHAR2(600),
                                       creation_date DATE);

To get the automatic dequing functionality to work we need to add a subscriber and register a procedure with the logic we want to execute.
BEGIN
   DBMS_AQADM.ADD_SUBSCRIBER (
      queue_name => 'XXDEMO_INV_QUE',
      subscriber => SYS.AQ$_AGENT('xxdemo_queue_subscriber',
                                   NULL,
                                   NULL));

    DBMS_AQ.REGISTER (SYS.AQ$_REG_INFO_LIST(SYS.AQ$_REG_INFO('XXDEMO_INV_QUE:xxdemo_queue_subscriber',
                                                              DBMS_AQ.NAMESPACE_AQ,
                                                             'plsql://xxdemo_AQ_callback_proc',
                                                              HEXTORAW('FF'))
                                           ),1);
END;
The procedure that will execute.
create or replace
PROCEDURE xxdemo_AQ_callback_proc(context  RAW,
                                  reginfo  SYS.AQ$_REG_INFO,
                                  descr    SYS.AQ$_DESCRIPTOR,
                                  payload  RAW,
                                  payloadl NUMBER) AS

   r_dequeue_options    DBMS_AQ.DEQUEUE_OPTIONS_T;
   r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
   v_message_handle     RAW(16);
   v_xmldata            xmltype;

BEGIN

   r_dequeue_options.msgid := descr.msg_id;
   r_dequeue_options.consumer_name := descr.consumer_name;

   -- deque message
   DBMS_AQ.DEQUEUE(
      queue_name         => descr.queue_name,
      dequeue_options    => r_dequeue_options,
      message_properties => r_message_properties,
      payload            => v_xmldata,
      msgid              => v_message_handle);

   -- insert raw message into table for reference
   INSERT INTO xxdemo_AQ_mess_table (message, creation_date)
   VALUES (v_xmldata, SYSDATE);

  /*********************************************************
  * Inserts into master and details table with 1 statemant *
  **********************************************************/
  INSERT ALL
    WHEN rn = 1 THEN
      INTO xxdemo_AQ_data_table_head VALUES (id, first, last)
    WHEN address IS NOT NULL THEN
      INTO xxdemo_AQ_data_table_det VALUES (id, address)
  SELECT row_number() over (PARTITION BY id ORDER BY null) rn,
         id,
         first,
         last,
         address
  FROM (SELECT EXTRACTVALUE(VALUE(headers), '//ID') id,
               EXTRACTVALUE(VALUE(headers), '//VALUE1') first,
               EXTRACTVALUE(VALUE(headers), '//VALUE2') last,
               EXTRACTVALUE (VALUE(details), '*/ADDRESS') address
          FROM TABLE(XMLSEQUENCE(EXTRACT(v_xmldata, '*/INVOICE'))) headers,
               TABLE(XMLSEQUENCE(EXTRACT(VALUE(headers), '*/DISTRIBUTION'))) details);

  /**********************************
  * The same as above but with loop *
  ***********************************/
  --FOR rec in (SELECT row_number() over (PARTITION BY id ORDER BY NULL) rn,
  --                   id,
  --                   first,
  --                   last,
  --                   address
  --            FROM (SELECT EXTRACTVALUE(VALUE(headers), '//ID') id,
  --                         EXTRACTVALUE(VALUE(headers), '//VALUE1') first,
  --                         EXTRACTVALUE(VALUE(headers), '//VALUE2') last,
  --                         EXTRACTVALUE (VALUE(details), '*/ADDRESS') address
  --            FROM TABLE(XMLSEQUENCE(EXTRACT(v_xmldata, '*/INVOICE'))) headers,
  --                 TABLE (XMLSEQUENCE(EXTRACT(VALUE(headers), '*/DISTRIBUTION'))) details)) LOOP
  --
  --  IF rec.rn = 1 THEN
  --    INSERT INTO xxdemo_AQ_data_table_head VALUES (rec.id, rec.first, rec.last, SYSDATE);
  --  END IF;
  --
  --  IF rec.address IS NOT NULL THEN
  --    INSERT INTO xxdemo_AQ_data_table_det VALUES (rec.id, rec.address, SYSDATE);
  --  END IF;
  --
  --END LOOP;
  COMMIT;
END xxdemo_AQ_callback_proc;
Test by putting a message on the que.
DECLARE
  r_enqueue_options    DBMS_AQ.ENQUEUE_OPTIONS_T;
  r_message_properties DBMS_AQ.MESSAGE_PROPERTIES_T;
  v_message_handle     RAW(16);
  v_data               CLOB;
  v_xmldata            XMLTYPE;
BEGIN

  DELETE FROM xxdemo_AQ_data_table_head;
  DELETE FROM xxdemo_AQ_data_table_det;

  v_data := '<?xml version="1.0"?><DATA>';
  v_data := v_data||'<INVOICE><ID>1</ID><VALUE1>Daniel</VALUE1><VALUE2>Borgstrom</VALUE2><DISTRIBUTION><ADDRESS>1 Broadway</ADDRESS></DISTRIBUTION><DISTRIBUTION><ADDRESS>26 Wall Street</ADDRESS></DISTRIBUTION></INVOICE>';
  v_data := v_data||'<INVOICE><ID>2</ID><VALUE1>Sven</VALUE1><VALUE2>Svensson</VALUE2><DISTRIBUTION><ADDRESS>23 Houston Street</ADDRESS></DISTRIBUTION></INVOICE>';
  v_data := v_data||'<INVOICE><ID>3</ID><VALUE1>Tom</VALUE1><VALUE2>Olsson</VALUE2><DISTRIBUTION><ADDRESS>44 Lexington Ave</ADDRESS></DISTRIBUTION></INVOICE>';
  v_data := v_data||'<INVOICE><ID>4</ID><VALUE1>Arne</VALUE1><VALUE2>Jonsson</VALUE2><DISTRIBUTION><ADDRESS>81 Rue de Paris</ADDRESS></DISTRIBUTION><DISTRIBUTION><ADDRESS>71 Champs Elysee</ADDRESS></DISTRIBUTION></INVOICE>';
  v_data := v_data||'</DATA>';

  v_xmldata := xmltype(v_data);

   DBMS_AQ.ENQUEUE(
      queue_name         => 'XXDEMO_INV_QUE',
      enqueue_options    => r_enqueue_options,
      message_properties => r_message_properties,
      payload            => v_xmldata,
      msgid              => v_message_handle);

  COMMIT;

END;
When the que has processed the message data should appear in xxdemo_AQ_mess_table, xxdemo_AQ_data_table_head and xxdemo_AQ_data_table_det.

Monday, September 19, 2011

Disable Forms Personalization

Sometimes when you are developing a Forms Personalization it will error out before the form is opened. When this happens you cannot disable custom code to get the form to open and fix the problem.

The easiest way to fix this is to disable it directly in the core table.
UPDATE fnd_form_custom_actions SET enabled = 'N' WHERE action_id = your action id;
Now your form will open and you can fix the problem.

Friday, August 26, 2011

Native XML (BI) Publisher Report

This post describes how to create a report using XML Publisher in Oracle E-Business Suite.
Traditionally when a XML Publisher report has been created Oracle Reports have been the engine to
produce the XML. A template has then been developed to use the created XML. This way of working
is only recommended when the Oracle Report is already available and a new layout is created. If a
new report is created from scratch you should use the XML Publisher engine to create both the XML
and the layout. It is possible to use this method in both 11.5.10 and R12.

How to create a native XML Publisher report
The query and parameters is created in a XML-document called Data Template.
Example of a Data Template:
<?xml version="1.0" encoding="WINDOWS-1252" ?>
<dataTemplate name="CUST_LIST" description="Orderdetail per customer" version="1.0">
<parameters>
<parameter name="p_fr_datum" datatype="character"/>
<parameter name="p_till_datum" datatype="character"/>
<parameter name="p_ordertyp" datatype="character"/>
<parameter name="p_status" datatype="character"/>
<parameter name="p_kundnr" datatype="number"/>
<parameter name="p_kst" datatype="varchar2"/>
</parameters>
<dataQuery>
<sqlStatement name="Q_param">
  SELECT TO_CHAR(TO_DATE(SUBSTR(:p_fr_datum,1,10),'yyyy/mm/dd'),'yyyy-mm-dd') fr_datum,
         TO_CHAR(TO_DATE(SUBSTR(:p_till_datum,1,10),'yyyy/mm/dd'),'yyyy-mm-dd') ti_datum,
        (SELECT name FROM oe_transaction_types_vl WHERE transaction_type_id = :p_ordertyp) otyp,
        (SELECT meaning FROM oe_lookups WHERE lookup_type = 'FLOW_STATUS' AND lookup_code = :p_status) status,
        (SELECT party.party_name||' ('||cust.account_number||')' kund FROM hz_cust_accounts cust, hz_parties party WHERE cust.party_id = party.party_id AND cust.account_number = :p_kundnr) kund
   FROM dual
</sqlStatement>
<sqlStatement name="Q1">
  SELECT h.customer_number kundnr,
         h.sold_to kundnamn,
         h.ship_to_location leveransid,
         h.order_number ordernummer,
         h2.order_number avtalsnummer,
         l.ordered_item artikel,
         i.description artikelnamn,
         l.ship_to_address1 lev_adress_1,
         l.ship_to_address2 lev_adress_2,
         l.ship_to_address3 lev_adress_3,
         l.ship_to_address4 lev_adress_4,
         l.ship_to_address5 lev_adress_5,
         h.attribute7 kund_ref,
         h.attribute17 fakturaref
  FROM oe_order_headers_v h,
       oe_order_lines_v l,
       mtl_system_items_b i,
       oe_order_headers_all h2
  WHERE h.header_id = l.header_id
  AND   l.inventory_item_id = i.inventory_item_id
  ANd   i.organization_id = 101
  AND   h.ordered_date BETWEEN TO_DATE(SUBSTR(:p_fr_datum,1,10),'yyyy/mm/dd') AND TO_DATE(SUBSTR(:p_till_datum,1,10),'yyyy/mm/dd')
  AND   h.order_type_id = :p_ordertyp
  AND   h.source_document_id = h2.header_id (+)
  AND   h.flow_status_code = nvl(:p_status, h.flow_status_code)
  AND   h.customer_number = nvl(:p_kundnr, h.customer_number)
  AND   h2.attribute1 = nvl(:p_kst, h2.attribute1)
  ORDER BY h.order_number
</sqlStatement>
</dataQuery>
<dataStructure>
<group name="G_PARAM" source="Q_param">
<element name="FR_DATUM" value="FR_DATUM" />
<element name="TI_DATUM" value="TI_DATUM" />
<element name="OTYP" value="OTYP" />
<element name="STATUS" value="STATUS" />
<element name="KUND" value="KUND" />
</group>
<group name="G_CUST" source="Q1">
<element name="KUNDNR" value="KUNDNR" />
<element name="KUNDNAMN" value="KUNDNAMN"/>
<element name="LEVERANSID" value="LEVERANSID" />
<element name="ORDERNUMMER" value="ORDERNUMMER" />
<element name="AVTALSNUMMER" value="AVTALSNUMMER" />
<element name="ARTIKEL" value="ARTIKEL" />
<element name="ARTIKELNAMN" value="ARTIKELNAMN" />
<element name="LEV_ADRESS_1" value="LEV_ADRESS_1" />
<element name="LEV_ADRESS_2" value="LEV_ADRESS_2" />
<element name="LEV_ADRESS_3" value="LEV_ADRESS_3" />
<element name="LEV_ADRESS_4" value="LEV_ADRESS_4" />
<element name="LEV_ADRESS_5" value="LEV_ADRESS_5" />
<element name="KUND_REF" value="KUND_REF" />
<element name="FAKTURAREF" value="FAKTURAREF" />
</group>
</dataStructure>
</dataTemplate>
How to develop a Data Template is described in detail in Oracle XML Publisher Administration and Developers Guide.

The Data Template is uploaded under the Data Definition under the XML Publisher Administrator responsibility.


The next step is to set up the concurrent request so the report can be run with XML output. The XML is needed to develop the template.


Three things are important to set when the request is created:
1. The Short Name must have the same value as the Data Definition Code.
2. The Executable Name must have the value of XDODTEXE.
3. The Output Format must have the value of XML.

Now it is possible to run the concurrent Request and (1) validate that the Data Template is working as expected and (2) verify the produced XML output and use it to develop the template.

When the template is created and uploaded under Templates in the XML Publisher Administrator responsibility it is possible to run the request and see the final result.


One thing is important to set when the Template is created:
1. The Template Code must have the same value as the Data Definition Code.

Sources
• Oracle XML Publisher Administration and Developers Guide
• Oracle XML Publisher Report Designer's Guide

Thursday, August 25, 2011

Get your ORGs...

To list your organizations in EBS run

select * from hr_all_organization_units;
select * from hr_all_organization_units_tl;

Tuesday, August 23, 2011

Set MOAC context (R12)

To set the MOAC (Multiorg Access Control) context in your database session (SQL*PLUS, TOAD, SQL Developer etc) use:
begin
  mo_global.set_policy_context('S', <orgID>);
end;
When policy context is set to M (Multi), data from all accessible Operating Units will be returned. When policy context is set to S (Single), then only data from the specified org_id will be returned.

Set language:
alter session set nls_language = 'SWEDISH';

Monday, August 22, 2011

Clear buffer cache

When you are working with performance issues you need to have an empty database cache to get a "real" result from your query. If you run a query which runs for 2 minutes the first time it would run very much faster the second time. To prevent the database to fetch the result from the cache you need to clear the buffer cache.

Run the command below to flush the cache (you need a DB-user which has sufficient privileges, for example system)
alter system flush buffer_cache;
Note: this should not be done in any production enviroment.

Tuesday, August 16, 2011

Creating a PL/SQL based webservice with a XMLType in/out parameter (EBS 12.1.1)

Out of the box can we not create a webservice that have a parameter (in or out) of type XMLType using SOA Gateway. When the service is called you will get an error.

In-parameter:
Error Description:  Error occured while service was being generated. 
Error Details:  oracle.apps.fnd.soa.util.SOAException: ServiceGenerationError: Exception returned from JCA Service Runtime.

    Missing class: oracle.xdb.XMLType

  Dependent class: oracle.tip.adapter.db.sp.oracle.TypeConverter
           Loader: AppsSOAAdapter:0.0.0
      Code-Source: /u02/oracle/VISION2/apps/tech_st/10.1.3/j2ee/oafm/connectors/AppsSOAAdapter/AppsSOAAdapter/DBAdapter.jar
    Configuration:  in /u02/oracle/VISION2/apps/tech_st/10.1.3/j2ee/oafm/connectors/AppsSOAAdapter/AppsSOAAdapter

The missing class is available from the following locations:

  1. Code-Source: /u02/oracle/VISION2/apps/tech_st/10.1.3/rdbms/jlib/xdb.jar (from  in /u02/oracle/VISION2/apps/apps_st/comn/webapps/oafm/)
     This code-source is available in loader oafm.root:0.0.0. 

  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.invoke(JCAHandler.java:222)
  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.handleRequest(JCAHandler.java:153)
  at oracle.apps.fnd.soa.provider.SOAProvider.processMessage(SOAProvider.java:295)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doEndpointProcessing(ProviderProcessor.java:956)
  at oracle.j2ee.ws.server.WebServiceProcessor$1.run(WebServiceProcessor.java:358)
  at java.security.AccessController.doPrivileged(Native Method)
  at javax.security.auth.Subject.doAs(Subject.java:396)
  at oracle.j2ee.ws.server.WebServiceProcessor.invokeEndpointImplementation(WebServiceProcessor.java:355)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doRequestProcessing(ProviderProcessor.java:466)
  at oracle.j2ee.ws.server.WebServiceProcessor.processRequest(WebServiceProcessor.java:114)
  at oracle.j2ee.ws.server.WebServiceProcessor.doService(WebServiceProcessor.java:96)
  at oracle.j2ee.ws.server.WebServiceServlet.doPost(WebServiceServlet.java:194)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
  at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:713)
  at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:370)
  at com.evermind.server.http.HttpRequestHandler.doProcessRequest(HttpRequestHandler.java:871)
  at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:453)
  at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:313)
  at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:199)
  at oracle.oc4j.network.ServerSocketReadHandler$SafeRunnable.run(ServerSocketReadHandler.java:260)
  at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:303)
  at java.lang.Thread.run(Thread.java:619)
oracle.apps.fnd.soa.util.SOAException: ServiceGenerationError: Exception returned from JCA Service Runtime.

    Missing class: oracle.xdb.XMLType

  Dependent class: oracle.tip.adapter.db.sp.oracle.TypeConverter
           Loader: AppsSOAAdapter:0.0.0
      Code-Source: /u02/oracle/VISION2/apps/tech_st/10.1.3/j2ee/oafm/connectors/AppsSOAAdapter/AppsSOAAdapter/DBAdapter.jar
    Configuration:  in /u02/oracle/VISION2/apps/tech_st/10.1.3/j2ee/oafm/connectors/AppsSOAAdapter/AppsSOAAdapter

The missing class is available from the following locations:

  1. Code-Source: /u02/oracle/VISION2/apps/tech_st/10.1.3/rdbms/jlib/xdb.jar (from  in /u02/oracle/VISION2/apps/apps_st/comn/webapps/oafm/)
     This code-source is available in loader oafm.root:0.0.0. 

  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.invoke(JCAHandler.java:222)
  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.handleRequest(JCAHandler.java:153)
  at oracle.apps.fnd.soa.provider.SOAProvider.processMessage(SOAProvider.java:295)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doEndpointProcessing(ProviderProcessor.java:956)
  at oracle.j2ee.ws.server.WebServiceProcessor$1.run(WebServiceProcessor.java:358)
  at java.security.AccessController.doPrivileged(Native Metho

Out-parameter:
Error Description  Error occured while service was being generated. 
Error Details  oracle.apps.fnd.soa.util.SOAException: ServiceGenerationError: Exception returned from JCA Service Runtime.oracle/classloader/util/AnnotatedNoClassDefFoundError
  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.invoke(JCAHandler.java:222)
  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.handleRequest(JCAHandler.java:153)
  at oracle.apps.fnd.soa.provider.SOAProvider.processMessage(SOAProvider.java:295)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doEndpointProcessing(ProviderProcessor.java:956)
  at oracle.j2ee.ws.server.WebServiceProcessor$1.run(WebServiceProcessor.java:358)
  at java.security.AccessController.doPrivileged(Native Method)
  at javax.security.auth.Subject.doAs(Subject.java:396)
  at oracle.j2ee.ws.server.WebServiceProcessor.invokeEndpointImplementation(WebServiceProcessor.java:355)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doRequestProcessing(ProviderProcessor.java:466)
  at oracle.j2ee.ws.server.WebServiceProcessor.processRequest(WebServiceProcessor.java:114)
  at oracle.j2ee.ws.server.WebServiceProcessor.doService(WebServiceProcessor.java:96)
  at oracle.j2ee.ws.server.WebServiceServlet.doPost(WebServiceServlet.java:194)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
  at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:713)
  at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:370)
  at com.evermind.server.http.HttpRequestHandler.doProcessRequest(HttpRequestHandler.java:871)
  at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:453)
  at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:313)
  at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:199)
  at oracle.oc4j.network.ServerSocketReadHandler$SafeRunnable.run(ServerSocketReadHandler.java:260)
  at com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableResourcePooledExecutor.java:303)
  at java.lang.Thread.run(Thread.java:619)
oracle.apps.fnd.soa.util.SOAException: ServiceGenerationError: Exception returned from JCA Service Runtime.oracle/classloader/util/AnnotatedNoClassDefFoundError
  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.invoke(JCAHandler.java:222)
  at oracle.apps.fnd.soa.provider.services.jca.JCAHandler.handleRequest(JCAHandler.java:153)
  at oracle.apps.fnd.soa.provider.SOAProvider.processMessage(SOAProvider.java:295)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doEndpointProcessing(ProviderProcessor.java:956)
  at oracle.j2ee.ws.server.WebServiceProcessor$1.run(WebServiceProcessor.java:358)
  at java.security.AccessController.doPrivileged(Native Method)
  at javax.security.auth.Subject.doAs(Subject.java:396)
  at oracle.j2ee.ws.server.WebServiceProcessor.invokeEndpointImplementation(WebServiceProcessor.java:355)
  at oracle.j2ee.ws.server.provider.ProviderProcessor.doRequestProcessing(ProviderProcessor.java:466)
  at oracle.j2ee.ws.server.WebServiceProcessor.processRequest(WebServiceProcessor.java:114)
  at oracle.j2ee.ws.server.WebServiceProcessor.doService(WebServiceProcessor.java:96)
  at oracle.j2ee.ws.server.WebServiceServlet.doPost(WebServiceServlet.java:194)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:763)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
  at com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispatcher.java:713)
  at com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletRequestDispatcher.java:370)
  at com.evermind.server.http.HttpRequestHandler.doProcessRequest(HttpRequestHandler.java:871)
  at com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandler.java:453)
  at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:313)
  at com.evermind.server.http.AJPRequestHandler.run(AJPRequestHandler.java:199)
  at oracle.oc4j.network.ServerSo

To fix this we need to include xdb.jar in the oc4j.jar.
  1. Shutdown OC4J ($ADMIN_SCRIPTS_HOME/adopmnctl.sh stopall)
  2. Go to $ORACLE_HOME/j2ee/home (make sure that you are in the 10.1.3 folder, NOT 10.1.2)
  3. Make a backup of file oc4j.jar
  4. Copy file oc4j.jar to a temp folder
  5. Extract jar file
    jar xf oc4j.jar
  6. Edit file META-INF/boot.xml
    - In the shared library section called oracle.xml (<shared-library name="oracle.xml" parent="api" version="10.1.0_2">) look for the line <code-source path="${oracle.home}/rdbms/jlib/xdb.jar"/>
    - If the line is missing, then add the line to the section
    - Double check that xdb.jar exists in $ORACLE_HOME/rdbms/jlib/ (10.1.3 folder)
  7. Re-packaged boot.xml into oc4j.jar with path meta-inf
    jar uf oc4j.jar META-INF/boot.xml
  8. Copy the new oc4j.jar to $ORACLE_HOME/j2ee/home (10.1.3 folder)
  9. Restart OC4J ($ADMIN_SCRIPTS_HOME/adopmnctl.sh startall)
javascript:void(0)