Wednesday, September 30, 2009

Oracle BI Publisher aka XML Publisher within E-Business Oracle Apps

Oracle XML Publisher

MOAC Show

MOAC Knowledge Shariing

OA Framework - The Onion Stack

 

Where to get Jad for download

http://www.varaneckas.com/jad

How to attach a "Web Page" URL attachment to a Payables Invoice via FND Document Attachment Private API.

How to attach a "Web Page" URL attachment to a Payables Invoice via FND Document Attachment Private API.
To use this code there are a few things that you'll need to change:

In the fnd_global call change the variables to your required user_id, resp_id, resp_appl_id, or comment the call if not needed see my post if you're unsure of this
The l_pk1_value which is ap_invoices_all.invoice_id
The l_filename and l_description variables
Possibly l_category_id: create an real example, check out examine and find the category_id you need to use.
Remember to commit!
This code has been tested against 11.5.10.2, if you have a different version this may have changed. Note this is a customization via a private API so is unsupported.
declare
l_rowid rowid;
l_attached_document_id number;
l_document_id number;
l_media_id number;
l_category_id number := 291; -- Invoice Internal
l_pk1_value fnd_attached_documents.pk1_value%TYPE := '63227';
l_description fnd_documents_tl.description%TYPE := 'Gareth Document Attach Demo';
l_filename fnd_documents_tl.file_name%TYPE := 'http://www.oracle.com/index.html';
l_seq_num number;
begin
-- Setup applications session
-- User = OPERATIONS
-- Resp = Payables, Vision Operations
-- App = Payables
fnd_global.apps_initialize(1318,50554,200);

select FND_DOCUMENTS_S.nextval
into l_document_id
from dual;

select FND_ATTACHED_DOCUMENTS_S.nextval
into l_attached_document_id
from dual;

select nvl(max(seq_num),0) + 10
into l_seq_num
from fnd_attached_documents
where pk1_value = l_pk1_value
and entity_name = 'AP_INVOICES';

fnd_documents_pkg.insert_row
( X_ROWID => l_rowid
, X_DOCUMENT_ID => l_document_id
, X_CREATION_DATE => sysdate
, X_CREATED_BY => fnd_profile.value('USER_ID')
, X_LAST_UPDATE_DATE => sysdate
, X_LAST_UPDATED_BY => fnd_profile.value('USER_ID')
, X_LAST_UPDATE_LOGIN => fnd_profile.value('LOGIN_ID')
, X_DATATYPE_ID => 5 -- Web Page
, X_CATEGORY_ID => l_category_id
, X_SECURITY_TYPE => 2
, X_PUBLISH_FLAG => 'Y'
, X_USAGE_TYPE => 'O'
, X_LANGUAGE => 'US'
, X_DESCRIPTION => l_description
, X_FILE_NAME => l_filename
, X_MEDIA_ID => l_media_id
);

fnd_documents_pkg.insert_tl_row
( X_DOCUMENT_ID => l_document_id
, X_CREATION_DATE => sysdate
, X_CREATED_BY => fnd_profile.value('USER_ID')
, X_LAST_UPDATE_DATE => sysdate
, X_LAST_UPDATED_BY => fnd_profile.value('USER_ID')
, X_LAST_UPDATE_LOGIN => fnd_profile.value('LOGIN_ID')
, X_LANGUAGE => 'US'
, X_DESCRIPTION => l_description
, X_FILE_NAME => l_filename
, X_MEDIA_ID => l_media_id
);

fnd_attached_documents_pkg.insert_row
( X_ROWID => l_rowid
, X_ATTACHED_DOCUMENT_ID => l_attached_document_id
, X_DOCUMENT_ID => l_document_id
, X_CREATION_DATE => sysdate
, X_CREATED_BY => fnd_profile.value('USER_ID')
, X_LAST_UPDATE_DATE => sysdate
, X_LAST_UPDATED_BY => fnd_profile.value('USER_ID')
, X_LAST_UPDATE_LOGIN => fnd_profile.value('LOGIN_ID')
, X_SEQ_NUM => l_seq_num
, X_ENTITY_NAME => 'AP_INVOICES'
, X_COLUMN1 => null
, X_PK1_VALUE => l_pk1_value
, X_PK2_VALUE => null
, X_PK3_VALUE => null
, X_PK4_VALUE => null
, X_PK5_VALUE => null
, X_AUTOMATICALLY_ADDED_FLAG => 'N'
, X_DATATYPE_ID => 5
, X_CATEGORY_ID => l_category_id
, X_SECURITY_TYPE => 2
, X_PUBLISH_FLAG => 'Y'
, X_LANGUAGE => 'US'
, X_DESCRIPTION => l_description
, X_FILE_NAME => l_filename
, X_MEDIA_ID => l_media_id
);
end;
/
Where to the actual attachments/documents get stored for attachments?
Here are some queries to get back the Payables Invoice attachments of category "Invoice Internal" for a given invoice. Attachments of type Web Page (URL or Filename)

select fad_f.seq_num
, fdt_f.file_name media_data_text
from fnd_attached_documents fad_f
, fnd_documents fd_f
, fnd_documents_tl fdt_f
, fnd_document_categories_tl fdct_f
where 1 = 1
and fad_f.document_id = fd_f.document_id
and fad_f.document_id = fdt_f.document_id
and fdct_f.category_id = fd_f.category_id
and fdct_f.user_name = 'Invoice Internal'
and fd_f.datatype_id = 5
and fad_f.entity_name = 'AP_INVOICES'
and fad_f.pk1_value = '63227';
Attachments of type "Long Text"

select fad_f.seq_num
, fdlt_f.media_id media_id
, fdlt_f.long_text media_data_text
from fnd_attached_documents fad_f
, fnd_documents fd_f
, fnd_documents_tl fdt_f
, fnd_document_categories_tl fdct_f
, fnd_documents_long_text fdlt_f
where 1 = 1
and fad_f.document_id = fd_f.document_id
and fad_f.document_id = fdt_f.document_id
and fdct_f.category_id = fd_f.category_id
and fdt_f.media_id = fdlt_f.media_id
and fdct_f.user_name = 'Invoice Internal'
and fad_f.entity_name = 'AP_INVOICES'
and fad_f.pk1_value = '63227';
Attachments of type "Short Text"

select fad_f.seq_num
, fdst_f.media_id media_id
, fdst_f.short_text media_data_text
from fnd_attached_documents fad_f
, fnd_documents fd_f
, fnd_documents_tl fdt_f
, fnd_document_categories_tl fdct_f
, fnd_documents_short_text fdst_f
where 1 = 1
and fad_f.document_id = fd_f.document_id
and fad_f.document_id = fdt_f.document_id
and fdct_f.category_id = fd_f.category_id
and fdt_f.media_id = fdst_f.media_id
and fdct_f.user_name = 'Invoice Internal'
and fad_f.entity_name = 'AP_INVOICES'
and fad_f.pk1_value = '63227';
Attachments of type "File"

select fad_l.seq_num
, fl_l.file_id media_id
, fl_l.file_data media_data_blob
from fnd_attached_documents fad_l
, fnd_documents fd_l
, fnd_documents_tl fdt_l
, fnd_document_categories_tl fdct_l
, fnd_lobs fl_l
where 1 = 1
and fad_l.document_id = fd_l.document_id
and fad_l.document_id = fdt_l.document_id
and fdct_l.category_id = fd_l.category_id
and fdt_l.media_id = fl_l.file_id -- Release 11.x
-- and fd_l.media_id = fl_l.file_id -- Release 12.x
and fad_l.entity_name = 'AP_INVOICES'
and fdct_l.user_name = 'Invoice Internal'
and fad_l.pk1_value = '63227';
Update: Added extra line to file query for R12. Update: In case anyone needs to delete any attachments here's an example (thanks to Mark L):

declare
l_entity_name varchar2(20):= 'PO_LINES'; -- This defines the PO_LINES entity
l_pk1_value varchar2 (20) := '200487'; -- PO_LINE_ID items are attached to
l_delete_document_flag varchar2 (1) := 'Y'; -- Delete the document
begin
--fnd_global.apps_initialize(0,20420,1); -- SYSADMIN System Administrator
fnd_attached_documents2_pkg.delete_attachments
( X_entity_name => l_entity_name
, X_pk1_value => l_pk1_value
, X_delete_document_flag => l_delete_document_flag
);
end;
/
commit;

Tuesday, September 29, 2009

How To Add Shared Region To JRAD Notification REQAPPRV workflow

Author
Sai Narayan

Sai.narayan@asggroup.com.au

61-423821703

Applies to:
Oracle Applications - Version: 12.0.6 RDBMS – 10.2.0.4.0 Workflow Builder 2.6.3.5 JDeveloper 10.1.3.1.0 iProcurement patch level R12.ICX.A.6

Goal
How to add custom instructions/comments to a JRAD notification in REQAPPR workflow using OA Framework shared region?

Solution
JRAD notifications use OA framework region in their message HTML Body.

If we want to add custom instructions/comments to recipient using a JRAD notification, we can

1) either use the WF_NOTIFICATION message function to add some user comments into the notification header OR 2) we have to create a new OA Framework shared region and call it in the message HTML body

We could not use personalization because the instructions/comments have dynamic content and are generated at runtime.

Option 1 works and is easy to implement – but it offers no custom control over display format. It uses standard OraDataText css class which renders the instructions in bold.

Coming to Option 2, it gives more control over which css class to use to display the text.

As we were not happy with the option 1 due to the formatting/font, we had to go with Option 2.

Following is an outline of the steps followed to create a shared OA region and embed it within the JRAD notification.

Pre-requisite Setup for JDEVELOPER
Follow Oracle Applications Framework developer guide to setup database connection, JDEV_USER_HOME environment variables

Creating a new OA Workspace and project
1. Create a new OA Workspace in JDeveloper (Workspace configured for Oracle Applications)


2. Check the Add a New OA Project checkbox


Wizard will help you in creating the project Step 1 of 3


DET custom package name take the form CUSTOM.oracle.apps…. Step 2 of 3


Step 3 of 3


Here we have to select the .dbc file for the environment. We can ftp it from $FND_SECURE top on database tier. Select the user name and password for logon to EBS Select a application short name and responsibility key for the EBS The user selected should have been assigned the responsibility mentioned here

Creating a new shared region
Right click on the project and select New


Select New->OA Components->Region

Enter the details of the shared region

Name: Typically region names have an RN suffix Package: CUSTOM.oracle.apps.icx.por.wf.webui Style: stackLayout


Right click on the shared region structure and select New->Item


Select the item style as formattedText in the property inspector Enter the ID as NotificationComments1 Enter the CSS class as OraPromptText (this is driven by the display format of choice) We created 2 more items of the same style with a Spacer in between to cater for paragraphing. The message text can then be split and sent across to the shared region for display in multiple paragraphs for readability.


Creating a controller class
For the shared region created above, right click on it in the Structure window, and you can


Defaulting some data for the page fields usually goes into processRequest method. The following code essentially does the following basic activities

ü Calls the parent processRequest method
ü Looks for URL parameter , NotificationComments1
ü If the parameter has been passed and has a value, then it sets the formatted text field
of the same name with the contents of the parameter
ü It allows for 3 such comments parameters to support paragraphing for readability

/*=====================================================================

======+ | Copyright (c) 2001, 2005 Oracle Corporation, Redwood Shores, CA, USA | | All rights reserved. |

+====================================================================== =====+ | HISTORY |

+====================================================================== =====*/ package CUSTOM.oracle.apps.icx.por.wf.webui;

import oracle.apps.fnd.common.VersionInfo; import oracle.apps.fnd.framework.OAException; import oracle.apps.fnd.framework.webui.OAControllerImpl; import oracle.apps.fnd.framework.webui.OAPageContext; import oracle.apps.fnd.framework.webui.beans.OAFormattedTextBean; import oracle.apps.fnd.framework.webui.beans.OARawTextBean; import oracle.apps.fnd.framework.webui.beans.OAStaticStyledTextBean; import oracle.apps.fnd.framework.webui.beans.OAWebBean; import oracle.apps.fnd.framework.webui.beans.message.OAMessageStyledTextBean;

/**

* Controller for ...

*/ public class XXPORequisitionNtfnCO extends OAControllerImpl {

public static final String RCS_ID="$Header: XXPORequisitionNtfnCO.java 1.0 2009/07/03

14:46:00 snarayan noship $";;

public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion(RCS_ID, "%packagename%");

/**

*
Layout and page setup logic for a region.

*
@param pageContext the current OA page context

*
@param webBean the web bean corresponding to the region

*/ public void processRequest(OAPageContext pageContext, OAWebBean webBean) {

super.processRequest(pageContext, webBean); //If the notification comments 1 is not null, set the text field if (pageContext.getParameter("NotificationComments1") != null)

{ String userContent1 = pageContext.getParameter("NotificationComments1"); OAFormattedTextBean oaformattedtextbean1 =

(OAFormattedTextBean)webBean.findIndexedChildRecursive("NotificationComments1"); oaformattedtextbean1.setText(userContent1); }

//If the notification comments 2 is not null, set the text field if (pageContext.getParameter("NotificationComments2") != null)

{ String userContent2 = pageContext.getParameter("NotificationComments2"); OAFormattedTextBean oaformattedtextbean2 =

(OAFormattedTextBean)webBean.findIndexedChildRecursive("NotificationComments2"); oaformattedtextbean2.setText(userContent2); }

//If the notification comments 3 is not null, set the text field if (pageContext.getParameter("NotificationComments3") != null)

{ String userContent3 = pageContext.getParameter("NotificationComments3"); OAFormattedTextBean oaformattedtextbean3 =

(OAFormattedTextBean)webBean.findIndexedChildRecursive("NotificationComments3"); oaformattedtextbean3.setText(userContent3); }

}

/**

*
Procedure to handle form submissions for form elements in

*
a region.

*
@param pageContext the current OA page context

*
@param webBean the web bean corresponding to the region

*/ public void processFormRequest(OAPageContext pageContext, OAWebBean webBean) {

super.processFormRequest(pageContext, webBean);

}

}

Rightclick on .java class and click on Rebuild to compile it once code is done

ftp the controller java and class files to the following location:

/u01/ebsdev2/apps/apps_st/comn/java/classes/CUSTOM/oracle/apps/icx/por/wf/webui

This is basically $JAVA_TOP/CUSTOM/oracle/apps/icx/por/wf/webui

Importing XML page into Oracle MDS
All OA pages/regions have to be imported into the Oracle MDS repository

First ftp the xml file for the region to the respective product top/mds/… folder as in example below $XXPO_TOP/mds/oracle/apps/xxpo/icx/por/wf/webui/XXPORequisitionNtfnRN.xml

Note: The directory name highlighted in yellow tells the importer utility which application the page need to be registered under. So be careful to indicate the right application short code there!

Then, issue following command line utility to import the XML page definition into MDS repository:

java oracle.jrad.tools.xml.importer.XMLImporter $XXPO_TOP/mds/oracle/apps/xxpo /icx/por/wf/webui/XXPORequisitionNtfnRN.xml -rootdir $XXPO_TOP/mds/ -username apps password apps -dbconnection "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=e7359svsun034)(PORT=1546)) (CONNECT_DATA=(SERVICE_NAME = EBSDEV2)))"

Bounce OC4J components on web tier
This step is mandatory for java class file changes. If the OC4J components service is not bounced, latest changes to Java class are not reflected at runtime.

Register the shared region as a function in EBS
Standard process to register the shared region as a function using System Administrator resp

Notes: Function Type should be SSWA jsp function


Make sure to enter the HTML Call under the Web HTML tab


Invoking the shared region from the notification
In this case we are customizing the REQAPPRV workflow. We used Workflow Builder

2.6.3.5 to customize the workflow.

Within Workflow Builder and within the REQAPPRV item type, create a new item attribute of type Document and the Attribute Value will be JSP call to the OA function defined in EBS

JSP:/OA_HTML/OA.jsp?OAFunc=XXPO_ICX_POR_NTFN_COMMENTS&NotificationCo mments1=-&XXPO_NOTIFICATION_COMMENTS1-


In the HTML Message Body of JRAD notification message, put in the new attribute


References
Oracle Application Framework - Developer's Guide Release 12.0.4