This is the last article in the series “Custom Defaulting and Validation in iProcurement”. Prior to this I implemented (not so successfully) my requirement
of copying a DFF attribute value called ‘Fund’ on requisition header to a DFF attribute in requisition line during checkout process using POR_CUSTOM_PKG , and OAF extension of Application Module and Controller.
Limitations I had with the previous approaches are,
- POR_CUSTOM_PKG - 'custom_default_req_line' procedure is executed only when requisition is first created. The changes made to fund in requisition header there after are not copied to line.
- Extension of Application Module and Controller - By extending root application module (RequisitionAM) I faced a "Cannot Display Page" issue with all list of values in iProcurement. I was getting session time out on Lov regions. It is not advisable to extend rootAM unless you know your way out.
Before I implement my third approach, a short briefing on iProcurement architecture will help understand the interaction between different layers each time a page is displayed or information on page is submitted.
iProcurement Architecture Overview:
(Courtesy: 11.5.10: Oracle iProcurement Architecture Overview. Metalink Note: 313195.1)
Page Display Execution Flow
A typical execution of the processRequest method is explained below.
1. When a page is displayed, the OAF will automatically call the processRequest method on the Controller of a page. In certain cases, in addition to the statically rendered items on a page, there are dynamically controlled elements that are displayed based on other setup in the system. If this logic is simple, then the corresponding implementation would be in the Controller for the page (Step 1).
2. In many cases, the logic to determine the state of the dynamic elements on the page is sufficiently complex to warrant new Server Commands (refer to the “Server Command” section on Page 7 for more details) to encapsulate the logic. In this scenario, a call is made from the Controller to the Server Command via the corresponding Application Module (AM) for the transaction. The Application Module maintains a mapping of the Server Command names and the corresponding classes. The Controller passes the name of the Server Command to the Application Module, which in turn uses the mapping to execute the Server Command (Step 2).
3. The Server Command then calls the corresponding View Object (VO), which in turn calls the mapped Entity Object (EO), to retrieve the data required to determine which elements and data values to be displayed on the page (Steps 3, 4 and 5).
Page Submission Execution Flow
A typical execution of the processFormRequest method is explained below
1. When the data on the page is submitted (for e.g. when a button on the page is clicked), OAF calls the processFormRequest on the Controller for the page. In most cases, all the processing that needs to be done once a page is submitted is implemented in Server Commands (Step 1).
2. Depending on the event being processed by the Controller, the Controller passes the name of the Server Command to the Application Module, which in turn makes a call to the corresponding Server Command (Step 2).
3. In most cases, the data submitted on a page needs to be validated before the user proceeds to the next page in the flow. All the validation logic is implemented in Helper classes (refer to the “Helper” section on Page 14), which can be associated with one or more Entity Objects. The Server Command calls methods in the Helper classes to perform all the required validations on the page. Helpers might use additional criteria (Business Attribute Sets and Business Views as explained in Pages 10 and 11) to determine which validation needs to be performed on a given page (Steps 3, 4, 5 and 6).
Server Command Classes
A Server Command is a class that contains code that would normally be placed in an Application Module. The code is extracted out into a separate class to prevent the Application Module from becoming too big, ease maintenance, facilitate concurrent development and promote reuse (different Application Modules may be able to use the same Server Command class). For example, a Server Command class could contain the code used to populate/query the different VOs displayed on a particular page, or contain the code to apply changes to all the requisition lines.
Every Server Command should implement the ServerCommand interface (oracle.apps.icx.por.common.server). There is an abstract method 'execute' which has to be implemented in child classes.
At runtime, a Server Command is invoked by name. There are two methods in the RequisitionAM (inherited from parent class oracle.apps.icx.por.common.server.PorBaseAMImpl) that are used to invoke the Server Commands by name.
public Serializable executeServerCommand(String cmd, ArrayList args)
Parameters: cmd – Name of the Server Command that needs to be executed
args – List of parameters that are input to the Server Command
public Serializable executeServerCommand(String cmd)
Parameter: cmd – Name of the Server Command that needs to be executed
The Server Command can be invoked from the client-tier (Controller) through one of the above methods in the Application Module. With this architecture, all the logic/events on the user interface is handled via methods in the Server Commands, providing modularity and reuse.
A mapping class (oracle.apps.icx.por.common.PorClassMap) is used to locate the Server Command class by name.
Some of the Server Commands used in requisition checkout flow are CheckoutSummarySvrCmd, CheckoutLinesSvrCmd, ShoppingCartSvrCmd etc.
Helper Classes
There are 2 categories of Helpers – Entity Object Helpers and Server Command Helpers. Entity Object Helpers contain defaulting and validation logic for Entity Objects. Each EO Helper implements a particular interface related to the EO. An EO Helper can “help” more than one EO by implementing several EO Helper interfaces. Server Command Helpers (e.g. DataMappingHelper) contain reusable processing and validation logic that are part of a Server Command.
When an EO is created, each of the associated EO Helpers is responsible for providing the appropriate default values. Similarly, when an EO is validated, the validation is delegated to the Helpers.
Approach 3: Extending Server Command
To implement my requirement to copy header fund value to line fund, I will follow below high level steps to create custom Server Command class:
- Create a new Server Command class 'XxCustomSvrCmd' which implements oracle.apps.icx.por.common.server.ServerCommand
- Add method copyFundFromHeader to do custom defaulting.
- Create a new class mapping class which extends oracle.apps.icx.por.common.PorClassMap
- Add property name 'PorClassMap' to map it to new class map in RequisitionAM.xml
- Extend CheckoutSummaryCO to call XxCustomSvrCmd during events ‘Save’, ‘Submit’, and ‘Edit Lines’.
Implementation
- Create new Server Command class 'XxCustomSvrCmd' which implements oracle.apps.icx.por.common.server.ServerCommand
- Implement execute and executeMethodByName methods. executeMethodByName calls copyFundFromHeader if string parameter equals 'customDefault'
- copyFundFromHeader fetches header fund value in attribute15 from PoRequisitionHeadersVO and sets it to attribute15 in ReqSummaryVO. This logic is same as in previous article.
// Source File Name: XxCustomSvrCmd.java
package xx.oracle.apps.icx.por.req.server;
import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.OAException;
import com.sun.java.util.collections.ArrayList;
import java.io.Serializable;
import oracle.jbo.domain.Number;
import oracle.jdbc.driver.OracleCallableStatement;
import oracle.apps.fnd.framework.server.*;
import oracle.apps.icx.por.common.server.*;
import oracle.apps.icx.por.req.server.RequisitionAMImpl;
import oracle.apps.icx.por.req.server.PoRequisitionHeadersVOImpl;
import oracle.apps.icx.por.req.server.PoRequisitionHeadersVORowImpl;
import oracle.apps.icx.por.req.server.ReqSummaryVOImpl;
import oracle.apps.icx.por.req.server.ReqSummaryVORowImpl;
public class XxCustomSvrCmd
implements ServerCommand
{
public XxCustomSvrCmd()
{
}
/*
* Method: execute
* Author: Kishore Ryali
* Date: 11/24/2008
* Purpose:
* Called from customValidation method in XxCheckoutSummaryCO
*/
public Serializable execute(OAApplicationModuleImpl oaapplicationmoduleimpl, ArrayList arraylist)
{
RequisitionAMImpl requisitionamimpl = (RequisitionAMImpl)oaapplicationmoduleimpl;
OADBTransactionImpl oadbtransactionimpl = (OADBTransactionImpl)requisitionamimpl.getOADBTransaction();
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "execute.begin", 1);
if(arraylist == null || arraylist.size() == 0)
{
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "XxCustomSvrCmd executed with no method name.", 1);
Exception exception = new Exception("XxCustomSvrCmd executed with no method name.");
ErrorUtil.handleFatalException(oadbtransactionimpl, exception, this);
}
String s = (String)arraylist.get(0);
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "XxCustomSvrCmd - execute().begin, " + "methodName="+ s, 1);
arraylist.remove(0);
Serializable serializable = executeMethodByName(oadbtransactionimpl, requisitionamimpl, s, arraylist);
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "execute.end", 1);
return serializable;
}
protected Serializable executeMethodByName(OADBTransactionImpl oadbtransactionimpl, RequisitionAMImpl requisitionamimpl, String s, ArrayList arraylist)
{
if("customDefault".equals(s))
customDefault(oadbtransactionimpl, requisitionamimpl);
return null;
}
protected void customDefault(OADBTransactionImpl oadbtransactionimpl, RequisitionAMImpl requisitionamimpl)
{
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "customDefault.begin", 1);
copyFundFromHeader(oadbtransactionimpl, requisitionamimpl);
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "customDefault.end", 1);
}
/*
* Method: copyFundFromHeader
* Author: Kishore Ryali
* Date: 11/24/2008
* Purpose:
* Copies Header Fund Number Attr15 to Line Fund Number Att15
*/
protected void copyFundFromHeader(OADBTransactionImpl oadbtransactionimpl, RequisitionAMImpl requisitionamimpl)
{
if(oadbtransactionimpl.isLoggingEnabled(1))
{ oadbtransactionimpl.writeDiagnostics(this, "copyFundFromHeader.begin", 1);
oadbtransactionimpl.writeDiagnostics(this, "*** Xx Code for coping Fund Number from Req Header to Line ***", 1);
}
try
{
// Fetch Header Fund Number i.e Attr15
PoRequisitionHeadersVOImpl porequisitionheadersvoimpl = requisitionamimpl.getPoRequisitionHeadersVO();
PoRequisitionHeadersVORowImpl porequisitionheadersvorowimpl = (PoRequisitionHeadersVORowImpl)porequisitionheadersvoimpl.getCurrentRow();
String headerFund = porequisitionheadersvorowimpl.getAttribute15();
Number reqHeaderId = null;
String reqSumAtt15 = null;
String defaultFund = null;
ReqSummaryVOImpl reqsummaryvoimpl = requisitionamimpl.getReqSummaryVO();
ReqSummaryVORowImpl reqsummaryvorowimpl = (ReqSummaryVORowImpl)reqsummaryvoimpl.getCurrentRow();
reqHeaderId = reqsummaryvorowimpl.getRequisitionHeaderId();
reqSumAtt15 = reqsummaryvorowimpl.getAttribute15();
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "BEFORE> reqHeaderId=" + reqHeaderId + ",reqSumAtt15=" + reqSumAtt15, 1);
// Modified by Kishore Ryali on 12/09/2008
// Purpose: Fund DFF on Header is made not mandatory. So if Fund is left NULL,
// copy default fund number value i.e. 0000000000 i.e profile XX_DEFAULT_FUND_NUMBER to make
// account generation work.
if (headerFund == null)
{
// Fetch default fund number from profile
defaultFund = oadbtransactionimpl.getProfile("XX_DEFAULT_FUND_NUMBER");
reqsummaryvorowimpl.setAttribute15(defaultFund);
}
else
{
// Set Header Fund Number to Line Fund Number i.e. Attr15
reqsummaryvorowimpl.setAttribute15(headerFund);
}
reqHeaderId = reqsummaryvorowimpl.getRequisitionHeaderId();
reqSumAtt15 = reqsummaryvorowimpl.getAttribute15();
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "AFTER> reqHeaderId=" + reqHeaderId + ",reqSumAtt15=" + reqSumAtt15, 1);
}
catch(Exception exception)
{
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "Error=" + exception, 1);
throw new OAException("Error in XxCustomSvrCmd.copyFundFromHeader=" + exception);
//ErrorUtil.handleFatalException(getOADBTransaction(), exception, this);
}
if(oadbtransactionimpl.isLoggingEnabled(1))
{
oadbtransactionimpl.writeDiagnostics(this, "*** End of Xx Code for coping Fund Number from Req Header to Line ***", 1);
oadbtransactionimpl.writeDiagnostics(this, "copyFundFromHeader.end", 1);
}
}
public static final String RCS_ID = "$Header: XxCustomSvrCmd.java 115.30 2008/11/24 13:31:39 kryali noship $";
public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion("$Header: XxCustomSvrCmd.java 115.30 2008/11/24 13:31:39 kryali noship $", "xx.oracle.apps.icx.por.req.server");
}
- After custom Server Command is implemented, create a new mapping class 'XxClassMap' which extends oracle.apps.icx.por.common.PorClassMap. This new class is stored in xx.oracle.apps.icx.por.common directory.
- Override getClass method to create mapping for new Server Command class 'XxCustomSvrCmd'. Since I extended PorClassMap, mapping for seeded Server Commands are inherited.
// Source File Name: XxClassMap.java
package xx.oracle.apps.icx.por.common;
import oracle.apps.icx.por.common.PorClassMap;
import oracle.apps.fnd.common.VersionInfo;
public class XxClassMap extends PorClassMap
{
public XxClassMap()
{
}
public String getClass(String name)
{
if ("XxCustomSvrCmd".equals(name))
{
return "xx.oracle.apps.icx.por.req.server.XxCustomSvrCmd";
}
else
{
return (String)s_classNames.get(name);
}
}
public static final String RCS_ID = "$Header: XxClassMap.java 115.30 2008/11/24 13:31:39 kryali noship $";
public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion("$Header: XxClassMap.java 115.30 2008/11/24 13:31:39 kryali noship $", "xx.oracle.apps.icx.por.common");
}
- Now RequisitionAM should use mapping class 'XxClassMap' instead of 'PorClassMap' to get the location of Server Commands including 'XxCustomSvrCmd'. This is done by adding new property to RequisitionAM.xml. (Note: Take a copy of RequistionAM.xml in oracle.apps.icx.por.req.server, before changing it)
- In Properties element, add new property name 'PorClasMap' with value pointing to location of custom class map 'XxClassMap'. Everything else in RequisitionAM.xml stays the same.
- Extend CheckoutSummaryCO to override processFormRequest method to call XxServerCmd on the events ‘Save’, ‘Submit’, and ‘Edit Lines’.
- Server Command name 'XxCustomSvrCmd' is passed as a parameter along with 'customDefault' method name to executeServerCommand. This method is inherited by RequisitionAM from PorBaseAM. Using XxClassMap, RequisitionAM locates XxCustomSvrCmd and executes the logic in customDefault method.
// Source File Name: XxCheckoutSummaryCO.java
package xx.oracle.apps.icx.por.req.webui;
import com.sun.java.util.collections.ArrayList;
import oracle.apps.fnd.common.*;
import oracle.apps.fnd.framework.*;
import oracle.apps.fnd.framework.webui.*;
import oracle.apps.fnd.framework.webui.beans.*;
import oracle.apps.icx.por.req.webui.*;
public class XxCheckoutSummaryCO extends CheckoutSummaryCO
{
public XxCheckoutSummaryCO()
{
}
public void processFormRequest(OAPageContext oapagecontext, OAWebBean oawebbean)
{
OAApplicationModule oaapplicationmodule = oapagecontext.getApplicationModule(oawebbean);
if(oapagecontext.isLoggingEnabled(2))
oapagecontext.writeDiagnostics(this, "processFormRequest().begin", 2);
String s = oapagecontext.getParameter("event");
if(oapagecontext.isLoggingEnabled(1))
oapagecontext.writeDiagnostics(this, "*** Xx Code for Custom Defaulting and Validation in PFR event " + s + " ***", 1);
/*
* Execute below custom code on Edit Lines/Save/Submit/Next events
* Custom Validation on Deliver-To Location and Fund Number
* Custom Defaulting for copying Fund Number for Header DFF to Line DFF
*/
if("editLines".equals(s))
customDefault(oapagecontext, oaapplicationmodule);
if("save".equals(s))
customDefault(oapagecontext, oaapplicationmodule);
if("submit".equals(s))
customDefault(oapagecontext, oaapplicationmodule);
if("goto".equals(s))
customDefault(oapagecontext, oaapplicationmodule);
if(oapagecontext.isLoggingEnabled(1))
oapagecontext.writeDiagnostics(this, "*** End of Xx Code for Custom Defaulting and Validation in PFR event " + s + " ***", 1);
if(oapagecontext.isLoggingEnabled(2))
oapagecontext.writeDiagnostics(this, "processFormRequest().end", 2);
// TODO: Override this oracle.apps.icx.por.req.webui.CheckoutSummaryCO method
super.processFormRequest(oapagecontext, oawebbean);
}
/*
* Method: customDefault
* Author: Kishore Ryali
* Date: 11/24/2008
* Purpose:
* Custom Validation on Deliver-To Location and Fund Number
* Custom Defaulting for copying Fund Number for Header DFF to Line DFF
*/
protected void customDefault(OAPageContext oapagecontext, OAApplicationModule oaapplicationmodule)
{
ArrayList arraylist1 = new ArrayList(2);
// Call Custom Server Cmd 'XxCustomSvrCmd'
// RequisitionAM.xml is updated to Custom Property to include XxClassMap
arraylist1.add("customDefault");
executeServerCommand(oapagecontext, oaapplicationmodule, "XxCustomSvrCmd", arraylist1);
return;
// oaapplicationmodule.invokeMethod("copyFundFromHeader");
}
public static final String RCS_ID = "$Header: XxCheckoutSummaryCO.java 115.30 2008/11/24 13:31:39 kryali noship $";
public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion("$Header: XxCheckoutSummaryCO.java 115.30 2008/11/24 13:31:39 kryali noship $", "xx.oracle.apps.icx.por.req.webui");
}
- Upload custom files in JAVA_TOP into respective directories. Bounce Middle-Tier to reflect the changes.
- In Checkout: Requisition Information page, Personalize page is used to substitute XxCheckoutSummaryCO.
Though this approach is fairly complex with many steps, I could successfully achieve my requirement without effecting standard functionality. We can follow similar approach for extending Helper classes. por_custom_pkg is in fact invoked from Helper classes which implement Helper Interfaces.
If you have any other methods for doing custom validation and defaulting in iProcurement, please share with us in the comments section.
written by KrishnaKishoreT , August 12, 2009
I tried to use the approach you explained above to copy some Header DFFs to Line and I am getting an exception when the extended controller calls the 'executeServerCommand' function from 'customDefault'.
I have created the XxCustomSvrCmd and XxClassMap as was explained above. I also updated the RequisitionAM.xml file to have the below property:
The exception trace is as follows:
Fatal OAException
racle.apps.fnd.framework.OAException: Application: FND, Message Name: FND_GENERIC_MESSAGE. Tokens: MESSAGE = java.lang.NullPointerException; at oracle.apps.fnd.framework.OAException.wrapperException(OAException.java:891)
at oracle.apps.icx.por.common.server.ErrorUtil.handleFatalException(ErrorUtil.java:631)
at oracle.apps.icx.por.common.server.PorBaseAMImpl.executeServerCommand(PorBaseAMImpl.java:126)
at sun.reflect.GeneratedMethodAccessor335.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at oracle.apps.fnd.framework.server.OAUtility.invokeMethod(OAUtility.java:190)
at oracle.apps.fnd.framework.server.OAApplicationModuleImpl.invokeMethod(OAApplicationModuleImpl.java:70
at oracle.apps.icx.por.common.webui.ClientUtil.invokeMethod(ClientUtil.java:964)
at oracle.apps.icx.por.common.webui.PorBaseCOImpl.invokeMethod(PorBaseCOImpl.java:194)
at oracle.apps.icx.por.common.webui.PorBaseCOImpl.executeServerCommand(PorBaseCOImpl.java:112)
at oracle.apps.icx.por.req.webui.XxCheckoutSummaryCO.customDefault(XxCheckoutSummaryCO.java:65)
at oracle.apps.icx.por.req.webui.XxCheckoutSummaryCO.processFormRequest(XxCheckoutSummaryCO.java:39)
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequest(OAWebBeanHelper.java:810)
at oracle.apps.fnd.framework.webui.OAWebBeanContainerHelper.processFormRequest(OAWebBeanContainerHelper.java:363)
at oracle.apps.fnd.framework.webui.OAPageLayoutHelper.processFormRequest(OAPageLayoutHelper.java:1159)
at oracle.apps.fnd.framework.webui.beans.layout.OAPageLayoutBean.processFormRequest(OAPageLayoutBean.java:1579)
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequestChildren(OAWebBeanHelper.java:1022)
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequestChildren(OAWebBeanHelper.java:98
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequest(OAWebBeanHelper.java:843)
at oracle.apps.fnd.framework.webui.OAWebBeanContainerHelper.processFormRequest(OAWebBeanContainerHelper.java:363)
at oracle.apps.fnd.framework.webui.beans.form.OAFormBean.processFormRequest(OAFormBean.java:395)
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequestChildren(OAWebBeanHelper.java:1022)
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequestChildren(OAWebBeanHelper.java:98
at oracle.apps.fnd.framework.webui.OAWebBeanHelper.processFormRequest(OAWebBeanHelper.java:843)
at oracle.apps.fnd.framework.webui.OAWebBeanContainerHelper.processFormRequest(OAWebBeanContainerHelper.java:363)
at oracle.apps.fnd.framework.webui.beans.OABodyBean.processFormRequest(OABodyBean.java:363)
at oracle.apps.fnd.framework.webui.OAPageBean.processFormRequest(OAPageBean.java:2676)
at oracle.apps.fnd.framework.webui.OAPageBean.preparePage(OAPageBean.java:1683)
at oracle.apps.fnd.framework.webui.OAPageBean.preparePage(OAPageBean.java:509)
at oracle.apps.fnd.framework.webui.OAPageBean.preparePage(OAPageBean.java:430)
at _oa__html._OA._jspService(_OA.java:84)
at oracle.jsp.runtime.HttpJsp.service(HttpJsp.java:119)
at oracle.jsp.app.JspApplication.dispatchRequest(JspApplication.java:417)
at oracle.jsp.JspServlet.doDispatch(JspServlet.java:267)
at oracle.jsp.JspServlet.internalService(JspServlet.java:186)
at oracle.jsp.JspServlet.service(JspServlet.java:156)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:58
at org.apache.jserv.JServConnection.processRequest(JServConnection.java:456)
at org.apache.jserv.JServConnection.run(JServConnection.java:294)
at java.lang.Thread.run(Thread.java:534)
## Detail 0 ##
java.lang.NullPointerException
at oracle.apps.icx.por.common.server.PorBaseAMImpl.executeServerCommand(PorBaseAMImpl.java:122)
at sun.reflect.GeneratedMethodAccessor335.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang
Could you please let me know what the issue could be.
Thanks,
Krishna
written by KrishnaKishoreT , August 12, 2009
The property that i specified in RequisitionAM.xml is
Please find below the code for XxCustomSvrCmd and XxClassMap (its almost exactly your code)
XxClassMap.java
---------------------
// Source File Name: XxClassMap.java
package oracle.apps.icx.por.common;
import oracle.apps.icx.por.common.PorClassMap;
import oracle.apps.fnd.common.VersionInfo;
public class XxClassMap extends PorClassMap
{
public XxClassMap()
{
}
public String getClass(String name)
{
if ("XxCustomSvrCmd".equals(name))
{
return "oracle.apps.icx.por.req.server.XxCustomSvrCmd";
}
else
{
return (String)s_classNames.get(name);
}
}
public static final String RCS_ID = "$Header: XxClassMap.java 115.30 2009/08/12 13:31:39 kthatavarthy noship $";
public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion("$Header: XxClassMap.java 115.30 2009/08/12 13:31:39 kthatavarthy noship $", "oracle.apps.icx.por.common");
}
Thanks,
Krishna
written by KrishnaKishoreT , August 12, 2009
------------------------------
package oracle.apps.icx.por.req.server;
import....
public class XxCustomSvrCmd implements ServerCommand
{
public XxCustomSvrCmd()
{
}
public Serializable execute(OAApplicationModuleImpl oaapplicationmoduleimpl, ArrayList arraylist)
{
RequisitionAMImpl requisitionamimpl = (RequisitionAMImpl)oaapplicationmoduleimpl;
OADBTransactionImpl oadbtransactionimpl = (OADBTransactionImpl)requisitionamimpl.getOADBTransaction();
if(arraylist == null || arraylist.size() == 0)
{
if(oadbtransactionimpl.isLoggingEnabled(1))
oadbtransactionimpl.writeDiagnostics(this, "XxCustomSvrCmd executed with no method name.", 1);
Exception exception = new Exception("XxCustomSvrCmd executed with no method name.");
ErrorUtil.handleFatalException(oadbtransactionimpl, exception, this);
}
String s = (String)arraylist.get(0);
arraylist.remove(0);
Serializable serializable = executeMethodByName(oadbtransactionimpl, requisitionamimpl, s, arraylist);
return serializable;
}
protected Serializable executeMethodByName(OADBTransactionImpl oadbtransactionimpl, RequisitionAMImpl requisitionamimpl, String s, ArrayList arraylist)
{
if("customDefault".equals(s))
customDefault(oadbtransactionimpl, requisitionamimpl);
return null;
}
protected void customDefault(OADBTransactionImpl oadbtransactionimpl, RequisitionAMImpl requisitionamimpl)
{
copyHeaderDff(oadbtransactionimpl, requisitionamimpl);
}
protected void copyHeaderDff(OADBTransactionImpl oadbtransactionimpl, RequisitionAMImpl requisitionamimpl)
{
try
{
// Fetch Header Fund Number i.e Attr15
PoRequisitionHeadersVOImpl porequisitionheadersvoimpl = requisitionamimpl.getPoRequisitionHeadersVO();
PoRequisitionHeadersVORowImpl porequisitionheadersvorowimpl = (PoRequisitionHeadersVORowImpl)porequisitionheadersvoim pl.getCurrentRow();
String headerDept = porequisitionheadersvorowimpl.getAttribute6();
String headerAcct = porequisitionheadersvorowimpl.getAttribute7();
ReqSummaryVOImpl reqsummaryvoimpl = requisitionamimpl.getReqSummaryVO();
ReqSummaryVORowImpl reqsummaryvorowimpl = (ReqSummaryVORowImpl)reqsummaryvoimpl.getCurrentRow();
// Set Line DFFs Attr1 and Attr2 to Header Dept and Acct
reqsummaryvorowimpl.setAttribute1(headerDept);
reqsummaryvorowimpl.setAttribute2(headerAcct);
}
catch(Exception exception)
{
throw new OAException("Error in XxCustomSvrCmd.copyHeaderDff=" + exception);
public static final boolean RCS_ID_RECORDED = VersionInfo.recordClassVersion("$Header: XxCustomSvrCmd.java 115.30 2009/08/12 13:31:39 kthatavarthy noship $", "oracle.apps.icx.por.req.server");
}
written by KrishnaKishoreT , August 12, 2009
The server command is now being executed without any any errors and the requisition header dffs are being copied to the lines without any issues.
I had the apache bounced and it is working now!
Thanks,
Krishna
written by Steve , December 01, 2009
really nice written example. Thanks for sharing your ideas.
When I worked through this example a question comes up by mine.
You change the RequisitionAM.xml. What is if Oracle will deliver a new version
of RequestionAM.xml then the file will be overwritten.
Isn't it better or possible to make a substitution of this file in Jdeveloper
and after this use jpximport? Was it also necessary in your example using
jpximport because I can't read about this?
Thank you
written by Steve , December 02, 2009
I'm recreating this example and stuck by substitution of XxCheckoutSummaryCO. I've tried in Jdeveloper
under Project Properties/Business Components/Substitutions to substitute
oracle.apps.icx.por.req.webui.CheckoutSummaryCO
with
xx.oracle.apps.icx.por.req.webui.XxCheckoutSummaryCO
and want after this using JPXImporter
but I can't see the package path
xx.oracle.apps.icx.por.req.webui and
oracle.apps.icx.por.req.webui
There is only oracle.apps.fnd.framework.* shown. The path of
myprojects contains oracle.apps.icx.por.req.webui.CheckoutSummaryCO
I've also rebuilt this project in jdeveloper. How can I get displayed the icx-packages
for substitution in addition.
Thanks a lot
written by Steve , December 02, 2009
thank you very much for clarity.
regards Steve
written by Kumar NK , August 11, 2010
1.So what is the point in extending the AM apart from the fact that AM is on the server side and controller is on the client side.
2. Mainly I want to know the CONS or disadvantages in writing the code in controller directly without extending the AM.
written by Kumar NK , August 13, 2010
When we add the mapping class property to RequisitionAm.xml, We are altering the standard file. How is this an upgrade proof? Even a small patch might impact this.
I had a similar requirement as yours and I did it by extending the CO and wrote the logic there. So its very simple and upgrade proof. Just for the fact that oracle suggested approach is to leave handling of VO/EO to AM, do we have to take the pain of writing the server class, extending the mapper class, changing the AM?
Please understand that I am just trying to asses the risk of extending the CO directly without following oracle's suggested approach. I hope you have an answer for my question.
Finally, its been a good effort by you. I appreciate this.
written by Rajesh Gupta , January 10, 2011
I modified the PricingHelper class to modify the getDisplayTxnPrice method to add Attribute11, it is working fine but when we check the Requisition in My Requisition Region of IProc Home Page I am getting error for Non-Catalogue Requisitions only:
Request URI:/OA_HTML/OA.jsp
Exception:
java.lang.NoSuchMethodError: oracle.apps.icx.por.schema.server.PricingHelper.getDisplayTxnPrice(Loracle/apps/fnd/framework/server/OADBTransaction;Loracle/jbo/domain/Number;Loracle/jbo/domain/Number
Loracle/jbo/domain/Number Please Help.
Thanks,
Rajesh
written by mb_denver_us , October 20, 2011
If this date is different across the requisition lines; how would I go about copying this to the expenditure item date after i hit the submit/edit lines/save buttons on check out. I have tried something like this but this does not seem to work.
Thanks
MB






The article is awesome! Thanks for your efforts again.
Thanks,
Krishna